aoflagger-v3.4.0/0000755000175000017500000000000014516225226012326 5ustar olesolesaoflagger-v3.4.0/quality/0000755000175000017500000000000014516225226014016 5ustar olesolesaoflagger-v3.4.0/quality/loghistogram.h0000644000175000017500000003546614507760372016712 0ustar olesoles#ifndef LOGHISTOGRAM_H #define LOGHISTOGRAM_H #include #include #include #include #include "histogramtablesformatter.h" #include "../util/serializable.h" #ifndef HAVE_EXP10 #define exp10(x) exp((2.3025850929940456840179914546844) * (x)) #endif class LogHistogram : public Serializable { private: class AmplitudeBin : public Serializable { public: AmplitudeBin() : count(0) {} long unsigned count; long unsigned GetCount() const { return count; } AmplitudeBin& operator+=(const AmplitudeBin& other) { count += other.count; return *this; } AmplitudeBin& operator-=(const AmplitudeBin& other) { if (count >= other.count) count -= other.count; else count = 0; return *this; } virtual void Serialize(std::ostream& stream) const final override { SerializeToUInt64(stream, count); } virtual void Unserialize(std::istream& stream) final override { count = UnserializeUInt64(stream); } }; public: LogHistogram() {} LogHistogram(const LogHistogram& source) : _amplitudes(source._amplitudes) {} void Add(const double amplitude) { if (std::isfinite(amplitude)) { const double centralAmp = getCentralAmplitude(amplitude); AmplitudeBin& bin = getBin(centralAmp); ++bin.count; } } void Add(const LogHistogram& histogram) { for (std::map::const_iterator i = histogram._amplitudes.begin(); i != histogram._amplitudes.end(); ++i) { AmplitudeBin& bin = getBin(i->first); bin += i->second; } } void operator-=(const LogHistogram& histogram) { for (std::map::const_iterator i = histogram._amplitudes.begin(); i != histogram._amplitudes.end(); ++i) { AmplitudeBin& bin = getBin(i->first); bin -= i->second; } } double MaxAmplitude() const { if (_amplitudes.empty()) return 0.0; return _amplitudes.rbegin()->first; } double MinPositiveAmplitude() const { std::map::const_iterator i = _amplitudes.begin(); if (i == _amplitudes.end()) return 0.0; while (i->first <= 0.0) { ++i; if (i == _amplitudes.end()) return 0.0; } return i->first; } double NormalizedCount(double startAmplitude, double endAmplitude) const { unsigned long count = 0; for (std::map::const_iterator i = _amplitudes.begin(); i != _amplitudes.end(); ++i) { if (i->first >= startAmplitude && i->first < endAmplitude) count += i->second.GetCount(); } return (double)count / (endAmplitude - startAmplitude); } double NormalizedCount(double centreAmplitude) const { const double key = getCentralAmplitude(centreAmplitude); std::map::const_iterator i = _amplitudes.find(key); if (i == _amplitudes.end()) return 0.0; return (double)i->second.GetCount() / (binEnd(centreAmplitude) - binStart(centreAmplitude)); } double MinNormalizedCount() const { const_iterator i = begin(); if (i == end()) return 0.0; double minCount = i.normalizedCount(); do { const double c = i.normalizedCount(); if (c < minCount) minCount = c; ++i; } while (i != end()); return minCount; } double MaxNormalizedCount() const { double maxCount = 0.0; for (LogHistogram::const_iterator i = begin(); i != end(); ++i) { if (i.normalizedCount() > maxCount && i.value() > 0 && std::isfinite(i.value())) maxCount = i.normalizedCount(); } return maxCount; } double NormalizedTotalCount() const { unsigned long count = 0; for (LogHistogram::const_iterator i = begin(); i != end(); ++i) count += i.unnormalizedCount(); return count; } double NormalizedCountAbove(double lowerLimitingAmplitude) const { unsigned long count = 0; LogHistogram::const_iterator i = begin(); while (i != end() && i.value() <= lowerLimitingAmplitude) { ++i; } while (i != end()) { count += i.unnormalizedCount(); ++i; } return count; } double AmplitudeWithMaxNormalizedCount() const { double maxCount = 0.0, maxPosition = 0.0; for (LogHistogram::const_iterator i = begin(); i != end(); ++i) { if (i.normalizedCount() > maxCount && i.value() > 0 && std::isfinite(i.value())) { maxCount = i.normalizedCount(); maxPosition = i.value(); } } return maxPosition; } double MinPosNormalizedCount() const { const_iterator i = begin(); if (i == end()) return 0.0; double minCount = std::isfinite(i.normalizedCount()) ? i.normalizedCount() + 1.0 : 1.0; do { const double c = i.normalizedCount(); if (c < minCount && c > 0.0 && std::isfinite(c)) minCount = c; ++i; } while (i != end()); return minCount; } double NormalizedSlope(double startAmplitude, double endAmplitude) const { unsigned long n = 0; long double sumX = 0.0, sumXY = 0.0, sumY = 0.0, sumXSquare = 0.0; for (const_iterator i = begin(); i != end(); ++i) { if (i.value() >= startAmplitude && i.value() < endAmplitude) { double x = log10(i.value()); double y = log10(i.normalizedCount()); ++n; sumX += x; sumXSquare += x * x; sumY += y; sumXY += x * y; } } return (sumXY - sumX * sumY / n) / (sumXSquare - (sumX * sumX / n)); } double PowerLawExponent(double startAmplitude) const { const long double xMin = startAmplitude; long double termSum = 0.0; long double termCount = 0.0; for (const_iterator i = begin(); i != end(); ++i) { const long double x = i.value(); if (x >= startAmplitude) { const long double count = i.unnormalizedCount(); const long double thisTerm = logl(x / xMin); termCount += count; termSum += thisTerm * count; } } return (double)(-1.0L - termCount / termSum); } double PowerLawExponentStdError(double startAmplitude, double expEstimator) const { long double termCount = 0.0; for (const_iterator i = begin(); i != end(); ++i) { if (i.value() >= startAmplitude) { const long double count = i.unnormalizedCount(); termCount += count; } } return (double)((-expEstimator - 1.0L) / sqrtl(termCount)); } double NormalizedSlopeOffset(double startAmplitude, double endAmplitude, double slope) const { unsigned long n = 0; long double sumOffset = 0.0; for (const_iterator i = begin(); i != end(); ++i) { if (i.value() >= startAmplitude && i.value() < endAmplitude) { double y = log10(i.normalizedCount()); double x = log10(i.value()); double ySlope = x * slope; ++n; sumOffset += (y - ySlope); } } return (double)(sumOffset / (long double)n); } double NormalizedSlopeStdError(double startAmplitude, double endAmplitude, double slope) const { long double ssxx = 0.0, ssxy = 0.0, ssyy = 0.0, xSum = 0.0, ySum = 0.0; unsigned long n = 0; // determine the 'average' x and y for (const_iterator i = begin(); i != end(); ++i) { if (i.value() >= startAmplitude && i.value() < endAmplitude) { xSum += log10(i.value()); ySum += log10(i.normalizedCount()); ++n; } } const long double avgX = xSum / (long double)n, avgY = ySum / (long double)n; for (const_iterator i = begin(); i != end(); ++i) { if (i.value() >= startAmplitude && i.value() < endAmplitude) { long double y = log10(i.normalizedCount()); long double x = log10(i.value()); ssxx += (x - avgX) * (x - avgX); ssxy += (x - avgX) * (y - avgY); ssyy += (y - avgY) * (y - avgY); } } return (double)sqrtl((ssyy - slope * ssxy) / (ssxx * (long double)(n - 2))); } double NormalizedSlopeStdDevBySampling(double startAmplitude, double endAmplitude, double slope, double stepFactor) const { long double sum = 0.0; unsigned long n = 0; if (stepFactor <= 1.0001) stepFactor = 1.0001; while (startAmplitude < endAmplitude) { const double stepEnd = startAmplitude * stepFactor; double sampledSlope = NormalizedSlope(startAmplitude, stepEnd); double sampleError = sampledSlope - slope; sum += sampleError * sampleError; ++n; startAmplitude = stepEnd; } return (double)sqrtl(sum / ((long double)n * n - n)); } double PowerLawUpperLimit(double constrainingAmplitude, double exponent, double factor) const { const double count = NormalizedCountAbove(constrainingAmplitude); const double term = count * (exponent + 1.0) / factor + pow(constrainingAmplitude, exponent + 1.0); return pow(term, 1.0 / (exponent + 1.0)); } double PowerLawLowerLimit(double constrainingAmplitude, double exponent, double factor, double rfiRatio) const { const double countPart = NormalizedCountAbove(constrainingAmplitude); const double countTotal = NormalizedTotalCount() * rfiRatio; const double term = (countPart - countTotal) * (exponent + 1.0) / factor + pow(constrainingAmplitude, exponent + 1.0); return pow(term, 1.0 / (exponent + 1.0)); } double PowerLawLowerLimit2(double constrainingAmplitude, double exponent, double factor, double rfiRatio) const { const double countPart = NormalizedCountAbove(constrainingAmplitude); const double countTotal = NormalizedTotalCount() * rfiRatio; const double term = (countPart - countTotal) * (exponent + 1.0) / factor + pow(constrainingAmplitude, exponent + 1.0); return pow(term / -exponent, 1.0 / (exponent + 1.0)); } void GetRFIRegion(double& start, double& end) const { double sigmaEstimate = AmplitudeWithMaxNormalizedCount(); double maxAmplitude = MaxAmplitude(); start = sigmaEstimate * 20.0; double halfWay = exp((log(start) + log(maxAmplitude)) * 0.5); end = halfWay; } double NormalizedSlopeInRFIRegion() const { double start, end; GetRFIRegion(start, end); return NormalizedSlope(start, end); } void SetData( std::vector& histogramData) { for (std::vector::const_iterator i = histogramData.begin(); i != histogramData.end(); ++i) { const double b = (i->binStart + i->binEnd) * 0.5; // TODO somewhat inefficient... getBin(getCentralAmplitude(b)).count = (unsigned long)i->count; } } void Rescale(double factor) { std::map newAmplitudes; std::map::iterator position = newAmplitudes.begin(); for (std::map::const_iterator i = _amplitudes.begin(); i != _amplitudes.end(); ++i) { position = newAmplitudes.insert( position, std::pair( getCentralAmplitude(i->first * factor), i->second)); } _amplitudes = newAmplitudes; } class const_iterator { public: const_iterator(const LogHistogram& histogram, std::map::const_iterator iter) : _iterator(iter) {} const_iterator(const const_iterator& source) : _iterator(source._iterator) {} const_iterator& operator=(const const_iterator& source) { _iterator = source._iterator; return *this; } bool operator==(const const_iterator& other) const { return other._iterator == _iterator; } bool operator!=(const const_iterator& other) const { return other._iterator != _iterator; } const_iterator& operator++() { ++_iterator; return *this; } const_iterator& operator--() { --_iterator; return *this; } double value() const { return _iterator->first; } double normalizedCount() const { return _iterator->second.GetCount() / (binEnd() - binStart()); } long unsigned unnormalizedCount() const { return _iterator->second.GetCount(); } double binStart() const { return _iterator->first > 0.0 ? exp10(log10(_iterator->first) - 0.005) : -exp10(log10(-_iterator->first) - 0.005); } double binEnd() const { return _iterator->first > 0.0 ? exp10(log10(_iterator->first) + 0.005) : -exp10(log10(-_iterator->first) + 0.005); } private: std::map::const_iterator _iterator; }; typedef const_iterator iterator; const_iterator begin() const { return const_iterator(*this, _amplitudes.begin()); } const_iterator end() const { return const_iterator(*this, _amplitudes.end()); } virtual void Serialize(std::ostream& stream) const final override { SerializeToUInt64(stream, _amplitudes.size()); for (std::map::const_iterator i = _amplitudes.begin(); i != _amplitudes.end(); ++i) { SerializeToDouble(stream, i->first); i->second.Serialize(stream); } } virtual void Unserialize(std::istream& stream) final override { _amplitudes.clear(); size_t mapSize = UnserializeUInt64(stream); std::map::iterator insertPos = _amplitudes.begin(); for (size_t i = 0; i != mapSize; ++i) { std::pair p; p.first = UnserializeDouble(stream); p.second.Unserialize(stream); insertPos = _amplitudes.insert(insertPos, p); } } void CreateMissingBins() { double first = MinPositiveAmplitude(), last = MaxAmplitude(); for (double i = first; i < last; i *= 1.01) { getBin(getCentralAmplitude(i)); } } private: std::map _amplitudes; AmplitudeBin& getBin(double centralAmplitude) { std::map::iterator element = _amplitudes.find(centralAmplitude); if (element == _amplitudes.end()) { element = _amplitudes .insert(std::pair(centralAmplitude, AmplitudeBin())) .first; } return element->second; } double binStart(double x) const { return x > 0.0 ? exp10(log10(x) - 0.005) : -exp10(log10(x) - 0.005); } double binEnd(double x) const { return x > 0.0 ? exp10(log10(x) + 0.005) : -exp10(log10(x) + 0.005); } static double getCentralAmplitude(const double amplitude) { if (amplitude >= 0.0) return exp10(round(100.0 * log10(amplitude)) / 100.0); else return -exp10(round(100.0 * log10(-amplitude)) / 100.0); } }; #endif aoflagger-v3.4.0/quality/statisticalvalue.h0000644000175000017500000000312214507760372017554 0ustar olesoles#ifndef MSIO_STATISTICAL_VALUE_H #define MSIO_STATISTICAL_VALUE_H #include class StatisticalValue { public: explicit StatisticalValue(unsigned _polarizationCount) : _polarizationCount(_polarizationCount), _kindIndex(0), _values(new std::complex[_polarizationCount]) {} StatisticalValue(const StatisticalValue& source) : _polarizationCount(source._polarizationCount), _kindIndex(source._kindIndex), _values(new std::complex[source._polarizationCount]) { for (unsigned i = 0; i < _polarizationCount; ++i) _values[i] = source._values[i]; } ~StatisticalValue() { delete[] _values; } StatisticalValue& operator=(const StatisticalValue& source) { if (_polarizationCount != source._polarizationCount) { _polarizationCount = source._polarizationCount; delete[] _values; _values = new std::complex[_polarizationCount]; } _kindIndex = source._kindIndex; for (unsigned i = 0; i < _polarizationCount; ++i) _values[i] = source._values[i]; return *this; } unsigned PolarizationCount() const { return _polarizationCount; } unsigned KindIndex() const { return _kindIndex; } void SetKindIndex(unsigned kindIndex) { _kindIndex = kindIndex; } std::complex Value(unsigned polarizationIndex) const { return _values[polarizationIndex]; } void SetValue(unsigned polarizationIndex, std::complex newValue) { _values[polarizationIndex] = newValue; } private: unsigned _polarizationCount; unsigned _kindIndex; std::complex* _values; }; #endif aoflagger-v3.4.0/quality/histogramtablesformatter.cpp0000644000175000017500000002323414507760372021650 0ustar olesoles#include "histogramtablesformatter.h" #include #include #include #include #include #include #include #include "statisticalvalue.h" const std::string HistogramTablesFormatter::ColumnNameType = "TYPE"; const std::string HistogramTablesFormatter::ColumnNameName = "NAME"; const std::string HistogramTablesFormatter::ColumnNameCount = "COUNT"; const std::string HistogramTablesFormatter::ColumnNamePolarization = "POLARIZATION"; const std::string HistogramTablesFormatter::ColumnNameBinStart = "BIN_START"; const std::string HistogramTablesFormatter::ColumnNameBinEnd = "BIN_END"; void HistogramTablesFormatter::InitializeEmptyTables() { if (TableExists(HistogramCountTable)) removeEntries(HistogramCountTable); else createCountTable(); if (TableExists(HistogramTypeTable)) removeEntries(HistogramTypeTable); else createTypeTable(); } void HistogramTablesFormatter::RemoveTable(enum TableKind table) { if (TableExists(table)) { Close(); openMainTable(true); if (_measurementSet->keywordSet().isDefined(TableName(table))) _measurementSet->rwKeywordSet().removeField(TableName(table)); if (_measurementSet->isReadable(TableFilename(table))) casacore::Table::deleteTable(TableFilename(table)); } } unsigned HistogramTablesFormatter::QueryTypeIndex(enum HistogramType type, unsigned polarizationIndex) { unsigned kindIndex; if (!QueryTypeIndex(type, polarizationIndex, kindIndex)) throw std::runtime_error( "getKindIndex(): Requested statistic kind not available."); return kindIndex; } bool HistogramTablesFormatter::QueryTypeIndex(enum HistogramType type, unsigned polarizationIndex, unsigned& destTypeIndex) { openTypeTable(false); const casacore::ROScalarColumn typeColumn(*_typeTable, ColumnNameType); const casacore::ROScalarColumn polarizationColumn( *_typeTable, ColumnNamePolarization); const casacore::ROScalarColumn nameColumn(*_typeTable, ColumnNameName); const casacore::String nameToFind(TypeToName(type)); const unsigned nrRow = _typeTable->nrow(); for (unsigned i = 0; i < nrRow; ++i) { if ((unsigned)polarizationColumn(i) == polarizationIndex && nameColumn(i) == nameToFind) { destTypeIndex = typeColumn(i); return true; } } return false; } bool HistogramTablesFormatter::hasOneEntry(unsigned typeIndex) { const casacore::Table& casaTable = getTable(HistogramCountTable, false); const casacore::ROScalarColumn typeColumn(casaTable, ColumnNameType); const unsigned nrRow = casaTable.nrow(); for (unsigned i = 0; i < nrRow; ++i) { if (typeColumn(i) == (int)typeIndex) return true; } return false; } void HistogramTablesFormatter::createTypeTable() { casacore::TableDesc tableDesc(TypeTableName() + "_TYPE", "1.0", casacore::TableDesc::Scratch); tableDesc.comment() = "Couples the TYPE column in the QUALITY_HISTOGRAM_COUNT table to the " "name and polarization of the histogram"; tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameType, "Index of the statistic kind")); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNamePolarization, "Index of the polarization corresponding to the main table")); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameName, "Name of the statistic")); casacore::SetupNewTable newTableSetup(TableFilename(HistogramTypeTable), tableDesc, casacore::Table::New); const casacore::Table newTable(newTableSetup); openMainTable(true); _measurementSet->rwKeywordSet().defineTable(TypeTableName(), newTable); } void HistogramTablesFormatter::createCountTable() { casacore::TableDesc tableDesc(CountTableName() + "_TYPE", "1.0", casacore::TableDesc::Scratch); tableDesc.comment() = "Histograms of the data in the main table"; tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameType, "Index of the statistic kind")); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameBinStart, "Lower start value of the bin corresponding to the count")); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameBinEnd, "Higher end value of the bin corresponding to the count")); tableDesc.addColumn( casacore::ScalarColumnDesc(ColumnNameCount, "Histogram y-value")); casacore::SetupNewTable newTableSetup(TableFilename(HistogramCountTable), tableDesc, casacore::Table::New); const casacore::Table newTable(newTableSetup); openMainTable(true); _measurementSet->rwKeywordSet().defineTable(CountTableName(), newTable); } unsigned HistogramTablesFormatter::StoreType(enum HistogramType type, unsigned polarizationIndex) { openTypeTable(true); const unsigned typeIndex = findFreeTypeIndex(*_typeTable); const unsigned newRow = _typeTable->nrow(); _typeTable->addRow(); casacore::ScalarColumn typeColumn(*_typeTable, ColumnNameType); casacore::ScalarColumn polarizationColumn(*_typeTable, ColumnNamePolarization); casacore::ScalarColumn nameColumn(*_typeTable, ColumnNameName); typeColumn.put(newRow, typeIndex); polarizationColumn.put(newRow, polarizationIndex); nameColumn.put(newRow, TypeToName(type)); return typeIndex; } unsigned HistogramTablesFormatter::findFreeTypeIndex( casacore::Table& typeTable) { int maxIndex = 0; const casacore::ROScalarColumn typeColumn(typeTable, ColumnNameType); const unsigned nrRow = typeTable.nrow(); for (unsigned i = 0; i < nrRow; ++i) { if (typeColumn(i) > maxIndex) maxIndex = typeColumn(i); } return maxIndex + 1; } void HistogramTablesFormatter::openTable( enum TableKind table, bool needWrite, std::unique_ptr& tablePtr) { if (!tablePtr) { openMainTable(false); tablePtr = std::make_unique( _measurementSet->keywordSet().asTable(TableName(table))); if (needWrite) tablePtr->reopenRW(); } else { if (needWrite && !tablePtr->isWritable()) tablePtr->reopenRW(); } } void HistogramTablesFormatter::StoreValue(unsigned typeIndex, double binStart, double binEnd, double count) { openCountTable(true); const unsigned newRow = _countTable->nrow(); _countTable->addRow(); casacore::ScalarColumn typeColumn(*_countTable, ColumnNameType); casacore::ScalarColumn binStartColumn(*_countTable, ColumnNameBinStart); casacore::ScalarColumn binEndColumn(*_countTable, ColumnNameBinEnd); casacore::ScalarColumn countColumn(*_countTable, ColumnNameCount); typeColumn.put(newRow, typeIndex); binStartColumn.put(newRow, binStart); binEndColumn.put(newRow, binEnd); countColumn.put(newRow, count); } void HistogramTablesFormatter::removeTypeEntry(enum HistogramType type, unsigned polarizationIndex) { openTypeTable(true); const casacore::ScalarColumn polarizationColumn(*_typeTable, ColumnNamePolarization); const casacore::ScalarColumn nameColumn(*_typeTable, ColumnNameName); const unsigned nrRow = _typeTable->nrow(); const casacore::String typeName(TypeToName(type)); for (unsigned i = 0; i < nrRow; ++i) { if (nameColumn(i) == typeName && (unsigned)polarizationColumn(i) == polarizationIndex) { _typeTable->removeRow(i); break; } } } void HistogramTablesFormatter::removeEntries(enum TableKind table) { casacore::Table& casaTable = getTable(table, true); const unsigned nrRow = casaTable.nrow(); for (int i = nrRow - 1; i >= 0; --i) { casaTable.removeRow(i); } } void HistogramTablesFormatter::QueryHistogram( unsigned typeIndex, std::vector& histogram) { const casacore::Table& table(getTable(HistogramCountTable, false)); const unsigned nrRow = table.nrow(); const casacore::ROScalarColumn typeColumn(table, ColumnNameType); const casacore::ROScalarColumn binStartColumn(table, ColumnNameBinStart); const casacore::ROScalarColumn binEndColumn(table, ColumnNameBinEnd); const casacore::ROScalarColumn countColumn(table, ColumnNameCount); for (unsigned i = 0; i < nrRow; ++i) { if (typeColumn(i) == (int)typeIndex) { HistogramItem item; item.binStart = binStartColumn(i); item.binEnd = binEndColumn(i); item.count = countColumn(i); histogram.push_back(item); } } } void HistogramTablesFormatter::openMainTable(bool needWrite) { if (_measurementSet == nullptr) { if (needWrite) _measurementSet = std::make_unique( _measurementSetName, casacore::Table::Update); else _measurementSet = std::make_unique(_measurementSetName); } else if (needWrite) { if (!_measurementSet->isWritable()) _measurementSet->reopenRW(); } } aoflagger-v3.4.0/quality/statisticsderivator.h0000644000175000017500000003334214507760372020314 0ustar olesoles#ifndef QUALITY__STATISTICS_DERIVATOR_H #define QUALITY__STATISTICS_DERIVATOR_H #include "statisticscollection.h" #include #include #include "../structures/antennainfo.h" #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" struct stat; class StatisticsDerivator { public: explicit StatisticsDerivator(const StatisticsCollection& collection) : _collection(collection) {} std::complex GetComplexBaselineStatistic( QualityTablesFormatter::StatisticKind kind, unsigned antenna1, unsigned antenna2, unsigned polarization) const { const DefaultStatistics& statistics = _collection.BaselineStatistics().GetStatistics(antenna1, antenna2); return deriveComplex(kind, statistics, polarization); } std::complex GetComplexTimeStatistic( QualityTablesFormatter::StatisticKind kind, double time, unsigned polarization) const { const DefaultStatistics& statistics = _collection.TimeStatistics().find(time)->second; return deriveComplex(kind, statistics, polarization); } std::complex GetComplexFrequencyStatistic( QualityTablesFormatter::StatisticKind kind, double frequency, unsigned polarization) const { const DefaultStatistics& statistics = _collection.FrequencyStatistics().find(frequency)->second; return deriveComplex(kind, statistics, polarization); } static std::complex GetComplexStatistic( QualityTablesFormatter::StatisticKind kind, const DefaultStatistics& statistics, unsigned polarization) { return deriveComplex(kind, statistics, polarization); } static long double GetStatisticAmplitude( QualityTablesFormatter::StatisticKind kind, const DefaultStatistics& statistics, unsigned polarization) { const std::complex val = GetComplexStatistic(kind, statistics, polarization); return sqrtl(val.real() * val.real() + val.imag() * val.imag()); } static std::complex Variance(unsigned long n, std::complex sum, std::complex sumP2) { return deriveVariance(n, sum, sumP2); } static long double VarianceAmplitude(unsigned long n, std::complex sum, std::complex sumP2) { const std::complex variance = deriveVariance(n, sum, sumP2); return sqrtl(variance.real() * variance.real() + variance.imag() * variance.imag()); } static long double StandardDeviationAmplitude( unsigned long n, std::complex sum, std::complex sumP2) { const std::complex stdDev = deriveStandardDeviation(n, sum, sumP2); return sqrtl(stdDev.real() * stdDev.real() + stdDev.imag() * stdDev.imag()); } std::pair CreateTFData( QualityTablesFormatter::StatisticKind kind) { const std::map>& map = _collection.AllTimeStatistics(); std::set frequencies; std::set timesteps; // List the frequencies and timesteps for (std::map>::const_iterator i = map.begin(); i != map.end(); ++i) { const double frequency = i->first; frequencies.insert(frequency); const std::map& innerMap = i->second; for (std::map::const_iterator j = innerMap.begin(); j != innerMap.end(); ++j) { const double time = j->first; timesteps.insert(time); } } std::map freqIndices; std::map timeIndices; std::vector observationTimes; BandInfo band; size_t index = 0; for (std::set::const_iterator i = frequencies.begin(); i != frequencies.end(); ++i) { freqIndices.insert(std::pair(*i, index)); ChannelInfo channel; channel.frequencyIndex = index; channel.frequencyHz = *i; band.channels.push_back(channel); ++index; } index = 0; for (std::set::const_iterator i = timesteps.begin(); i != timesteps.end(); ++i) { timeIndices.insert(std::pair(*i, index)); observationTimes.push_back(*i); ++index; } // create the images const size_t pCount = _collection.PolarizationCount(); std::vector realImage(pCount), imagImage(pCount); Mask2DPtr mask = Mask2D::CreateSetMaskPtr(timesteps.size(), frequencies.size()); for (size_t p = 0; p < pCount; ++p) { realImage[p] = Image2D::CreateZeroImagePtr(timesteps.size(), frequencies.size()); imagImage[p] = Image2D::CreateZeroImagePtr(timesteps.size(), frequencies.size()); } // add the statistis for (std::map>::const_iterator i = map.begin(); i != map.end(); ++i) { const double frequency = i->first; const size_t freqIndex = freqIndices.find(frequency)->second; const std::map& innerMap = i->second; for (std::map::const_iterator j = innerMap.begin(); j != innerMap.end(); ++j) { const double time = j->first; const size_t timeIndex = timeIndices.find(time)->second; mask->SetValue(timeIndex, freqIndex, false); for (size_t p = 0; p < pCount; ++p) { const std::complex statValue = deriveComplex(kind, j->second, p); realImage[p]->SetValue(timeIndex, freqIndex, statValue.real()); imagImage[p]->SetValue(timeIndex, freqIndex, statValue.imag()); } } } TimeFrequencyData data = TimeFrequencyData::FromLinear( pCount, (Image2DCPtr*)&(realImage[0]), (Image2DCPtr*)&(imagImage[0])); data.SetGlobalMask(mask); TimeFrequencyMetaDataPtr metaData(new TimeFrequencyMetaData()); metaData->SetObservationTimes(observationTimes); metaData->SetBand(band); metaData->SetValueDescription(GetDescription(kind)); metaData->SetValueUnits(GetUnits(kind)); return std::pair(data, metaData); } static std::string GetDescription( QualityTablesFormatter::StatisticKind kind) { switch (kind) { case QualityTablesFormatter::MeanStatistic: return "Mean"; case QualityTablesFormatter::VarianceStatistic: return "Variance"; case QualityTablesFormatter::StandardDeviationStatistic: return "Standard deviation"; case QualityTablesFormatter::CountStatistic: return "Sample count"; case QualityTablesFormatter::DMeanStatistic: return "Differential mean"; case QualityTablesFormatter::DVarianceStatistic: return "Differential variance"; case QualityTablesFormatter::DStandardDeviationStatistic: return "Differential standard deviation"; case QualityTablesFormatter::DCountStatistic: return "Sample count in differential statistics"; case QualityTablesFormatter::RFICountStatistic: return "Sample count affected by RFI"; case QualityTablesFormatter::RFIRatioStatistic: return "RFI"; case QualityTablesFormatter::RFIPercentageStatistic: return "RFI"; case QualityTablesFormatter::SignalToNoiseStatistic: return "SNR"; default: return "Value"; } } static bool HasUnits(QualityTablesFormatter::StatisticKind kind) { return !GetUnits(kind).empty(); } static std::string GetUnits(QualityTablesFormatter::StatisticKind kind) { switch (kind) { case QualityTablesFormatter::MeanStatistic: case QualityTablesFormatter::StandardDeviationStatistic: case QualityTablesFormatter::DMeanStatistic: case QualityTablesFormatter::DVarianceStatistic: case QualityTablesFormatter::DStandardDeviationStatistic: return "Jy"; case QualityTablesFormatter::VarianceStatistic: return "Jy^2"; case QualityTablesFormatter::RFIPercentageStatistic: return "%"; case QualityTablesFormatter::CountStatistic: case QualityTablesFormatter::DCountStatistic: case QualityTablesFormatter::RFICountStatistic: return "count"; case QualityTablesFormatter::RFIRatioStatistic: return "ratio"; case QualityTablesFormatter::SignalToNoiseStatistic: default: return ""; } } static std::string GetDescWithUnits( QualityTablesFormatter::StatisticKind kind) { std::ostringstream str; str << GetDescription(kind); if (HasUnits(kind)) str << " (" << GetUnits(kind) << ")"; return str.str(); } private: template static std::complex deriveComplex( QualityTablesFormatter::StatisticKind kind, const DefaultStatistics& statistics, unsigned polarization) { switch (kind) { case QualityTablesFormatter::CountStatistic: return std::complex(statistics.count[polarization], 0.0); break; case QualityTablesFormatter::MeanStatistic: return statistics.Mean(polarization); break; case QualityTablesFormatter::SumStatistic: return statistics.Sum(polarization); break; case QualityTablesFormatter::SumP2Statistic: return statistics.SumP2(polarization); break; case QualityTablesFormatter::VarianceStatistic: return deriveVariance(statistics.count[polarization], statistics.sum[polarization], statistics.sumP2[polarization]); break; case QualityTablesFormatter::StandardDeviationStatistic: return deriveStandardDeviation(statistics.count[polarization], statistics.sum[polarization], statistics.sumP2[polarization]); break; case QualityTablesFormatter::DCountStatistic: return std::complex(statistics.dCount[polarization], 0.0f); break; case QualityTablesFormatter::DMeanStatistic: return statistics.DMean(polarization); break; case QualityTablesFormatter::DSumStatistic: return statistics.DSum(polarization); break; case QualityTablesFormatter::DSumP2Statistic: return statistics.DSumP2(polarization); break; case QualityTablesFormatter::DVarianceStatistic: return deriveVariance(statistics.dCount[polarization], statistics.dSum[polarization], statistics.dSumP2[polarization]); break; case QualityTablesFormatter::DStandardDeviationStatistic: return deriveStandardDeviation(statistics.dCount[polarization], statistics.dSum[polarization], statistics.dSumP2[polarization]); break; case QualityTablesFormatter::RFIRatioStatistic: return std::complex((double)statistics.rfiCount[polarization] / (statistics.count[polarization] + statistics.rfiCount[polarization]), 0.0f); break; case QualityTablesFormatter::RFIPercentageStatistic: return std::complex(100.0 * (double)statistics.rfiCount[polarization] / (statistics.count[polarization] + statistics.rfiCount[polarization]), 0.0f); break; case QualityTablesFormatter::RFICountStatistic: return std::complex(statistics.rfiCount[polarization], 0.0f); break; case QualityTablesFormatter::SignalToNoiseStatistic: { const std::complex stddev = deriveComplex( QualityTablesFormatter::DStandardDeviationStatistic, statistics, polarization); return std::complex( fabsl(statistics.Mean(polarization).real() / stddev.real()), fabsl(statistics.Mean(polarization).imag() / stddev.imag())); } default: throw std::runtime_error("Can not derive requested statistic"); } } template static std::complex deriveVariance(unsigned long n, std::complex sum, std::complex sumP2) { return std::complex(deriveVarianceSingle(n, sum.real(), sumP2.real()), deriveVarianceSingle(n, sum.imag(), sumP2.imag())); } template static std::complex deriveStandardDeviation( unsigned long n, std::complex sum, std::complex sumP2) { return std::complex( deriveStandardDeviationSingle(n, sum.real(), sumP2.real()), deriveStandardDeviationSingle(n, sum.imag(), sumP2.imag())); } template static T deriveVarianceSingle(unsigned long n, T sum, T sumP2) { T sumMeanSquared = sum * sum / n; return (sumP2 - sumMeanSquared) / (n - 1.0); } template static T deriveStandardDeviationSingle(unsigned long n, T sum, T sumP2) { T sumMeanSquared = sum * sum / n; return sqrt((sumP2 - sumMeanSquared) / n); } const StatisticsCollection& _collection; }; #endif aoflagger-v3.4.0/quality/combine.cpp0000644000175000017500000000273014507760372016146 0ustar olesoles#include "combine.h" #include "../structures/msmetadata.h" namespace quality { FileContents ReadAndCombine(const std::vector& files, bool verbose) { FileContents result; size_t n_polarizations = 0; for (size_t i = 0; i != files.size(); ++i) { const std::string& filename = files[i]; if (n_polarizations == 0) { n_polarizations = MSMetaData::PolarizationCount(filename); result.statistics_collection.SetPolarizationCount(n_polarizations); result.histogram_collection.SetPolarizationCount(n_polarizations); } else { if (n_polarizations != MSMetaData::PolarizationCount(filename)) { throw std::runtime_error( "Can't combine measurement set quality statistics with different " "number of polarizations"); } } if (verbose) std::cout << " (" << (i + 1) << "/" << files.size() << ") Adding " << filename << " to statistics...\n"; QualityTablesFormatter qualityTables(filename); StatisticsCollection statCollection(n_polarizations); statCollection.Load(qualityTables); result.statistics_collection.Add(statCollection); HistogramTablesFormatter histogramTables(filename); if (histogramTables.HistogramsExist()) { HistogramCollection histCollection(n_polarizations); histCollection.Load(histogramTables); result.histogram_collection.Add(histCollection); } } return result; } } // namespace quality aoflagger-v3.4.0/quality/collector.cpp0000644000175000017500000002041314507760372016516 0ustar olesoles#include "collector.h" #include "../structures/msmetadata.h" #include "../util/progress/progresslistener.h" #include "histogramcollection.h" #include "statisticscollection.h" #include #include #include #include Collector::Collector() : _mode(CollectDefault), _dataColumnName("DATA"), _intervalStart(0), _intervalEnd(0), _flaggedTimesteps(0) {} Collector::~Collector() = default; void Collector::Collect(const std::string& filename, StatisticsCollection& statisticsCollection, HistogramCollection& histogramCollection, ProgressListener& progressListener) { progressListener.OnStartTask("Collecting statistics"); std::unique_ptr ms(new MSMetaData(filename)); const size_t polarizationCount = ms->PolarizationCount(), bandCount = ms->BandCount(); const bool ignoreChannelZero = ms->IsChannelZeroRubish() && _mode != CollectTimeFrequency; const std::string stationName = ms->GetStationName(); std::vector bands(bandCount); std::vector> frequencies(bandCount); for (unsigned b = 0; b < bandCount; ++b) { bands[b] = ms->GetBandInfo(b); frequencies[b].resize(bands[b].channels.size()); for (unsigned c = 0; c < bands[b].channels.size(); ++c) { frequencies[b][c] = bands[b].channels[c].frequencyHz; } } ms.reset(); // Initialize statisticscollection _statisticsCollection = &statisticsCollection; _histogramCollection = &histogramCollection; statisticsCollection.SetPolarizationCount(polarizationCount); const size_t nCPU = aocommon::system::ProcessorCount(); _threadStats.clear(); for (size_t i = 0; i != nCPU; ++i) _threadStats.emplace_back(polarizationCount); if (_mode != CollectHistograms) { for (unsigned b = 0; b < bandCount; ++b) { if (ignoreChannelZero) statisticsCollection.InitializeBand(b, (frequencies[b].data() + 1), bands[b].channels.size() - 1); else statisticsCollection.InitializeBand(b, frequencies[b].data(), bands[b].channels.size()); for (size_t i = 0; i != nCPU; ++i) { if (ignoreChannelZero) _threadStats[i].InitializeBand(b, (frequencies[b].data() + 1), bands[b].channels.size() - 1); else _threadStats[i].InitializeBand(b, frequencies[b].data(), bands[b].channels.size()); } } } // Initialize Histograms collection histogramCollection.SetPolarizationCount(polarizationCount); // get columns const casacore::Table table(filename); const casacore::ArrayColumn dataColumn(table, _dataColumnName); const casacore::ArrayColumn flagColumn(table, "FLAG"); const casacore::ScalarColumn timeColumn(table, "TIME"); casacore::ScalarColumn antenna1Column(table, "ANTENNA1"), antenna2Column(table, "ANTENNA2"), windowColumn(table, "DATA_DESC_ID"); const size_t channelCount = bands[0].channels.size(); _correlatorFlags.assign(channelCount, false); _correlatorFlagsForBadAntenna.assign(channelCount, true); aocommon::Lane workLane(nCPU * 4); std::vector threads; for (size_t i = 0; i != nCPU; ++i) threads.emplace_back( [&, i]() { process(&workLane, &_threadStats[i], polarizationCount); }); const bool hasInterval = !(_intervalStart == 0 && _intervalEnd == 0); const size_t nrow = table.nrow(); size_t timestepIndex = (size_t)-1; double prevtime = -1.0; for (size_t row = 0; row != nrow; ++row) { Work work; work.time = timeColumn(row); if (work.time != prevtime) { ++timestepIndex; prevtime = work.time; } if (!hasInterval || (timestepIndex >= _intervalStart && timestepIndex < _intervalEnd)) { work.antenna1Index = antenna1Column(row), work.antenna2Index = antenna2Column(row), work.bandIndex = windowColumn(row); work.timestepIndex = timestepIndex; const BandInfo& band = bands[work.bandIndex]; const casacore::Array dataArray = dataColumn(row); const casacore::Array flagArray = flagColumn(row); work.hasFlaggedAntenna = _flaggedAntennae.find(work.antenna1Index) != _flaggedAntennae.end() || _flaggedAntennae.find(work.antenna2Index) != _flaggedAntennae.end(); casacore::Array::const_contiter dataIter = dataArray.cbegin(); casacore::Array::const_contiter flagIter = flagArray.cbegin(); const unsigned startChannel = ignoreChannelZero ? 1 : 0; if (ignoreChannelZero) { dataIter += polarizationCount; flagIter += polarizationCount; } work.nChan = band.channels.size() - startChannel; work.isRFI.resize(polarizationCount); work.samples.resize(polarizationCount); for (unsigned p = 0; p < polarizationCount; ++p) { work.isRFI[p].resize(band.channels.size()); work.samples[p].resize(band.channels.size()); } for (unsigned channel = startChannel; channel < band.channels.size(); ++channel) { for (unsigned p = 0; p < polarizationCount; ++p) { work.samples[p][channel - startChannel] = *dataIter; work.isRFI[p][channel - startChannel] = *flagIter; ++dataIter; ++flagIter; } } workLane.write(std::move(work)); } progressListener.OnProgress(row, nrow); } workLane.write_end(); for (size_t i = 0; i != nCPU; ++i) threads[i].join(); progressListener.OnFinish(); } void Collector::process(aocommon::Lane* workLane, StatisticsCollection* stats, size_t polarizationCount) { Work work; HistogramCollection histos(polarizationCount); while (workLane->read(work)) { for (unsigned p = 0; p < polarizationCount; ++p) { switch (_mode) { case CollectDefault: if (work.hasFlaggedAntenna || work.timestepIndex < _flaggedTimesteps) stats->Add(work.antenna1Index, work.antenna2Index, work.time, work.bandIndex, p, &reinterpret_cast(work.samples[p].data())[0], &reinterpret_cast(work.samples[p].data())[1], work.isRFI[p].data(), _correlatorFlagsForBadAntenna.data(), work.nChan, 2, 1, 1); else stats->Add(work.antenna1Index, work.antenna2Index, work.time, work.bandIndex, p, &reinterpret_cast(work.samples[p].data())[0], &reinterpret_cast(work.samples[p].data())[1], work.isRFI[p].data(), _correlatorFlags.data(), work.nChan, 2, 1, 1); break; case CollectHistograms: histos.Add(work.antenna1Index, work.antenna2Index, p, work.samples[p].data(), work.isRFI[p].data(), work.nChan); break; case CollectTimeFrequency: if (work.hasFlaggedAntenna || work.timestepIndex < _flaggedTimesteps) stats->Add(work.antenna1Index, work.antenna2Index, work.time, work.bandIndex, p, &reinterpret_cast(work.samples[p].data())[0], &reinterpret_cast(work.samples[p].data())[1], work.isRFI[p].data(), _correlatorFlagsForBadAntenna.data(), work.nChan, 2, 1, 1); else stats->AddToTimeFrequency( work.antenna1Index, work.antenna2Index, work.time, work.bandIndex, p, &reinterpret_cast(work.samples[p].data())[0], &reinterpret_cast(work.samples[p].data())[1], work.isRFI[p].data(), _correlatorFlags.data(), work.nChan, 2, 1, 1); break; } } } const std::unique_lock lock(_mutex); _statisticsCollection->Add(*stats); _histogramCollection->Add(histos); } aoflagger-v3.4.0/quality/operations.cpp0000644000175000017500000005473514507760372016731 0ustar olesoles#include "operations.h" #include #include #include #include "collector.h" #include "combine.h" #include "defaultstatistics.h" #include "histogramcollection.h" #include "qualitytablesformatter.h" #include "statisticscollection.h" #include "statisticsderivator.h" #include "../util/progress/stdoutreporter.h" #include "../structures/msmetadata.h" namespace quality { namespace { void PrintStatistics(std::complex* complexStat, unsigned count) { if (count != 1) std::cout << '['; if (count > 0) std::cout << complexStat[0].real() << " + " << complexStat[0].imag() << 'i'; for (unsigned p = 1; p < count; ++p) { std::cout << ", " << complexStat[p].real() << " + " << complexStat[p].imag() << 'i'; } if (count != 1) std::cout << ']'; } void PrintStatistics(unsigned long* stat, unsigned count) { if (count != 1) std::cout << '['; if (count > 0) std::cout << stat[0]; for (unsigned p = 1; p < count; ++p) { std::cout << ", " << stat[p]; } if (count != 1) std::cout << ']'; } void PrintStatistics(const DefaultStatistics& statistics) { std::cout << "Count="; PrintStatistics(statistics.count, statistics.PolarizationCount()); std::cout << "\nSum="; PrintStatistics(statistics.sum, statistics.PolarizationCount()); std::cout << "\nSumP2="; PrintStatistics(statistics.sumP2, statistics.PolarizationCount()); std::cout << "\nDCount="; PrintStatistics(statistics.dCount, statistics.PolarizationCount()); std::cout << "\nDSum="; PrintStatistics(statistics.dSum, statistics.PolarizationCount()); std::cout << "\nDSumP2="; PrintStatistics(statistics.dSumP2, statistics.PolarizationCount()); std::cout << "\nRFICount="; PrintStatistics(statistics.rfiCount, statistics.PolarizationCount()); std::cout << '\n'; } void PrintRFISlopeForHistogram(const std::map& histogramMap, char polarizationSymbol, const AntennaInfo* antennae) { for (std::map::const_iterator i = histogramMap.begin(); i != histogramMap.end(); ++i) { const unsigned a1 = i->first.first, a2 = i->first.second; const Baseline baseline(antennae[a1], antennae[a2]); const double length = baseline.Distance(); const LogHistogram& histogram = *i->second; double start, end; histogram.GetRFIRegion(start, end); const double slope = histogram.NormalizedSlope(start, end); const double stddev = histogram.NormalizedSlopeStdError(start, end, slope); std::cout << polarizationSymbol << '\t' << a1 << '\t' << a2 << '\t' << length << '\t' << slope << '\t' << stddev << '\n'; } } } // namespace void ListStatistics() { for (int i = 0; i != QualityTablesFormatter::EndPlaceHolderStatistic; ++i) { const QualityTablesFormatter::StatisticKind kind = (QualityTablesFormatter::StatisticKind)i; std::cout << QualityTablesFormatter::KindToName(kind) << '\n'; } } void CollectStatistics(const std::string& filename, Collector::CollectingMode mode, size_t flaggedTimesteps, std::set&& flaggedAntennae, const char* dataColumnName, size_t intervalStart, size_t intervalEnd) { StatisticsCollection statisticsCollection; HistogramCollection histogramCollection; Collector collector; collector.SetDataColumn(dataColumnName); collector.SetInterval(intervalStart, intervalEnd); collector.SetMode(mode); collector.SetFlaggedAntennae(std::move(flaggedAntennae)); collector.SetFlaggedTimesteps(flaggedTimesteps); StdOutReporter reporter; collector.Collect(filename, statisticsCollection, histogramCollection, reporter); switch (mode) { case Collector::CollectDefault: case Collector::CollectTimeFrequency: { std::cout << "Writing quality tables..." << std::endl; QualityTablesFormatter qualityData(filename); statisticsCollection.Save(qualityData); } break; case Collector::CollectHistograms: { std::cout << "Writing histogram tables..." << std::endl; HistogramTablesFormatter histograms(filename); histogramCollection.Save(histograms); } break; } std::cout << "Done.\n"; } void CollectHistograms(const std::string& filename, HistogramCollection& histogramCollection, size_t flaggedTimesteps, std::set&& flaggedAntennae, const char* dataColumnName) { std::cout << "Collecting statistics...\n"; StatisticsCollection tempCollection; Collector collector; collector.SetDataColumn(dataColumnName); collector.SetMode(Collector::CollectHistograms); collector.SetFlaggedAntennae(std::move(flaggedAntennae)); collector.SetFlaggedTimesteps(flaggedTimesteps); StdOutReporter reporter; collector.Collect(filename, tempCollection, histogramCollection, reporter); } void PrintGlobalStatistic(const std::string& kindName, const std::vector& filenames) { const MSMetaData ms(filenames.front()); BandInfo band; if (ms.BandCount() != 0) band = ms.GetBandInfo(0); const QualityTablesFormatter::StatisticKind kind = QualityTablesFormatter::NameToKind(kindName); const quality::FileContents contents = quality::ReadAndCombine(filenames, false); const unsigned n_polarizations = contents.statistics_collection.PolarizationCount(); DefaultStatistics statistics(n_polarizations); contents.statistics_collection.GetGlobalCrossBaselineStatistics(statistics); const StatisticsDerivator derivator(contents.statistics_collection); const DefaultStatistics singlePol(statistics.ToSinglePolarization()); double start, end; if (band.channels.empty()) { start = 0.0; end = 0.0; } else { start = band.channels.begin()->frequencyHz; end = band.channels.rbegin()->frequencyHz; } std::cout << round(start / 10000.0) / 100.0 << '\t' << round(end / 10000.0) / 100.0 << '\t' << derivator.GetStatisticAmplitude(kind, singlePol, 0); for (unsigned p = 0; p < n_polarizations; ++p) { const long double val = derivator.GetStatisticAmplitude(kind, statistics, p); std::cout << '\t' << val; } std::cout << '\n'; } void PrintFrequencyRangeStatistic(const std::string& kindName, const std::vector& filenames, double startFreqMHz, double endFreqMHz) { const QualityTablesFormatter::StatisticKind kind = QualityTablesFormatter::NameToKind(kindName); const quality::FileContents contents = quality::ReadAndCombine(filenames, false); const unsigned n_polarizations = contents.statistics_collection.PolarizationCount(); DefaultStatistics statistics(n_polarizations); contents.statistics_collection.GetFrequencyRangeStatistics( statistics, startFreqMHz * 1e6, endFreqMHz * 1e6); const StatisticsDerivator derivator(contents.statistics_collection); const DefaultStatistics singlePol(statistics.ToSinglePolarization()); std::cout << startFreqMHz << '\t' << endFreqMHz << '\t' << derivator.GetStatisticAmplitude(kind, singlePol, 0); for (unsigned p = 0; p < n_polarizations; ++p) { const long double val = derivator.GetStatisticAmplitude(kind, statistics, p); std::cout << '\t' << val; } std::cout << '\n'; } void PrintPerBaselineStatistics(const std::string& kindName, const std::vector& filenames) { const QualityTablesFormatter::StatisticKind kind = QualityTablesFormatter::NameToKind(kindName); quality::FileContents contents = quality::ReadAndCombine(filenames, false); contents.statistics_collection.IntegrateBaselinesToOneChannel(); const std::vector>& baselines = contents.statistics_collection.BaselineStatistics().BaselineList(); const StatisticsDerivator derivator(contents.statistics_collection); std::cout << "ANTENNA1\tANTENNA2"; const unsigned n_polarizations = contents.statistics_collection.PolarizationCount(); for (unsigned p = 0; p < n_polarizations; ++p) std::cout << '\t' << kindName << "_POL" << p << "_R\t" << kindName << "_POL" << p << "_I"; std::cout << '\n'; for (std::vector>::const_iterator i = baselines.begin(); i != baselines.end(); ++i) { const unsigned antenna1 = i->first, antenna2 = i->second; std::cout << antenna1 << '\t' << antenna2; for (unsigned p = 0; p < n_polarizations; ++p) { const std::complex val = derivator.GetComplexBaselineStatistic(kind, antenna1, antenna2, p); std::cout << '\t' << val.real() << '\t' << val.imag(); } std::cout << '\n'; } } void PrintPerFrequencyStatistics(const std::string& kindName, const std::vector& filenames, std::optional downsample) { const QualityTablesFormatter::StatisticKind kind = QualityTablesFormatter::NameToKind(kindName); quality::FileContents contents = quality::ReadAndCombine(filenames, false); if (downsample) contents.statistics_collection.LowerFrequencyResolution(*downsample); const std::map& freqStats = contents.statistics_collection.FrequencyStatistics(); const StatisticsDerivator derivator(contents.statistics_collection); std::cout << "FREQUENCY"; const unsigned n_polarizations = contents.statistics_collection.PolarizationCount(); for (size_t p = 0; p < n_polarizations; ++p) std::cout << '\t' << kindName << "_POL" << p << "_R\t" << kindName << "_POL" << p << "_I"; std::cout << '\n'; for (const std::pair& freqStat : freqStats) { const double frequency = freqStat.first; std::cout << frequency * 1e-6; for (unsigned p = 0; p < n_polarizations; ++p) { const std::complex val = derivator.GetComplexStatistic(kind, freqStat.second, p); std::cout << '\t' << val.real() << '\t' << val.imag(); } std::cout << '\n'; } } void PrintPerTimeStatistics(const std::string& kindName, const std::vector& filenames) { const QualityTablesFormatter::StatisticKind kind = QualityTablesFormatter::NameToKind(kindName); quality::FileContents contents = quality::ReadAndCombine(filenames, false); contents.statistics_collection.IntegrateTimeToOneChannel(); const std::map& timeStats = contents.statistics_collection.TimeStatistics(); const StatisticsDerivator derivator(contents.statistics_collection); std::cout << "TIME"; const unsigned n_polarizations = contents.statistics_collection.PolarizationCount(); for (unsigned p = 0; p < n_polarizations; ++p) std::cout << '\t' << kindName << "_POL" << p << "_R\t" << kindName << "_POL" << p << "_I"; std::cout << '\n'; for (std::map::const_iterator i = timeStats.begin(); i != timeStats.end(); ++i) { const double time = i->first; std::cout << time; for (unsigned p = 0; p < n_polarizations; ++p) { const std::complex val = derivator.GetComplexStatistic(kind, i->second, p); std::cout << '\t' << val.real() << '\t' << val.imag(); } std::cout << '\n'; } } void PrintPerAntennaStatistics(const std::string& kindName, const std::vector& filenames) { const QualityTablesFormatter::StatisticKind kind = QualityTablesFormatter::NameToKind(kindName); quality::FileContents contents = quality::ReadAndCombine(filenames, false); contents.statistics_collection.IntegrateBaselinesToOneChannel(); const std::map stats = contents.statistics_collection.GetAntennaStatistics(); const StatisticsDerivator derivator(contents.statistics_collection); std::cout << "ANTENNA"; const unsigned n_polarizations = contents.statistics_collection.PolarizationCount(); for (unsigned p = 0; p < n_polarizations; ++p) std::cout << '\t' << kindName << "_POL" << p << "_R\t" << kindName << "_POL" << p << "_I"; std::cout << '\n'; for (const std::pair& s : stats) { const size_t antenna = s.first; std::cout << antenna; for (unsigned p = 0; p < n_polarizations; ++p) { const std::complex val = derivator.GetComplexStatistic(kind, s.second, p); std::cout << '\t' << val.real() << '\t' << val.imag(); } std::cout << '\n'; } } void PrintSummary(const std::vector& filenames) { const quality::FileContents contents = quality::ReadAndCombine(filenames, false); const unsigned n_polarizations = contents.statistics_collection.PolarizationCount(); DefaultStatistics statistics(n_polarizations); contents.statistics_collection.GetGlobalTimeStatistics(statistics); std::cout << "Time statistics: \n"; PrintStatistics(statistics); contents.statistics_collection.GetGlobalFrequencyStatistics(statistics); std::cout << "\nFrequency statistics: \n"; PrintStatistics(statistics); contents.statistics_collection.GetGlobalCrossBaselineStatistics(statistics); std::cout << "\nCross-correlated baseline statistics: \n"; PrintStatistics(statistics); const DefaultStatistics singlePolStat = statistics.ToSinglePolarization(); std::cout << "RFIPercentange: " << StatisticsDerivator::GetStatisticAmplitude( QualityTablesFormatter::RFIPercentageStatistic, singlePolStat, 0) << '\n'; contents.statistics_collection.GetGlobalAutoBaselineStatistics(statistics); std::cout << "\nAuto-correlated baseline: \n"; PrintStatistics(statistics); } void PrintRfiSummary(const std::vector& filenames) { const MSMetaData ms(filenames.front()); const BandInfo band = ms.GetBandInfo(0); const quality::FileContents contents = quality::ReadAndCombine(filenames, false); DefaultStatistics statistics( contents.statistics_collection.PolarizationCount()); contents.statistics_collection.GetGlobalCrossBaselineStatistics(statistics); const DefaultStatistics singlePolStat = statistics.ToSinglePolarization(); double startTime = contents.statistics_collection.TimeStatistics().begin()->first, endTime = contents.statistics_collection.TimeStatistics().rbegin()->first, startFreq = band.channels.begin()->frequencyHz, endFreq = band.channels.rbegin()->frequencyHz; std::cout.precision(16); std::cout << startTime << '\t' << endTime << '\t' << round(startFreq / 10000.0) / 100.0 << '\t' << round(endFreq / 10000.0) / 100.0 << '\t' << StatisticsDerivator::GetStatisticAmplitude( QualityTablesFormatter::RFIPercentageStatistic, singlePolStat, 0) << '\n'; } void WriteAntennae(casacore::MeasurementSet& ms, const std::vector& antennae) { casacore::MSAntenna antTable = ms.antenna(); casacore::ScalarColumn nameCol = casacore::ScalarColumn( antTable, antTable.columnName(casacore::MSAntennaEnums::NAME)); casacore::ScalarColumn stationCol = casacore::ScalarColumn( antTable, antTable.columnName(casacore::MSAntennaEnums::STATION)); casacore::ScalarColumn typeCol = casacore::ScalarColumn( antTable, antTable.columnName(casacore::MSAntennaEnums::TYPE)); casacore::ScalarColumn mountCol = casacore::ScalarColumn( antTable, antTable.columnName(casacore::MSAntennaEnums::MOUNT)); casacore::ArrayColumn positionCol = casacore::ArrayColumn( antTable, antTable.columnName(casacore::MSAntennaEnums::POSITION)); casacore::ScalarColumn dishDiameterCol = casacore::ScalarColumn( antTable, antTable.columnName(casacore::MSAntennaEnums::DISH_DIAMETER)); size_t rowIndex = antTable.nrow(); antTable.addRow(antennae.size()); for (std::vector::const_iterator antPtr = antennae.begin(); antPtr != antennae.end(); ++antPtr) { const AntennaInfo& ant = *antPtr; nameCol.put(rowIndex, ant.name); stationCol.put(rowIndex, ant.station); typeCol.put(rowIndex, ""); mountCol.put(rowIndex, ant.mount); casacore::Vector posArr(3); posArr[0] = ant.position.x; posArr[1] = ant.position.y; posArr[2] = ant.position.z; positionCol.put(rowIndex, posArr); dishDiameterCol.put(rowIndex, ant.diameter); ++rowIndex; } } void WritePolarizationForLinearPols(casacore::MeasurementSet& ms, bool flagRow = false) { casacore::MSPolarization polTable = ms.polarization(); casacore::ScalarColumn numCorrCol = casacore::ScalarColumn( polTable, polTable.columnName(casacore::MSPolarizationEnums::NUM_CORR)); casacore::ArrayColumn corrTypeCol = casacore::ArrayColumn( polTable, polTable.columnName(casacore::MSPolarizationEnums::CORR_TYPE)); casacore::ArrayColumn corrProductCol = casacore::ArrayColumn( polTable, polTable.columnName(casacore::MSPolarizationEnums::CORR_PRODUCT)); casacore::ScalarColumn flagRowCol = casacore::ScalarColumn( polTable, polTable.columnName(casacore::MSPolarizationEnums::FLAG_ROW)); const size_t rowIndex = polTable.nrow(); polTable.addRow(1); numCorrCol.put(rowIndex, 4); casacore::Vector cTypeVec(4); cTypeVec[0] = 9; cTypeVec[1] = 10; cTypeVec[2] = 11; cTypeVec[3] = 12; corrTypeCol.put(rowIndex, cTypeVec); casacore::Array cProdArr(casacore::IPosition(2, 2, 4)); casacore::Array::iterator i = cProdArr.begin(); *i = 0; ++i; *i = 0; ++i; *i = 0; ++i; *i = 1; ++i; *i = 1; ++i; *i = 0; ++i; *i = 1; ++i; *i = 1; corrProductCol.put(rowIndex, cProdArr); flagRowCol.put(rowIndex, flagRow); } void CombineStatistics(const std::string& result_filename, const std::vector& input_filenames) { if (!input_filenames.empty()) { const std::string& firstInFilename = *input_filenames.begin(); std::cout << "Combining " << input_filenames.size() << " sets into " << result_filename << '\n'; std::vector antennae; StatisticsCollection statisticsCollection; const HistogramCollection histogramCollection; std::cout << "Reading antenna table...\n"; const MSMetaData msMeta(firstInFilename); antennae.resize(msMeta.AntennaCount()); for (size_t i = 0; i != msMeta.AntennaCount(); ++i) antennae[i] = msMeta.GetAntennaInfo(i); for (std::vector::const_iterator i = input_filenames.begin(); i != input_filenames.end(); ++i) { std::cout << "Reading " << *i << "...\n"; // TODO read quality tables from all inFilenames QualityTablesFormatter formatter(*i); StatisticsCollection collectionPart; collectionPart.Load(formatter); if (i == input_filenames.begin()) statisticsCollection.SetPolarizationCount( collectionPart.PolarizationCount()); statisticsCollection.Add(collectionPart); } // Create main table casacore::TableDesc tableDesc = casacore::MS::requiredTableDesc(); const casacore::ArrayColumnDesc> dataColumnDesc = casacore::ArrayColumnDesc>( casacore::MS::columnName(casacore::MSMainEnums::DATA)); tableDesc.addColumn(dataColumnDesc); casacore::SetupNewTable newTab(result_filename, tableDesc, casacore::Table::New); casacore::MeasurementSet ms(newTab); ms.createDefaultSubtables(casacore::Table::New); std::cout << "Writing antenna table...\n"; WriteAntennae(ms, antennae); std::cout << "Writing polarization table (" << statisticsCollection.PolarizationCount() << " pols)...\n"; WritePolarizationForLinearPols(ms); std::cout << "Writing quality table...\n"; QualityTablesFormatter formatter(result_filename); statisticsCollection.Save(formatter); } } void RemoveStatistics(const std::string& filename) { QualityTablesFormatter formatter(filename); formatter.RemoveAllQualityTables(); } void PrintRfiSlope(const std::string& filename) { HistogramTablesFormatter histogramFormatter(filename); const unsigned polarizationCount = MSMetaData::PolarizationCount(filename); HistogramCollection collection(polarizationCount); collection.Load(histogramFormatter); const MSMetaData set(filename); std::cout << set.GetBandInfo(0).CenterFrequencyHz(); for (unsigned p = 0; p < polarizationCount; ++p) { LogHistogram histogram; collection.GetRFIHistogramForCrossCorrelations(p, histogram); std::cout << '\t' << histogram.NormalizedSlopeInRFIRegion(); } std::cout << '\n'; } void PrintRfiSlopePerBaseline(const std::string& filename, const char* dataColumnName) { HistogramTablesFormatter histogramFormatter(filename); const unsigned polarizationCount = MSMetaData::PolarizationCount(filename); HistogramCollection collection; CollectHistograms(filename, collection, 0, std::set(), dataColumnName); const MSMetaData set(filename); const size_t antennaCount = set.AntennaCount(); std::vector antennae(antennaCount); for (size_t a = 0; a < antennaCount; ++a) antennae[a] = set.GetAntennaInfo(a); HistogramCollection* summedCollection = collection.CreateSummedPolarizationCollection(); const std::map& histogramMap = summedCollection->GetRFIHistogram(0); PrintRFISlopeForHistogram(histogramMap, '*', &antennae[0]); delete summedCollection; for (unsigned p = 0; p < polarizationCount; ++p) { const std::map& histogramMap = collection.GetRFIHistogram(p); PrintRFISlopeForHistogram(histogramMap, '0' + p, &antennae[0]); } } void RemoveHistogram(const std::string& filename) { HistogramTablesFormatter histogramFormatter(filename); histogramFormatter.RemoveAll(); } } // namespace quality aoflagger-v3.4.0/quality/qualitytablesformatter.h0000644000175000017500000002561514507760372021015 0ustar olesoles#ifndef MSIO_QUALITY_DATA_H #define MSIO_QUALITY_DATA_H #include #include #define QUALITY_TABLES_VERSION 1 #define QUALITY_TABLES_VERSION_STR "1" class StatisticalValue; class QualityTablesFormatter { public: enum StatisticKind { CountStatistic, SumStatistic, MeanStatistic, RFICountStatistic, RFISumStatistic, RFIMeanStatistic, RFIRatioStatistic, RFIPercentageStatistic, FlaggedCountStatistic, FlaggedRatioStatistic, SumP2Statistic, SumP3Statistic, SumP4Statistic, VarianceStatistic, VarianceOfVarianceStatistic, StandardDeviationStatistic, SkewnessStatistic, KurtosisStatistic, SignalToNoiseStatistic, DSumStatistic, DMeanStatistic, DSumP2Statistic, DSumP3Statistic, DSumP4Statistic, DVarianceStatistic, DVarianceOfVarianceStatistic, DStandardDeviationStatistic, DCountStatistic, BadSolutionCountStatistic, CorrectCountStatistic, CorrectedMeanStatistic, CorrectedSumP2Statistic, CorrectedDCountStatistic, CorrectedDMeanStatistic, CorrectedDSumP2Statistic, FTSumStatistic, FTSumP2Statistic, EndPlaceHolderStatistic }; enum StatisticDimension { TimeDimension, FrequencyDimension, BaselineDimension, BaselineTimeDimension }; enum QualityTable { KindNameTable, TimeStatisticTable, FrequencyStatisticTable, BaselineStatisticTable, BaselineTimeStatisticTable }; struct TimePosition { double time; double frequency; }; struct FrequencyPosition { double frequency; }; struct BaselinePosition { unsigned antenna1; unsigned antenna2; double frequency; }; struct BaselineTimePosition { double time; unsigned antenna1; unsigned antenna2; double frequency; }; explicit QualityTablesFormatter(const std::string& measurementSetName) : _measurementSet(), _measurementSetName(measurementSetName), _kindNameTable(), _timeTable(), _frequencyTable(), _baselineTable(), _baselineTimeTable() {} ~QualityTablesFormatter() { Close(); } void Close() { _kindNameTable.reset(); _timeTable.reset(); _frequencyTable.reset(); _baselineTable.reset(); _baselineTimeTable.reset(); _measurementSet.reset(); } bool TableExists(enum QualityTable table) const { return _measurementSet->isReadable(TableToFilename(table)); } static const std::string& KindToName(const enum StatisticKind kind) { return _kindToNameTable[(int)kind]; } static enum StatisticKind NameToKind(const std::string& kindName); static const std::string& TableToName(const enum QualityTable table) { return _tableToNameTable[(int)table]; } const std::string TableToFilename(const enum QualityTable table) const { return _measurementSetName + '/' + TableToName(table); } enum QualityTable DimensionToTable( const enum StatisticDimension dimension) const { return _dimensionToTableTable[(int)dimension]; } bool IsStatisticAvailable(enum StatisticDimension dimension, enum StatisticKind kind); void InitializeEmptyStatistic(enum StatisticDimension dimension, enum StatisticKind kind, unsigned polarizationCount); void InitializeEmptyTable(enum QualityTable table, unsigned polarizationCount); void RemoveTable(enum QualityTable table); void RemoveAllQualityTables() { RemoveTable(BaselineTimeStatisticTable); RemoveTable(BaselineStatisticTable); RemoveTable(FrequencyStatisticTable); RemoveTable(TimeStatisticTable); RemoveTable(KindNameTable); } unsigned StoreKindName(enum StatisticKind kind) { return StoreKindName(KindToName(kind)); } unsigned StoreKindName(const std::string& name); void StoreTimeValue(double time, double frequency, const StatisticalValue& value); void StoreFrequencyValue(double frequency, const StatisticalValue& value); void StoreBaselineValue(unsigned antenna1, unsigned antenna2, double frequency, const StatisticalValue& value); void StoreBaselineTimeValue(unsigned antenna1, unsigned antenna2, double time, double frequency, const StatisticalValue& value); unsigned QueryKindIndex(enum StatisticKind kind); bool QueryKindIndex(enum StatisticKind kind, unsigned& destKindIndex); unsigned StoreOrQueryKindIndex(enum StatisticKind kind) { unsigned kindIndex; if (QueryKindIndex(kind, kindIndex)) return kindIndex; else return StoreKindName(kind); } unsigned QueryStatisticEntryCount(enum StatisticDimension dimension, unsigned kindIndex); void QueryTimeStatistic( unsigned kindIndex, std::vector>& entries); void QueryFrequencyStatistic( unsigned kindIndex, std::vector>& entries); void QueryBaselineStatistic( unsigned kindIndex, std::vector>& entries); void QueryBaselineTimeStatistic( unsigned kindIndex, std::vector>& entries); unsigned GetPolarizationCount(); private: QualityTablesFormatter(const QualityTablesFormatter&) = delete; // don't allow copies void operator=(const QualityTablesFormatter&) = delete; // don't allow assignment static const std::string _kindToNameTable[]; static const std::string _tableToNameTable[]; static const QualityTable _dimensionToTableTable[]; static const std::string ColumnNameAntenna1; static const std::string ColumnNameAntenna2; static const std::string ColumnNameFrequency; static const std::string ColumnNameKind; static const std::string ColumnNameName; static const std::string ColumnNameTime; static const std::string ColumnNameValue; std::unique_ptr _measurementSet; const std::string _measurementSetName; std::unique_ptr _kindNameTable; std::unique_ptr _timeTable; std::unique_ptr _frequencyTable; std::unique_ptr _baselineTable; std::unique_ptr _baselineTimeTable; bool hasOneEntry(enum QualityTable table, unsigned kindIndex); void removeStatisticFromStatTable(enum QualityTable table, enum StatisticKind kind); void removeKindNameEntry(enum StatisticKind kind); void removeEntries(enum QualityTable table); /** * Add the time column to the table descriptor. Used by create..Table() * methods. It holds "Measure"s of time, which is what casacore defines as a * value including a unit and a reference frame. */ void addTimeColumn(casacore::TableDesc& tableDesc); /** * Add the frequency column to the table descriptor. Used by create..Table() * methods. It holds "Quantum"s of frequency, which is what casacore defines * as a value including a unit (Hertz). */ void addFrequencyColumn(casacore::TableDesc& tableDesc); /** * Add value column to the table descriptor. Used by create..Table() methods. * It consist of an array of statistics, each element holds a polarization. */ void addValueColumn(casacore::TableDesc& tableDesc, unsigned polarizationCount); void createTable(enum QualityTable table, unsigned polarizationCount) { switch (table) { case KindNameTable: createKindNameTable(); break; case TimeStatisticTable: createTimeStatisticTable(polarizationCount); break; case FrequencyStatisticTable: createFrequencyStatisticTable(polarizationCount); break; case BaselineStatisticTable: createBaselineStatisticTable(polarizationCount); break; case BaselineTimeStatisticTable: createBaselineTimeStatisticTable(polarizationCount); break; default: break; } } /** * Will add an empty table to the measurement set named "QUALITY_KIND_NAME" * and initialize its default column. This table can hold a list of quality * statistic types that are referred to in the statistic value tables. */ void createKindNameTable(); /** * Will add an empty table to the measurement set named * "QUALITY_TIME_STATISTIC" and initialize its default column. This table can * hold several statistic kinds per time step. * @param polarizationCount specifies the nr polarizations. This is required * for the shape of the value column. */ void createTimeStatisticTable(unsigned polarizationCount); /** * Will add an empty table to the measurement set named * "QUALITY_FREQUENCY_STATISTIC" and initialize its default column. This table * can hold several statistic kinds per time step. * @param polarizationCount specifies the nr polarizations. This is required * for the shape of the value column. */ void createFrequencyStatisticTable(unsigned polarizationCount); /** * Will add an empty table to the measurement set named * "QUALITY_BASELINE_STATISTIC" and initialize its default column. This table * can hold several statistic kinds per time step. * @param polarizationCount specifies the nr polarizations. This is required * for the shape of the value column. */ void createBaselineStatisticTable(unsigned polarizationCount); void createBaselineTimeStatisticTable(unsigned polarizationCount); unsigned findFreeKindIndex(casacore::Table& kindTable); void openMainTable(bool needWrite); void openTable(QualityTable table, bool needWrite, std::unique_ptr& tablePtr); void openKindNameTable(bool needWrite) { openTable(KindNameTable, needWrite, _kindNameTable); } void openTimeTable(bool needWrite) { openTable(TimeStatisticTable, needWrite, _timeTable); } void openFrequencyTable(bool needWrite) { openTable(FrequencyStatisticTable, needWrite, _frequencyTable); } void openBaselineTable(bool needWrite) { openTable(BaselineStatisticTable, needWrite, _baselineTable); } void openBaselineTimeTable(bool needWrite) { openTable(BaselineTimeStatisticTable, needWrite, _baselineTimeTable); } casacore::Table& getTable(QualityTable table, bool needWrite) { std::unique_ptr* tablePtr = nullptr; switch (table) { case KindNameTable: tablePtr = &_kindNameTable; break; case TimeStatisticTable: tablePtr = &_timeTable; break; case FrequencyStatisticTable: tablePtr = &_frequencyTable; break; case BaselineStatisticTable: tablePtr = &_baselineTable; break; case BaselineTimeStatisticTable: tablePtr = &_baselineTimeTable; break; } openTable(table, needWrite, *tablePtr); return **tablePtr; } }; #endif aoflagger-v3.4.0/quality/rayleighfitter.h0000644000175000017500000000266214507760372017225 0ustar olesoles#ifndef RAYLEIGHFITTER_H #define RAYLEIGHFITTER_H #include "loghistogram.h" class RayleighFitter { public: RayleighFitter() : _fitLogarithmic(true), _hist(nullptr), _minVal(0.0), _maxVal(0.0) {} void Fit(double minVal, double maxVal, const LogHistogram& hist, double& sigma, double& n); static double SigmaEstimate(const LogHistogram& hist); static double SigmaEstimate(const LogHistogram& hist, double rangeStart, double rangeEnd); static double NEstimate(const LogHistogram& hist, double rangeStart, double rangeEnd); static void FindFitRangeUnderRFIContamination(double minPositiveAmplitude, double sigmaEstimate, double& minValue, double& maxValue); static double RayleighValue(double sigma, double n, double x) { double sigmaP2 = sigma * sigma; return n * x / (sigmaP2)*exp(-x * x / (2 * sigmaP2)); } static double ErrorOfFit(const LogHistogram& histogram, double rangeStart, double rangeEnd, double sigma, double n); bool FitLogarithmic() const { return _fitLogarithmic; } void SetFitLogarithmic(bool fitLogarithmic) { _fitLogarithmic = fitLogarithmic; } private: bool _fitLogarithmic; public: const LogHistogram* _hist; double _minVal, _maxVal; }; #endif aoflagger-v3.4.0/quality/histogramcollection.cpp0000644000175000017500000001014114507760372020576 0ustar olesoles#include "histogramcollection.h" #include "histogramtablesformatter.h" void HistogramCollection::Save(HistogramTablesFormatter& histogramTables) { histogramTables.InitializeEmptyTables(); for (size_t p = 0; p < _polarizationCount; ++p) { LogHistogram totalHistogram; GetTotalHistogramForCrossCorrelations(p, totalHistogram); const unsigned totalIndex = histogramTables.StoreOrQueryTypeIndex( HistogramTablesFormatter::TotalHistogram, p); for (LogHistogram::iterator i = totalHistogram.begin(); i != totalHistogram.end(); ++i) { histogramTables.StoreValue(totalIndex, i.binStart(), i.binEnd(), i.unnormalizedCount()); } LogHistogram rfiHistogram; GetRFIHistogramForCrossCorrelations(p, rfiHistogram); const unsigned rfiIndex = histogramTables.StoreOrQueryTypeIndex( HistogramTablesFormatter::RFIHistogram, p); for (LogHistogram::iterator i = rfiHistogram.begin(); i != rfiHistogram.end(); ++i) { histogramTables.StoreValue(rfiIndex, i.binStart(), i.binEnd(), i.unnormalizedCount()); } } } void HistogramCollection::Load(HistogramTablesFormatter& histogramTables) { Clear(); for (unsigned p = 0; p < _polarizationCount; ++p) { const unsigned totalHistogramIndex = histogramTables.QueryTypeIndex( HistogramTablesFormatter::TotalHistogram, p); std::vector totalHistogram; histogramTables.QueryHistogram(totalHistogramIndex, totalHistogram); GetTotalHistogram(0, 1, p).SetData(totalHistogram); const unsigned rfiHistogramIndex = histogramTables.QueryTypeIndex( HistogramTablesFormatter::RFIHistogram, p); std::vector rfiHistogram; histogramTables.QueryHistogram(rfiHistogramIndex, rfiHistogram); GetRFIHistogram(0, 1, p).SetData(rfiHistogram); } } void HistogramCollection::Add(const unsigned antenna1, const unsigned antenna2, const unsigned polarization, Image2DCPtr image, Mask2DCPtr flagMask) { LogHistogram& totalHistogram = GetTotalHistogram(antenna1, antenna2, polarization); LogHistogram& rfiHistogram = GetRFIHistogram(antenna1, antenna2, polarization); for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const double amplitude = image->Value(x, y); totalHistogram.Add(amplitude); if (flagMask->Value(x, y)) rfiHistogram.Add(amplitude); } } } void HistogramCollection::Add(const unsigned antenna1, const unsigned antenna2, const unsigned polarization, Image2DCPtr image, Mask2DCPtr flagMask, Mask2DCPtr correlatorMask) { LogHistogram& totalHistogram = GetTotalHistogram(antenna1, antenna2, polarization); LogHistogram& rfiHistogram = GetRFIHistogram(antenna1, antenna2, polarization); for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (!correlatorMask->Value(x, y)) { const double amplitude = image->Value(x, y); totalHistogram.Add(amplitude); if (flagMask->Value(x, y)) rfiHistogram.Add(amplitude); } } } } void HistogramCollection::Add(const unsigned antenna1, const unsigned antenna2, const unsigned polarization, Image2DCPtr real, Image2DCPtr imaginary, Mask2DCPtr flagMask, Mask2DCPtr correlatorMask) { LogHistogram& totalHistogram = GetTotalHistogram(antenna1, antenna2, polarization); LogHistogram& rfiHistogram = GetRFIHistogram(antenna1, antenna2, polarization); for (size_t y = 0; y < real->Height(); ++y) { for (size_t x = 0; x < real->Width(); ++x) { if (!correlatorMask->Value(x, y)) { const double r = real->Value(x, y), i = imaginary->Value(x, y); const double amplitude = sqrt(r * r + i * i); totalHistogram.Add(amplitude); if (flagMask->Value(x, y)) rfiHistogram.Add(amplitude); } } } } aoflagger-v3.4.0/quality/combine.h0000644000175000017500000000102114507760372015603 0ustar olesoles#ifndef AOFLAGGER_QUALITY_COMBINE_H_ #define AOFLAGGER_QUALITY_COMBINE_H_ #include #include #include "histogramcollection.h" #include "statisticscollection.h" namespace quality { struct FileContents { StatisticsCollection statistics_collection; HistogramCollection histogram_collection; }; /** * Reads and combines a number of quality statistics tables. */ FileContents ReadAndCombine(const std::vector& files, bool verbose); } // namespace quality #endif aoflagger-v3.4.0/quality/operations.h0000644000175000017500000000440614507760372016364 0ustar olesoles#ifndef AOFLAGGER_QUALITY_OPERATIONS_H_ #define AOFLAGGER_QUALITY_OPERATIONS_H_ #include #include #include #include "collector.h" namespace quality { void ListStatistics(); void CollectStatistics(const std::string& filename, Collector::CollectingMode mode, size_t flaggedTimesteps, std::set&& flaggedAntennae, const char* dataColumnName, size_t intervalStart, size_t intervalEnd); void CollectHistograms(const std::string& filename, HistogramCollection& histogramCollection, size_t flaggedTimesteps, std::set&& flaggedAntennae, const char* dataColumnName); void CombineStatistics(const std::string& result_filename, const std::vector& input_filenames); void RemoveStatistics(const std::string& filename); void RemoveHistogram(const std::string& filename); void PrintSummary(const std::vector& filenames); void PrintRfiSummary(const std::vector& filenames); void PrintGlobalStatistic(const std::string& kindName, const std::vector& filenames); void PrintPerAntennaStatistics(const std::string& kindName, const std::vector& filenames); void PrintPerBaselineStatistics(const std::string& kindName, const std::vector& filenames); void PrintPerTimeStatistics(const std::string& kindName, const std::vector& filenames); void PrintPerFrequencyStatistics(const std::string& kindName, const std::vector& filenames, std::optional downsample); void PrintFrequencyRangeStatistic(const std::string& kindName, const std::vector& filenames, double startFreqMHz, double endFreqMHz); void PrintRfiSlope(const std::string& filename); void PrintRfiSlopePerBaseline(const std::string& filename, const char* dataColumnName); } // namespace quality #endif aoflagger-v3.4.0/quality/qualitytablesformatter.cpp0000644000175000017500000006321514507760372021346 0ustar olesoles#include "qualitytablesformatter.h" #include #include #include #include #include #include #include #include #include #include "statisticalvalue.h" const std::string QualityTablesFormatter::_kindToNameTable[] = { "Count", "Sum", "Mean", "RFICount", "RFISum", "RFIMean", "RFIRatio", "RFIPercentage", "FlaggedCount", "FlaggedRatio", "SumP2", "SumP3", "SumP4", "Variance", "VarianceOfVariance", "StandardDeviation", "Skewness", "Kurtosis", "SignalToNoise", "DSum", "DMean", "DSumP2", "DSumP3", "DSumP4", "DVariance", "DVarianceOfVariance", "DStandardDeviation", "DCount", "BadSolutionCount", "CorrectCount", "CorrectedMean", "CorrectedSumP2", "CorrectedDCount", "CorrectedDMean", "CorrectedDSumP2", "FTSum", "FTSumP2"}; const std::string QualityTablesFormatter::_tableToNameTable[] = { "QUALITY_KIND_NAME", "QUALITY_TIME_STATISTIC", "QUALITY_FREQUENCY_STATISTIC", "QUALITY_BASELINE_STATISTIC", "QUALITY_BASELINE_TIME_STATISTIC"}; const enum QualityTablesFormatter::QualityTable QualityTablesFormatter::_dimensionToTableTable[] = { TimeStatisticTable, FrequencyStatisticTable, BaselineStatisticTable, BaselineTimeStatisticTable}; const std::string QualityTablesFormatter::ColumnNameAntenna1 = "ANTENNA1"; const std::string QualityTablesFormatter::ColumnNameAntenna2 = "ANTENNA2"; const std::string QualityTablesFormatter::ColumnNameFrequency = "FREQUENCY"; const std::string QualityTablesFormatter::ColumnNameKind = "KIND"; const std::string QualityTablesFormatter::ColumnNameName = "NAME"; const std::string QualityTablesFormatter::ColumnNameTime = "TIME"; const std::string QualityTablesFormatter::ColumnNameValue = "VALUE"; enum QualityTablesFormatter::StatisticKind QualityTablesFormatter::NameToKind( const std::string& kindName) { for (unsigned i = 0; i < 37; ++i) { if (kindName == _kindToNameTable[i]) return (QualityTablesFormatter::StatisticKind)i; } throw std::runtime_error("Statistics kind not known"); } unsigned QualityTablesFormatter::QueryKindIndex(enum StatisticKind kind) { unsigned kindIndex; if (!QueryKindIndex(kind, kindIndex)) throw std::runtime_error( "getKindIndex(): Requested statistic kind not available."); return kindIndex; } bool QualityTablesFormatter::QueryKindIndex(enum StatisticKind kind, unsigned& destKindIndex) { openKindNameTable(false); const casacore::ROScalarColumn kindColumn(*_kindNameTable, ColumnNameKind); const casacore::ROScalarColumn nameColumn(*_kindNameTable, ColumnNameName); const casacore::String nameToFind(KindToName(kind)); const unsigned nrRow = _kindNameTable->nrow(); for (unsigned i = 0; i < nrRow; ++i) { if (nameColumn(i) == nameToFind) { destKindIndex = kindColumn(i); return true; } } return false; } bool QualityTablesFormatter::IsStatisticAvailable( enum StatisticDimension dimension, enum StatisticKind kind) { const QualityTable table = DimensionToTable(dimension); if (!TableExists(KindNameTable) || !TableExists(table)) return false; unsigned kindIndex; if (!QueryKindIndex(kind, kindIndex)) return false; return hasOneEntry(table, kindIndex); } void QualityTablesFormatter::InitializeEmptyStatistic( enum StatisticDimension dimension, enum StatisticKind kind, unsigned polarizationCount) { if (!TableExists(KindNameTable)) createKindNameTable(); const QualityTable table = DimensionToTable(dimension); if (!TableExists(table)) { InitializeEmptyTable(table, polarizationCount); } else { removeStatisticFromStatTable(table, kind); } } void QualityTablesFormatter::InitializeEmptyTable(enum QualityTable table, unsigned polarizationCount) { if (TableExists(table)) removeEntries(table); else createTable(table, polarizationCount); } void QualityTablesFormatter::RemoveTable(enum QualityTable table) { if (TableExists(table)) { Close(); openMainTable(true); if (_measurementSet->keywordSet().isDefined(TableToName(table))) _measurementSet->rwKeywordSet().removeField(TableToName(table)); if (_measurementSet->isReadable(TableToFilename(table))) casacore::Table::deleteTable(TableToFilename(table)); } } bool QualityTablesFormatter::hasOneEntry(enum QualityTable table, unsigned kindIndex) { const casacore::Table& casaTable = getTable(table, false); const casacore::ROScalarColumn kindColumn(casaTable, ColumnNameKind); const unsigned nrRow = casaTable.nrow(); for (unsigned i = 0; i < nrRow; ++i) { if (kindColumn(i) == (int)kindIndex) return true; } return false; } /** * Will add an empty table to the measurement set named "QUALITY_KIND_NAME" and * initialize its default column. * This table can hold a list of quality statistic types that are referred to in * the statistic value tables. */ void QualityTablesFormatter::createKindNameTable() { casacore::TableDesc tableDesc("QUALITY_KIND_NAME_TYPE", QUALITY_TABLES_VERSION_STR, casacore::TableDesc::Scratch); tableDesc.comment() = "Couples the KIND column in the other quality tables to the name of a " "statistic (e.g. Mean)"; tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameKind, "Index of the statistic kind")); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameName, "Name of the statistic")); casacore::SetupNewTable newTableSetup(TableToFilename(KindNameTable), tableDesc, casacore::Table::New); const casacore::Table newTable(newTableSetup); openMainTable(true); _measurementSet->rwKeywordSet().defineTable(TableToName(KindNameTable), newTable); } /** * Add the time column to the table descriptor. Used by create..Table() methods. * It holds "Measure"s of time, which is what casacore defines as a value * including a unit and a reference frame. */ void QualityTablesFormatter::addTimeColumn(casacore::TableDesc& tableDesc) { const casacore::ScalarColumnDesc timeDesc( ColumnNameTime, "Central time of statistic"); tableDesc.addColumn(timeDesc); const casacore::TableMeasRefDesc measRef(casacore::MEpoch::UTC); const casacore::TableMeasValueDesc measVal(tableDesc, ColumnNameTime); casacore::TableMeasDesc mepochCol(measVal, measRef); mepochCol.write(tableDesc); } /** * Add the frequency column to the table descriptor. Used by create..Table() * methods. It holds "Quantum"s of frequency, which is what casacore defines as * a value including a unit (Hertz). */ void QualityTablesFormatter::addFrequencyColumn( casacore::TableDesc& tableDesc) { const casacore::ScalarColumnDesc freqDesc( ColumnNameFrequency, "Central frequency of statistic bin"); tableDesc.addColumn(freqDesc); const casacore::Unit hertzUnit("Hz"); casacore::TableQuantumDesc quantDesc(tableDesc, ColumnNameFrequency, hertzUnit); quantDesc.write(tableDesc); } /** * Add value column to the table descriptor. Used by create..Table() methods. * It consist of an array of statistics, each element holds a polarization. */ void QualityTablesFormatter::addValueColumn(casacore::TableDesc& tableDesc, unsigned polarizationCount) { casacore::IPosition shape(1); shape[0] = polarizationCount; const casacore::ArrayColumnDesc valDesc( ColumnNameValue, "Value of statistic", shape, casacore::ColumnDesc::Direct); tableDesc.addColumn(valDesc); } /** * Will add an empty table to the measurement set named "QUALITY_TIME_STATISTIC" * and initialize its default column. This table can hold several statistic * kinds per time step. * @param polarizationCount specifies the nr polarizations. This is required for * the shape of the value column. */ void QualityTablesFormatter::createTimeStatisticTable( unsigned polarizationCount) { casacore::TableDesc tableDesc("QUALITY_TIME_STATISTIC_TYPE", QUALITY_TABLES_VERSION_STR, casacore::TableDesc::Scratch); tableDesc.comment() = "Statistics over time"; addTimeColumn(tableDesc); addFrequencyColumn(tableDesc); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameKind, "Index of the statistic kind")); addValueColumn(tableDesc, polarizationCount); casacore::SetupNewTable newTableSetup(TableToFilename(TimeStatisticTable), tableDesc, casacore::Table::New); const casacore::Table newTable(newTableSetup); openMainTable(true); _measurementSet->rwKeywordSet().defineTable(TableToName(TimeStatisticTable), newTable); } /** * Will add an empty table to the measurement set named * "QUALITY_FREQUENCY_STATISTIC" and initialize its default column. This table * can hold several statistic kinds per time step. * @param polarizationCount specifies the nr polarizations. This is required for * the shape of the value column. */ void QualityTablesFormatter::createFrequencyStatisticTable( unsigned polarizationCount) { casacore::TableDesc tableDesc("QUALITY_FREQUENCY_STATISTIC_TYPE", QUALITY_TABLES_VERSION_STR, casacore::TableDesc::Scratch); tableDesc.comment() = "Statistics over frequency"; addFrequencyColumn(tableDesc); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameKind, "Index of the statistic kind")); addValueColumn(tableDesc, polarizationCount); casacore::SetupNewTable newTableSetup( TableToFilename(FrequencyStatisticTable), tableDesc, casacore::Table::New); const casacore::Table newTable(newTableSetup); openMainTable(true); _measurementSet->rwKeywordSet().defineTable( TableToName(FrequencyStatisticTable), newTable); } /** * Will add an empty table to the measurement set named * "QUALITY_BASELINE_STATISTIC" and initialize its default column. This table * can hold several statistic kinds per time step. * @param polarizationCount specifies the nr polarizations. This is required for * the shape of the value column. */ void QualityTablesFormatter::createBaselineStatisticTable( unsigned polarizationCount) { casacore::TableDesc tableDesc("QUALITY_BASELINE_STATISTIC_TYPE", QUALITY_TABLES_VERSION_STR, casacore::TableDesc::Scratch); tableDesc.comment() = "Statistics per baseline"; tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameAntenna1, "Index of first antenna")); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameAntenna2, "Index of second antenna")); addFrequencyColumn(tableDesc); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameKind, "Index of the statistic kind")); addValueColumn(tableDesc, polarizationCount); casacore::SetupNewTable newTableSetup(TableToFilename(BaselineStatisticTable), tableDesc, casacore::Table::New); const casacore::Table newTable(newTableSetup); openMainTable(true); _measurementSet->rwKeywordSet().defineTable( TableToName(BaselineStatisticTable), newTable); } void QualityTablesFormatter::createBaselineTimeStatisticTable( unsigned polarizationCount) { casacore::TableDesc tableDesc("QUALITY_BASELINE_TIME_STATISTIC_TYPE", QUALITY_TABLES_VERSION_STR, casacore::TableDesc::Scratch); tableDesc.comment() = "Statistics per baseline"; addTimeColumn(tableDesc); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameAntenna1, "Index of first antenna")); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameAntenna2, "Index of second antenna")); addFrequencyColumn(tableDesc); tableDesc.addColumn(casacore::ScalarColumnDesc( ColumnNameKind, "Index of the statistic kind")); addValueColumn(tableDesc, polarizationCount); casacore::SetupNewTable newTableSetup( TableToFilename(BaselineTimeStatisticTable), tableDesc, casacore::Table::New); const casacore::Table newTable(newTableSetup); openMainTable(true); _measurementSet->rwKeywordSet().defineTable( TableToName(BaselineTimeStatisticTable), newTable); } unsigned QualityTablesFormatter::StoreKindName(const std::string& name) { // This should be done atomically, but two quality writers in the same table // would be a weird thing to do anyway, plus I don't know how the casa tables // can be made atomic (and still have good performance). openKindNameTable(true); const unsigned kindIndex = findFreeKindIndex(*_kindNameTable); const unsigned newRow = _kindNameTable->nrow(); _kindNameTable->addRow(); casacore::ScalarColumn kindColumn(*_kindNameTable, ColumnNameKind); casacore::ScalarColumn nameColumn(*_kindNameTable, ColumnNameName); kindColumn.put(newRow, kindIndex); nameColumn.put(newRow, name); return kindIndex; } unsigned QualityTablesFormatter::findFreeKindIndex(casacore::Table& kindTable) { int maxIndex = 0; const casacore::ROScalarColumn kindColumn(kindTable, ColumnNameKind); const unsigned nrRow = kindTable.nrow(); for (unsigned i = 0; i < nrRow; ++i) { if (kindColumn(i) > maxIndex) maxIndex = kindColumn(i); } return maxIndex + 1; } void QualityTablesFormatter::openTable( QualityTable table, bool needWrite, std::unique_ptr& tablePtr) { if (tablePtr == nullptr) { openMainTable(false); tablePtr.reset(new casacore::Table( _measurementSet->keywordSet().asTable(TableToName(table)))); if (needWrite) tablePtr->reopenRW(); } else { if (needWrite && !tablePtr->isWritable()) tablePtr->reopenRW(); } } void QualityTablesFormatter::StoreTimeValue(double time, double frequency, const StatisticalValue& value) { openTimeTable(true); const unsigned newRow = _timeTable->nrow(); _timeTable->addRow(); // TODO maybe the columns need to be cached to avoid having to look them up // for each store... casacore::ScalarColumn timeColumn(*_timeTable, ColumnNameTime); casacore::ScalarColumn frequencyColumn(*_timeTable, ColumnNameFrequency); casacore::ScalarColumn kindColumn(*_timeTable, ColumnNameKind); casacore::ArrayColumn valueColumn(*_timeTable, ColumnNameValue); timeColumn.put(newRow, time); frequencyColumn.put(newRow, frequency); kindColumn.put(newRow, value.KindIndex()); casacore::Vector data(value.PolarizationCount()); for (unsigned i = 0; i < value.PolarizationCount(); ++i) data[i] = value.Value(i); valueColumn.put(newRow, data); } void QualityTablesFormatter::StoreFrequencyValue( double frequency, const StatisticalValue& value) { openFrequencyTable(true); const unsigned newRow = _frequencyTable->nrow(); _frequencyTable->addRow(); casacore::ScalarColumn frequencyColumn(*_frequencyTable, ColumnNameFrequency); casacore::ScalarColumn kindColumn(*_frequencyTable, ColumnNameKind); casacore::ArrayColumn valueColumn(*_frequencyTable, ColumnNameValue); frequencyColumn.put(newRow, frequency); kindColumn.put(newRow, value.KindIndex()); casacore::Vector data(value.PolarizationCount()); for (unsigned i = 0; i < value.PolarizationCount(); ++i) data[i] = value.Value(i); valueColumn.put(newRow, data); } void QualityTablesFormatter::StoreBaselineValue(unsigned antenna1, unsigned antenna2, double frequency, const StatisticalValue& value) { openBaselineTable(true); const unsigned newRow = _baselineTable->nrow(); _baselineTable->addRow(); casacore::ScalarColumn antenna1Column(*_baselineTable, ColumnNameAntenna1); casacore::ScalarColumn antenna2Column(*_baselineTable, ColumnNameAntenna2); casacore::ScalarColumn frequencyColumn(*_baselineTable, ColumnNameFrequency); casacore::ScalarColumn kindColumn(*_baselineTable, ColumnNameKind); casacore::ArrayColumn valueColumn(*_baselineTable, ColumnNameValue); antenna1Column.put(newRow, antenna1); antenna2Column.put(newRow, antenna2); frequencyColumn.put(newRow, frequency); kindColumn.put(newRow, value.KindIndex()); casacore::Vector data(value.PolarizationCount()); for (unsigned i = 0; i < value.PolarizationCount(); ++i) data[i] = value.Value(i); valueColumn.put(newRow, data); } void QualityTablesFormatter::StoreBaselineTimeValue( unsigned antenna1, unsigned antenna2, double time, double frequency, const StatisticalValue& value) { openBaselineTimeTable(true); const unsigned newRow = _baselineTimeTable->nrow(); _baselineTimeTable->addRow(); casacore::ScalarColumn timeColumn(*_baselineTimeTable, ColumnNameTime); casacore::ScalarColumn antenna1Column(*_baselineTimeTable, ColumnNameAntenna1); casacore::ScalarColumn antenna2Column(*_baselineTimeTable, ColumnNameAntenna2); casacore::ScalarColumn frequencyColumn(*_baselineTimeTable, ColumnNameFrequency); casacore::ScalarColumn kindColumn(*_baselineTimeTable, ColumnNameKind); casacore::ArrayColumn valueColumn(*_baselineTimeTable, ColumnNameValue); timeColumn.put(newRow, time); antenna1Column.put(newRow, antenna1); antenna2Column.put(newRow, antenna2); frequencyColumn.put(newRow, frequency); kindColumn.put(newRow, value.KindIndex()); casacore::Vector data(value.PolarizationCount()); for (unsigned i = 0; i < value.PolarizationCount(); ++i) data[i] = value.Value(i); valueColumn.put(newRow, data); } void QualityTablesFormatter::removeStatisticFromStatTable( enum QualityTable qualityTable, enum StatisticKind kind) { unsigned kindIndex; if (QueryKindIndex(kind, kindIndex)) { casacore::Table& table = getTable(qualityTable, true); const casacore::ScalarColumn kindColumn(table, ColumnNameKind); unsigned nrRow = table.nrow(); for (unsigned i = 0; i < nrRow; ++i) { while (i < nrRow && kindColumn(i) == (int)kindIndex) { table.removeRow(i); --nrRow; } } } } void QualityTablesFormatter::removeKindNameEntry(enum StatisticKind kind) { openKindNameTable(true); const casacore::ScalarColumn nameColumn(*_kindNameTable, ColumnNameName); const unsigned nrRow = _kindNameTable->nrow(); const casacore::String kindName(KindToName(kind)); for (unsigned i = 0; i < nrRow; ++i) { if (nameColumn(i) == kindName) { _kindNameTable->removeRow(i); break; } } } void QualityTablesFormatter::removeEntries(enum QualityTable table) { casacore::Table& casaTable = getTable(table, true); const unsigned nrRow = casaTable.nrow(); for (int i = nrRow - 1; i >= 0; --i) { casaTable.removeRow(i); } } unsigned QualityTablesFormatter::QueryStatisticEntryCount( enum StatisticDimension dimension, unsigned kindIndex) { const casacore::Table& casaTable( getTable(DimensionToTable(dimension), false)); const casacore::ROScalarColumn kindColumn(casaTable, ColumnNameKind); const unsigned nrRow = casaTable.nrow(); size_t count = 0; for (unsigned i = 0; i < nrRow; ++i) { if (kindColumn(i) == (int)kindIndex) ++count; } return count; } unsigned QualityTablesFormatter::GetPolarizationCount() { const casacore::Table& table(getTable(TimeStatisticTable, false)); const casacore::ROArrayColumn valueColumn(table, ColumnNameValue); return valueColumn.columnDesc().shape()[0]; } void QualityTablesFormatter::QueryTimeStatistic( unsigned kindIndex, std::vector>& entries) { const casacore::Table& table(getTable(TimeStatisticTable, false)); const unsigned nrRow = table.nrow(); const casacore::ROScalarColumn timeColumn(table, ColumnNameTime); const casacore::ROScalarColumn frequencyColumn(table, ColumnNameFrequency); const casacore::ROScalarColumn kindColumn(table, ColumnNameKind); const casacore::ROArrayColumn valueColumn(table, ColumnNameValue); const int polarizationCount = valueColumn.columnDesc().shape()[0]; for (unsigned i = 0; i < nrRow; ++i) { if (kindColumn(i) == (int)kindIndex) { StatisticalValue value(polarizationCount); value.SetKindIndex(kindIndex); casacore::Array valueArray = valueColumn(i); casacore::Array::iterator iter = valueArray.begin(); for (int p = 0; p < polarizationCount; ++p) { value.SetValue(p, *iter); ++iter; } TimePosition position; position.time = timeColumn(i); position.frequency = frequencyColumn(i); entries.push_back( std::pair(position, value)); } } } void QualityTablesFormatter::QueryFrequencyStatistic( unsigned kindIndex, std::vector>& entries) { const casacore::Table& table(getTable(FrequencyStatisticTable, false)); const unsigned nrRow = table.nrow(); const casacore::ROScalarColumn frequencyColumn(table, ColumnNameFrequency); const casacore::ROScalarColumn kindColumn(table, ColumnNameKind); const casacore::ROArrayColumn valueColumn(table, ColumnNameValue); const int polarizationCount = valueColumn.columnDesc().shape()[0]; for (unsigned i = 0; i < nrRow; ++i) { if (kindColumn(i) == (int)kindIndex) { StatisticalValue value(polarizationCount); value.SetKindIndex(kindIndex); casacore::Array valueArray = valueColumn(i); casacore::Array::iterator iter = valueArray.begin(); for (int p = 0; p < polarizationCount; ++p) { value.SetValue(p, *iter); ++iter; } FrequencyPosition position; position.frequency = frequencyColumn(i); entries.push_back( std::pair(position, value)); } } } void QualityTablesFormatter::QueryBaselineStatistic( unsigned kindIndex, std::vector>& entries) { const casacore::Table& table(getTable(BaselineStatisticTable, false)); const unsigned nrRow = table.nrow(); const casacore::ROScalarColumn antenna1Column(table, ColumnNameAntenna1); const casacore::ROScalarColumn antenna2Column(table, ColumnNameAntenna2); const casacore::ROScalarColumn frequencyColumn(table, ColumnNameFrequency); const casacore::ROScalarColumn kindColumn(table, ColumnNameKind); const casacore::ROArrayColumn valueColumn(table, ColumnNameValue); const int polarizationCount = valueColumn.columnDesc().shape()[0]; for (unsigned i = 0; i < nrRow; ++i) { if (kindColumn(i) == (int)kindIndex) { StatisticalValue value(polarizationCount); value.SetKindIndex(kindIndex); casacore::Array valueArray = valueColumn(i); casacore::Array::iterator iter = valueArray.begin(); for (int p = 0; p < polarizationCount; ++p) { value.SetValue(p, *iter); ++iter; } BaselinePosition position; position.antenna1 = antenna1Column(i); position.antenna2 = antenna2Column(i); position.frequency = frequencyColumn(i); entries.push_back( std::pair(position, value)); } } } void QualityTablesFormatter::openMainTable(bool needWrite) { if (_measurementSet == nullptr) { if (needWrite) _measurementSet.reset( new casacore::Table(_measurementSetName, casacore::Table::Update)); else _measurementSet.reset(new casacore::Table(_measurementSetName)); } else if (needWrite) { if (!_measurementSet->isWritable()) _measurementSet->reopenRW(); } } aoflagger-v3.4.0/quality/baselinestatisticsmap.h0000644000175000017500000001303014507760372020565 0ustar olesoles#ifndef BASELINESTATISTICSMAP_H #define BASELINESTATISTICSMAP_H #include #include #include #include "../util/serializable.h" #include "defaultstatistics.h" class BaselineStatisticsMap : public Serializable { public: explicit BaselineStatisticsMap(unsigned polarizationCount) : _polarizationCount(polarizationCount) {} void operator+=(const BaselineStatisticsMap& other) { for (OuterMap::const_iterator i = other._map.begin(); i != other._map.end(); ++i) { unsigned antenna1 = i->first; const InnerMap& innerMap = i->second; for (InnerMap::const_iterator j = innerMap.begin(); j != innerMap.end(); ++j) { unsigned antenna2 = j->first; const DefaultStatistics& stat = j->second; GetStatistics(antenna1, antenna2) += stat; } } } DefaultStatistics& GetStatistics(unsigned antenna1, unsigned antenna2) { OuterMap::iterator antenna1Map = _map.insert(OuterPair(antenna1, InnerMap())).first; InnerMap& innerMap = antenna1Map->second; InnerMap::iterator antenna2Value = innerMap.find(antenna2); DefaultStatistics* statistics; if (antenna2Value == innerMap.end()) { // The baseline does not exist yet, create empty statistics. statistics = &(innerMap .insert(InnerPair( antenna2, DefaultStatistics(_polarizationCount))) .first->second); } else { statistics = &antenna2Value->second; } return *statistics; } const DefaultStatistics& GetStatistics(unsigned antenna1, unsigned antenna2) const { OuterMap::const_iterator antenna1Map = _map.find(antenna1); if (antenna1Map == _map.end()) { throw std::runtime_error( "BaselineStatisticsMap::GetStatistics() : Requested unavailable " "baseline"); } else { const InnerMap& innerMap = antenna1Map->second; InnerMap::const_iterator antenna2Value = innerMap.find(antenna2); if (antenna2Value == innerMap.end()) { throw std::runtime_error( "BaselineStatisticsMap::GetStatistics() : Requested unavailable " "baseline"); } else { return antenna2Value->second; } } } std::vector> BaselineList() const { std::vector> list; for (OuterMap::const_iterator outerIter = _map.begin(); outerIter != _map.end(); ++outerIter) { const unsigned antenna1 = outerIter->first; const InnerMap& innerMap = outerIter->second; for (InnerMap::const_iterator innerIter = innerMap.begin(); innerIter != innerMap.end(); ++innerIter) { const unsigned antenna2 = innerIter->first; list.push_back(std::pair(antenna1, antenna2)); } } return list; } unsigned AntennaCount() const { if (_map.empty()) return 0; unsigned highestIndex = _map.rbegin()->first; for (OuterMap::const_iterator outerIter = _map.begin(); outerIter != _map.end(); ++outerIter) { const InnerMap& innerMap = outerIter->second; if (highestIndex < innerMap.rbegin()->first) highestIndex = innerMap.rbegin()->first; } return highestIndex + 1; } void Clear() { _map.clear(); } unsigned PolarizationCount() const { return _polarizationCount; } virtual void Serialize(std::ostream& stream) const final override { SerializeToUInt32(stream, _polarizationCount); serializeOuterMap(stream, _map); } virtual void Unserialize(std::istream& stream) final override { _map.clear(); _polarizationCount = UnserializeUInt32(stream); unserializeOuterMap(stream, _map); } private: typedef std::map InnerMap; typedef std::pair InnerPair; typedef std::map OuterMap; typedef std::pair OuterPair; OuterMap _map; unsigned _polarizationCount; void serializeOuterMap(std::ostream& stream, const OuterMap& map) const { SerializeToUInt32(stream, map.size()); for (OuterMap::const_iterator i = map.begin(); i != map.end(); ++i) { unsigned antenna1 = i->first; SerializeToUInt32(stream, antenna1); const InnerMap& innerMap = i->second; serializeInnerMap(stream, innerMap); } } void unserializeOuterMap(std::istream& stream, OuterMap& map) const { size_t size = UnserializeUInt32(stream); for (size_t j = 0; j < size; ++j) { unsigned antenna1 = UnserializeUInt32(stream); OuterMap::iterator i = map.insert(std::pair(antenna1, InnerMap())).first; unserializeInnerMap(stream, i->second); } } void serializeInnerMap(std::ostream& stream, const InnerMap& map) const { SerializeToUInt32(stream, map.size()); for (InnerMap::const_iterator i = map.begin(); i != map.end(); ++i) { unsigned antenna2 = i->first; SerializeToUInt32(stream, antenna2); const DefaultStatistics& statistics = i->second; statistics.Serialize(stream); } } void unserializeInnerMap(std::istream& stream, InnerMap& map) const { size_t size = UnserializeUInt32(stream); for (size_t j = 0; j < size; ++j) { unsigned antenna2 = UnserializeUInt32(stream); InnerMap::iterator i = map.insert(std::pair( antenna2, DefaultStatistics(_polarizationCount))) .first; i->second.Unserialize(stream); } } }; #endif aoflagger-v3.4.0/quality/statisticscollection.cpp0000644000175000017500000003563314507760372021010 0ustar olesoles#include "statisticscollection.h" template void StatisticsCollection::addTimeAndBaseline( unsigned antenna1, unsigned antenna2, double time, double centralFrequency, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags) { unsigned long rfiCount = 0; unsigned long count = 0; long double sum_R = 0.0, sum_I = 0.0; long double sumP2_R = 0.0, sumP2_I = 0.0; for (unsigned j = 0; j < nsamples; ++j) { if (!*origFlags) { if (std::isfinite(*reals) && std::isfinite(*imags)) { if (*isRFI) { ++rfiCount; } else { const long double rVal = *reals; const long double iVal = *imags; ++count; sum_R += rVal; sum_I += iVal; sumP2_R += rVal * rVal; sumP2_I += iVal * iVal; } } } reals += step; imags += step; isRFI += stepRFI; origFlags += stepFlags; } if (antenna1 != antenna2) { DefaultStatistics& timeStat = getTimeStatistic(time, centralFrequency); addToStatistic(timeStat, polarization, count, sum_R, sum_I, sumP2_R, sumP2_I, rfiCount); } DefaultStatistics& baselineStat = getBaselineStatistic(antenna1, antenna2, centralFrequency); addToStatistic(baselineStat, polarization, count, sum_R, sum_I, sumP2_R, sumP2_I, rfiCount); } template void StatisticsCollection::addFrequency( unsigned band, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags, bool shiftOneUp) { std::vector& bandStats = _bands.find(band)->second; const unsigned fAdd = shiftOneUp ? 1 : 0; for (unsigned j = 0; j < nsamples; ++j) { if (!*origFlags) { if (std::isfinite(*reals) && std::isfinite(*imags)) { DefaultStatistics& freqStat = *bandStats[j + fAdd]; if (*isRFI) { addToStatistic(freqStat, polarization, 0, 0.0, 0.0, 0.0, 0.0, 1); } else { const long double r = *reals, i = *imags; addToStatistic(freqStat, polarization, 1, r, i, r * r, i * i, 0); } } } isRFI += stepRFI; origFlags += stepFlags; reals += step; imags += step; } } void StatisticsCollection::Add(unsigned antenna1, unsigned antenna2, double time, unsigned band, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags) { if (nsamples == 0) return; const double centralFrequency = _centralFrequencies.find(band)->second; addTimeAndBaseline(antenna1, antenna2, time, centralFrequency, polarization, reals, imags, isRFI, origFlags, nsamples, step, stepRFI, stepFlags); if (antenna1 != antenna2) addFrequency(band, polarization, reals, imags, isRFI, origFlags, nsamples, step, stepRFI, stepFlags, false); // Allocate vector with length nsamples, so there is // a diff element, even if nsamples=1. std::vector diffReals(nsamples); std::vector diffImags(nsamples); bool* diffRFIFlags = new bool[nsamples]; bool* diffOrigFlags = new bool[nsamples]; for (unsigned i = 0; i < nsamples - 1; ++i) { diffReals[i] = (reals[(i + 1) * step] - reals[i * step]) * M_SQRT1_2; diffImags[i] = (imags[(i + 1) * step] - imags[i * step]) * M_SQRT1_2; diffRFIFlags[i] = isRFI[i * stepRFI] | isRFI[(i + 1) * stepRFI]; diffOrigFlags[i] = origFlags[i * stepFlags] | origFlags[(i + 1) * stepFlags]; } addTimeAndBaseline(antenna1, antenna2, time, centralFrequency, polarization, &(diffReals[0]), &(diffImags[0]), diffRFIFlags, diffOrigFlags, nsamples - 1, 1, 1, 1); if (antenna1 != antenna2) { addFrequency(band, polarization, &(diffReals[0]), &(diffImags[0]), diffRFIFlags, diffOrigFlags, nsamples - 1, 1, 1, 1, false); addFrequency(band, polarization, &(diffReals[0]), &(diffImags[0]), diffRFIFlags, diffOrigFlags, nsamples - 1, 1, 1, 1, true); } delete[] diffRFIFlags; delete[] diffOrigFlags; } void StatisticsCollection::AddToTimeFrequency( unsigned antenna1, unsigned antenna2, double time, unsigned band, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags) { if (nsamples == 0) return; if (antenna1 == antenna2) return; addToTimeFrequency(time, &_bandFrequencies[band][0], polarization, reals, imags, isRFI, origFlags, nsamples, step, stepRFI, stepFlags, false); // Allocate vector with length nsamples, so there is // a diff element, even if nsamples=1. std::vector diffReals(nsamples); std::vector diffImags(nsamples); bool* diffRFIFlags = new bool[nsamples]; bool* diffOrigFlags = new bool[nsamples]; for (unsigned i = 0; i < nsamples - 1; ++i) { diffReals[i] = (reals[(i + 1) * step] - reals[i * step]) * M_SQRT1_2; diffImags[i] = (imags[(i + 1) * step] - imags[i * step]) * M_SQRT1_2; diffRFIFlags[i] = isRFI[i * stepRFI] | isRFI[(i + 1) * stepRFI]; diffOrigFlags[i] = origFlags[i * stepFlags] | origFlags[(i + 1) * stepFlags]; } addToTimeFrequency(time, &_bandFrequencies[band][0], polarization, &(diffReals[0]), &(diffImags[0]), diffRFIFlags, diffOrigFlags, nsamples - 1, 1, 1, 1, false); addToTimeFrequency(time, &_bandFrequencies[band][0], polarization, &(diffReals[0]), &(diffImags[0]), diffRFIFlags, diffOrigFlags, nsamples - 1, 1, 1, 1, true); delete[] diffRFIFlags; delete[] diffOrigFlags; } void StatisticsCollection::AddImage(unsigned antenna1, unsigned antenna2, const double* times, unsigned band, int polarization, const Image2DCPtr& realImage, const Image2DCPtr& imagImage, const Mask2DCPtr& rfiMask, const Mask2DCPtr& correlatorMask) { if (realImage->Width() == 0 || realImage->Height() == 0) return; const double centralFrequency = _centralFrequencies.find(band)->second; DefaultStatistics& baselineStat = getBaselineStatistic(antenna1, antenna2, centralFrequency); std::vector& bandStats = _bands.find(band)->second; std::vector timeStats(realImage->Width()); for (size_t t = 0; t != realImage->Width(); ++t) timeStats[t] = &getTimeStatistic(times[t], centralFrequency); for (size_t f = 0; f < realImage->Height(); ++f) { DefaultStatistics& freqStat = *bandStats[f]; const bool *origFlags = correlatorMask->ValuePtr(0, f), *nextOrigFlags = origFlags + correlatorMask->Stride(), *isRFI = rfiMask->ValuePtr(0, f), *isNextRFI = isRFI + rfiMask->Stride(); const float *reals = realImage->ValuePtr(0, f), *imags = imagImage->ValuePtr(0, f), *nextReal = reals + realImage->Stride(), *nextImag = imags + imagImage->Stride(); for (size_t t = 0; t < realImage->Width(); ++t) { if (!*origFlags && std::isfinite(*reals) && std::isfinite(*imags)) { long double real = *reals, imag = *imags; if (*isRFI) { if (antenna1 != antenna2) { ++timeStats[t]->rfiCount[polarization]; ++freqStat.rfiCount[polarization]; } ++baselineStat.rfiCount[polarization]; } else { long double realSq = real * real, imagSq = imag * imag; if (antenna1 != antenna2) { addSingleNonRFISampleToStatistic(*timeStats[t], polarization, real, imag, realSq, imagSq); addSingleNonRFISampleToStatistic(freqStat, polarization, real, imag, realSq, imagSq); } addSingleNonRFISampleToStatistic(baselineStat, polarization, real, imag, realSq, imagSq); } if (f != realImage->Height() - 1) { DefaultStatistics& nextFreqStat = *bandStats[f + 1]; if (!*nextOrigFlags && std::isfinite(*nextReal) && std::isfinite(*nextImag)) { real = (*nextReal - *reals) * M_SQRT1_2; imag = (*nextImag - *imags) * M_SQRT1_2; if (!(*isRFI || *isNextRFI)) { long double realSq = real * real, imagSq = imag * imag; if (antenna1 != antenna2) { addSingleNonRFISampleToStatistic( *timeStats[t], polarization, real, imag, realSq, imagSq); addSingleNonRFISampleToStatistic( freqStat, polarization, real, imag, realSq, imagSq); addSingleNonRFISampleToStatistic( nextFreqStat, polarization, real, imag, realSq, imagSq); } addSingleNonRFISampleToStatistic( baselineStat, polarization, real, imag, realSq, imagSq); } } } } ++origFlags; ++isRFI; ++reals; ++imags; ++nextOrigFlags; ++isNextRFI; ++nextReal; ++nextImag; } } } void StatisticsCollection::lowerResolution( StatisticsCollection::DoubleStatMap& map, size_t maxSteps) const { if (map.size() > maxSteps) { DoubleStatMap newMap; double gridStep, gridStart; if (maxSteps > 1) { const double oldGridStep = (map.rbegin()->first - map.begin()->first) / (map.size() - 1); gridStep = (map.rbegin()->first - map.begin()->first + oldGridStep) / maxSteps; gridStart = map.begin()->first - 0.5 * oldGridStep; } else { gridStep = map.rbegin()->first - map.begin()->first; gridStart = map.begin()->first; } size_t gridIndex = 0; for (DoubleStatMap::iterator i = map.begin(); i != map.end();) { DefaultStatistics integratedStat(_polarizationCount); double cellMid = (gridIndex + 0.5) * gridStep + gridStart, cellEnd = (gridIndex + 1) * gridStep + gridStart; size_t count = 0; while (i != map.end() && i->first < cellEnd) { ++count; integratedStat += i->second; ++i; } ++gridIndex; // If the last items are not yet gridded, they might be just over the // border due to rounding errors; put them in the last bucket: if (gridIndex == maxSteps) { while (i != map.end()) { ++count; integratedStat += i->second; ++i; } } if (count > 0) newMap.insert( std::pair(cellMid, integratedStat)); } map = newMap; } } template void StatisticsCollection::addToTimeFrequency( double time, const double* frequencies, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags, bool shiftOneUp) { const unsigned fAdd = shiftOneUp ? 1 : 0; for (unsigned j = 0; j < nsamples; ++j) { if (!*origFlags) { if (std::isfinite(*reals) && std::isfinite(*imags)) { DefaultStatistics& timeStat = getTimeStatistic(time, frequencies[j + fAdd]); if (*isRFI) { addToStatistic(timeStat, polarization, 0, 0.0, 0.0, 0.0, 0.0, 1); } else { const long double r = *reals, i = *imags; addToStatistic(timeStat, polarization, 1, r, i, r * r, i * i, 0); } } } isRFI += stepRFI; origFlags += stepFlags; reals += step; imags += step; } } void StatisticsCollection::saveTime(QualityTablesFormatter& qd) const { initializeEmptyStatistics(qd, QualityTablesFormatter::TimeDimension); Indices indices; indices.fill(qd); StatisticSaver saver; saver.dimension = QualityTablesFormatter::TimeDimension; saver.qualityData = &qd; for (std::map::const_iterator j = _timeStatistics.begin(); j != _timeStatistics.end(); ++j) { saver.frequency = j->first; const DoubleStatMap& map = j->second; for (DoubleStatMap::const_iterator i = map.begin(); i != map.end(); ++i) { saver.time = i->first; const DefaultStatistics& stat = i->second; saveEachStatistic(saver, stat, indices); } } } void StatisticsCollection::saveFrequency(QualityTablesFormatter& qd) const { if (!_frequencyStatistics.empty()) { initializeEmptyStatistics(qd, QualityTablesFormatter::FrequencyDimension); Indices indices; indices.fill(qd); StatisticSaver saver; saver.dimension = QualityTablesFormatter::FrequencyDimension; saver.qualityData = &qd; for (DoubleStatMap::const_iterator i = _frequencyStatistics.begin(); i != _frequencyStatistics.end(); ++i) { saver.frequency = i->first; const DefaultStatistics& stat = i->second; saveEachStatistic(saver, stat, indices); } } } void StatisticsCollection::saveBaseline(QualityTablesFormatter& qd) const { if (!_baselineStatistics.empty()) { initializeEmptyStatistics(qd, QualityTablesFormatter::BaselineDimension); Indices indices; indices.fill(qd); StatisticSaver saver; saver.dimension = QualityTablesFormatter::BaselineDimension; saver.frequency = centralFrequency(); saver.qualityData = &qd; for (std::map::const_iterator j = _baselineStatistics.begin(); j != _baselineStatistics.end(); ++j) { saver.frequency = j->first; const BaselineStatisticsMap& map = j->second; const std::vector> baselines = map.BaselineList(); for (std::vector>::const_iterator i = baselines.begin(); i != baselines.end(); ++i) { saver.antenna1 = i->first; saver.antenna2 = i->second; const DefaultStatistics& stat = map.GetStatistics(saver.antenna1, saver.antenna2); saveEachStatistic(saver, stat, indices); } } } } aoflagger-v3.4.0/quality/histogramtablesformatter.h0000644000175000017500000001173514507760372021320 0ustar olesoles#ifndef HISTOGRAM_TABLES_FORMATTER_H #define HISTOGRAM_TABLES_FORMATTER_H #include #include #include #include class HistogramTablesFormatter { public: enum TableKind { HistogramCountTable, HistogramTypeTable }; struct HistogramItem { double binStart; double binEnd; double count; }; enum HistogramType { TotalHistogram, RFIHistogram }; explicit HistogramTablesFormatter(const std::string& measurementSetName) : _measurementSet(nullptr), _measurementSetName(measurementSetName), _typeTable(nullptr), _countTable(nullptr) {} ~HistogramTablesFormatter() { Close(); } void Close() { _countTable.reset(); _typeTable.reset(); closeMainTable(); } std::string CountTableName() const { return "QUALITY_HISTOGRAM_COUNT"; } std::string TypeTableName() const { return "QUALITY_HISTOGRAM_TYPE"; } std::string TableName(enum TableKind table) const { switch (table) { case HistogramCountTable: return CountTableName(); case HistogramTypeTable: return TypeTableName(); default: return ""; } } std::string TypeToName(HistogramType type) const { switch (type) { case TotalHistogram: return "Total"; case RFIHistogram: return "RFI"; default: return std::string(); } } std::string TableFilename(enum TableKind table) const { return _measurementSetName + '/' + TableName(table); } bool TableExists(enum TableKind table) const { return _measurementSet->isReadable(TableFilename(table)); } bool IsAvailable(unsigned typeIndex) { if (!TableExists(HistogramCountTable) || !TableExists(HistogramTypeTable)) return false; return hasOneEntry(typeIndex); } void InitializeEmptyTables(); void RemoveTable(enum TableKind table); void StoreValue(unsigned typeIndex, double binStart, double binEnd, double count); void QueryHistogram(unsigned typeIndex, std::vector& histogram); unsigned QueryTypeIndex(enum HistogramType type, unsigned polarizationIndex); bool QueryTypeIndex(enum HistogramType type, unsigned polarizationIndex, unsigned& destTypeIndex); unsigned StoreOrQueryTypeIndex(enum HistogramType type, unsigned polarizationIndex) { unsigned typeIndex; if (QueryTypeIndex(type, polarizationIndex, typeIndex)) return typeIndex; else return StoreType(type, polarizationIndex); } unsigned StoreType(enum HistogramType type, unsigned polarizationIndex); bool HistogramsExist() { return TableExists(HistogramCountTable) && TableExists(HistogramTypeTable); } void RemoveAll() { RemoveTable(HistogramCountTable); RemoveTable(HistogramTypeTable); } private: HistogramTablesFormatter(const HistogramTablesFormatter&) = delete; // don't allow copies void operator=(const HistogramTablesFormatter&) = delete; // don't allow assignment static const std::string ColumnNameType; static const std::string ColumnNameName; static const std::string ColumnNamePolarization; static const std::string ColumnNameBinStart; static const std::string ColumnNameBinEnd; static const std::string ColumnNameCount; std::unique_ptr _measurementSet; const std::string _measurementSetName; std::unique_ptr _typeTable; std::unique_ptr _countTable; bool hasOneEntry(unsigned typeIndex); void removeTypeEntry(enum HistogramType type, unsigned polarizationIndex); void removeEntries(enum TableKind table); void addTimeColumn(casacore::TableDesc& tableDesc); void addFrequencyColumn(casacore::TableDesc& tableDesc); void addValueColumn(casacore::TableDesc& tableDesc); void createTable(enum TableKind table) { switch (table) { case HistogramTypeTable: createTypeTable(); break; case HistogramCountTable: createCountTable(); break; default: break; } } void createTypeTable(); void createCountTable(); unsigned findFreeTypeIndex(casacore::Table& typeTable); void openMainTable(bool needWrite); void closeMainTable() { _measurementSet.reset(); } void openTable(TableKind table, bool needWrite, std::unique_ptr& tablePtr); void openTypeTable(bool needWrite) { openTable(HistogramTypeTable, needWrite, _typeTable); } void openCountTable(bool needWrite) { openTable(HistogramCountTable, needWrite, _countTable); } casacore::Table& getTable(TableKind table, bool needWrite) { std::unique_ptr* tablePtr = nullptr; switch (table) { case HistogramTypeTable: tablePtr = &_typeTable; break; case HistogramCountTable: tablePtr = &_countTable; break; } assert(tablePtr); openTable(table, needWrite, *tablePtr); return **tablePtr; } }; #endif aoflagger-v3.4.0/quality/defaultstatistics.h0000644000175000017500000001434714507760372017745 0ustar olesoles#ifndef QUALITY__DEFAULT_STATISTICS_H #define QUALITY__DEFAULT_STATISTICS_H #include #include #include "../util/serializable.h" class DefaultStatistics : public Serializable { public: explicit DefaultStatistics(unsigned polarizationCount) : _polarizationCount(polarizationCount) { initialize(); for (unsigned p = 0; p < _polarizationCount; ++p) { rfiCount[p] = 0; count[p] = 0; sum[p] = 0.0; sumP2[p] = 0.0; dCount[p] = 0; dSum[p] = 0.0; dSumP2[p] = 0.0; } } ~DefaultStatistics() { destruct(); } DefaultStatistics(const DefaultStatistics& other) : _polarizationCount(other._polarizationCount) { initialize(); for (unsigned p = 0; p < _polarizationCount; ++p) { rfiCount[p] = other.rfiCount[p]; count[p] = other.count[p]; sum[p] = other.sum[p]; sumP2[p] = other.sumP2[p]; dCount[p] = other.dCount[p]; dSum[p] = other.dSum[p]; dSumP2[p] = other.dSumP2[p]; } } DefaultStatistics& operator=(const DefaultStatistics& other) { if (other._polarizationCount != _polarizationCount) { destruct(); _polarizationCount = other._polarizationCount; initialize(); } for (unsigned p = 0; p < _polarizationCount; ++p) { rfiCount[p] = other.rfiCount[p]; count[p] = other.count[p]; sum[p] = other.sum[p]; sumP2[p] = other.sumP2[p]; dCount[p] = other.dCount[p]; dSum[p] = other.dSum[p]; dSumP2[p] = other.dSumP2[p]; } return *this; } DefaultStatistics& operator+=(const DefaultStatistics& other) { for (unsigned p = 0; p < _polarizationCount; ++p) { rfiCount[p] += other.rfiCount[p]; count[p] += other.count[p]; sum[p] += other.sum[p]; sumP2[p] += other.sumP2[p]; dCount[p] += other.dCount[p]; dSum[p] += other.dSum[p]; dSumP2[p] += other.dSumP2[p]; } return *this; } bool operator==(const DefaultStatistics& rhs) const { if (_polarizationCount != rhs._polarizationCount) return false; for (unsigned p = 0; p < _polarizationCount; ++p) { if (rfiCount[p] != rhs.rfiCount[p]) return false; if (count[p] != rhs.count[p]) return false; if (sum[p] != rhs.sum[p]) return false; if (sumP2[p] != rhs.sumP2[p]) return false; if (dCount[p] != rhs.dCount[p]) return false; if (dSum[p] != rhs.dSum[p]) return false; if (dSumP2[p] != rhs.dSumP2[p]) return false; } return true; } bool operator!=(const DefaultStatistics& rhs) const { return !(*this == rhs); } DefaultStatistics ToSinglePolarization() const { if (_polarizationCount == 1) return *this; DefaultStatistics singlePol(1); for (unsigned p = 0; p < _polarizationCount; ++p) { singlePol.rfiCount[0] += rfiCount[p]; singlePol.count[0] += count[p]; singlePol.sum[0] += sum[p]; singlePol.sumP2[0] += sumP2[p]; singlePol.dCount[0] += dCount[p]; singlePol.dSum[0] += dSum[p]; singlePol.dSumP2[0] += dSumP2[p]; } return singlePol; } virtual void Serialize(std::ostream& stream) const final override { SerializeToUInt32(stream, _polarizationCount); for (unsigned p = 0; p < _polarizationCount; ++p) { SerializeToUInt64(stream, rfiCount[p]); SerializeToUInt64(stream, count[p]); SerializeToLDoubleC(stream, sum[p]); SerializeToLDoubleC(stream, sumP2[p]); SerializeToUInt64(stream, dCount[p]); SerializeToLDoubleC(stream, dSum[p]); SerializeToLDoubleC(stream, dSumP2[p]); } } virtual void Unserialize(std::istream& stream) final override { uint32_t pCount = UnserializeUInt32(stream); if (pCount != _polarizationCount) { destruct(); _polarizationCount = pCount; initialize(); } for (unsigned p = 0; p < _polarizationCount; ++p) { rfiCount[p] = UnserializeUInt64(stream); count[p] = UnserializeUInt64(stream); sum[p] = UnserializeLDoubleC(stream); sumP2[p] = UnserializeLDoubleC(stream); dCount[p] = UnserializeUInt64(stream); dSum[p] = UnserializeLDoubleC(stream); dSumP2[p] = UnserializeLDoubleC(stream); } } unsigned PolarizationCount() const { return _polarizationCount; } template std::complex Mean(unsigned polarization) const { return std::complex(sum[polarization].real() / count[polarization], sum[polarization].imag() / count[polarization]); } template std::complex Sum(unsigned polarization) const { return std::complex(sum[polarization].real(), sum[polarization].imag()); } template std::complex SumP2(unsigned polarization) const { return std::complex(sumP2[polarization].real(), sumP2[polarization].imag()); } template std::complex DMean(unsigned polarization) const { return std::complex(dSum[polarization].real() / dCount[polarization], dSum[polarization].imag() / dCount[polarization]); } template std::complex DSum(unsigned polarization) const { return std::complex(dSum[polarization].real(), dSum[polarization].imag()); } template std::complex DSumP2(unsigned polarization) const { return std::complex(dSumP2[polarization].real(), dSumP2[polarization].imag()); } unsigned long* rfiCount; unsigned long* count; std::complex* sum; std::complex* sumP2; unsigned long* dCount; std::complex* dSum; std::complex* dSumP2; private: void initialize() { rfiCount = new unsigned long[_polarizationCount]; count = new unsigned long[_polarizationCount]; sum = new std::complex[_polarizationCount]; sumP2 = new std::complex[_polarizationCount]; dCount = new unsigned long[_polarizationCount]; dSum = new std::complex[_polarizationCount]; dSumP2 = new std::complex[_polarizationCount]; } void destruct() { delete[] rfiCount; delete[] count; delete[] sum; delete[] sumP2; delete[] dCount; delete[] dSum; delete[] dSumP2; } unsigned _polarizationCount; }; #endif aoflagger-v3.4.0/quality/rayleighfitter.cpp0000644000175000017500000001532614507760372017561 0ustar olesoles#include "rayleighfitter.h" #include #include #include #ifdef HAVE_GSL #include #include #include static int fit_f(const gsl_vector* xvec, void* data, gsl_vector* f) { const double sigma = gsl_vector_get(xvec, 0); const double n = gsl_vector_get(xvec, 1); size_t t = 0; const RayleighFitter& fitter = *static_cast(data); const LogHistogram& hist = *fitter._hist; const double minVal = fitter._minVal; const double maxVal = fitter._maxVal; for (LogHistogram::const_iterator i = hist.begin(); i != hist.end(); ++i) { const double x = i.value(); if (x >= minVal && x < maxVal && std::isfinite(x)) { const double val = i.normalizedCount(); // const double logval = log(val); // const double weight = logval; const double sigmaP2 = sigma * sigma; const double Yi = x * exp(-(x * x) / (2 * sigmaP2)) * n / sigmaP2; if (fitter.FitLogarithmic()) gsl_vector_set(f, t, log(Yi) - log(val)); else gsl_vector_set(f, t, (Yi - val)); ++t; } } return GSL_SUCCESS; } int fit_df(const gsl_vector* xvec, void* data, gsl_matrix* J) { const double sigma = gsl_vector_get(xvec, 0); const double n = gsl_vector_get(xvec, 1); size_t t = 0; const RayleighFitter& fitter = *static_cast(data); const LogHistogram& hist = *fitter._hist; const double minVal = fitter._minVal; const double maxVal = fitter._maxVal; const double sigmaP2 = sigma * sigma; const double sigmaP3 = sigma * sigma * sigma; for (LogHistogram::const_iterator i = hist.begin(); i != hist.end(); ++i) { const double x = i.value(); if (x >= minVal && x < maxVal && std::isfinite(x)) { // const double val = i.normalizedCount(); // const double weight = log(val); double dfdsigma, dfdn; if (fitter.FitLogarithmic()) { dfdsigma = (x * x - 2.0 * sigmaP2) / sigmaP3; dfdn = 1.0 / n; } else { dfdsigma = -n * 2.0 * x * x * x / (sigmaP3 * sigmaP3) * exp(-x * x / (2.0 * sigmaP2)); dfdn = x * exp(-(x * x) / (2 * sigmaP2)) / sigmaP2; } // diff to sigma gsl_matrix_set(J, t, 0, dfdsigma); // diff to n gsl_matrix_set(J, t, 1, dfdn); ++t; } } return GSL_SUCCESS; } int fit_fdf(const gsl_vector* x, void* data, gsl_vector* f, gsl_matrix* J) { fit_f(x, data, f); fit_df(x, data, J); return GSL_SUCCESS; } void print_state(size_t iter, gsl_multifit_fdfsolver* s) { const double sigma = gsl_vector_get(s->x, 0); const double N = gsl_vector_get(s->x, 1); std::cout << "iteration " << iter << ", sigma=" << sigma << ", N=" << N << "\n"; } void RayleighFitter::Fit(double minVal, double maxVal, const LogHistogram& hist, double& sigma, double& n) { unsigned int iter = 0; const size_t nVars = 2; _hist = &hist; if (minVal > 0) _minVal = minVal; else _minVal = hist.MinPositiveAmplitude(); _maxVal = maxVal; if (sigma < minVal) sigma = minVal; size_t nData = 0; for (LogHistogram::iterator i = hist.begin(); i != hist.end(); ++i) { const double val = i.value(); if (val >= minVal && val < maxVal && std::isfinite(val)) ++nData; } std::cout << "ndata=" << nData << "\n"; double x_init[nVars] = {sigma, n}; const gsl_vector_view x = gsl_vector_view_array(x_init, nVars); gsl_multifit_function_fdf f; f.f = &fit_f; f.df = &fit_df; f.fdf = &fit_fdf; f.n = nData; f.p = nVars; f.params = this; const gsl_multifit_fdfsolver_type* T = gsl_multifit_fdfsolver_lmsder; gsl_multifit_fdfsolver* s = gsl_multifit_fdfsolver_alloc(T, nData, nVars); gsl_multifit_fdfsolver_set(s, &f, &x.vector); print_state(iter, s); int status; do { iter++; status = gsl_multifit_fdfsolver_iterate(s); std::cout << "status = " << gsl_strerror(status) << "\n"; print_state(iter, s); if (status) break; status = gsl_multifit_test_delta(s->dx, s->x, 1e-7, 1e-3); } while (status == GSL_CONTINUE && iter < 500); std::cout << "status = " << gsl_strerror(status) << "\n"; print_state(iter, s); sigma = fabs(gsl_vector_get(s->x, 0)); n = fabs(gsl_vector_get(s->x, 1)); gsl_multifit_fdfsolver_free(s); } #else // No gsl... void RayleighFitter::Fit(double minVal, double maxVal, const LogHistogram& hist, double& sigma, double& n) { sigma = 1.0; n = 1.0; } #endif double RayleighFitter::SigmaEstimate(const LogHistogram& hist) { return hist.AmplitudeWithMaxNormalizedCount(); } double RayleighFitter::SigmaEstimate(const LogHistogram& hist, double rangeStart, double rangeEnd) { double maxAmplitude = 0.0, maxNormalizedCount = boost::numeric::bounds::lowest(); for (LogHistogram::const_iterator i = hist.begin(); i != hist.end(); ++i) { if (i.value() > rangeStart && i.value() < rangeEnd && std::isfinite(i.value())) { if (std::isfinite(i.normalizedCount())) { if (i.normalizedCount() > maxNormalizedCount) { maxAmplitude = i.value(); maxNormalizedCount = i.normalizedCount(); } } } } return maxAmplitude; } void RayleighFitter::FindFitRangeUnderRFIContamination( double minPositiveAmplitude, double sigmaEstimate, double& minValue, double& maxValue) { minValue = minPositiveAmplitude; maxValue = sigmaEstimate * 1.5; std::cout << "Found range " << minValue << " -- " << maxValue << "\n"; } double RayleighFitter::ErrorOfFit(const LogHistogram& histogram, double rangeStart, double rangeEnd, double sigma, double n) { double sum = 0.0; size_t count = 0; for (LogHistogram::const_iterator i = histogram.begin(); i != histogram.end(); ++i) { const double x = i.value(); if (x >= rangeStart && x < rangeEnd && std::isfinite(x)) { const double val = i.normalizedCount(); const double sigmaP2 = sigma * sigma; const double Yi = x * exp(-(x * x) / (2 * sigmaP2)) * n / sigmaP2; const double error = (Yi - val) * (Yi - val); sum += error; ++count; } } return sum / (double)count; } double RayleighFitter::NEstimate(const LogHistogram& hist, double rangeStart, double rangeEnd) { double rangeSum = 0.0; size_t count = 0; for (LogHistogram::const_iterator i = hist.begin(); i != hist.end(); ++i) { if (i.value() > rangeStart && i.value() < rangeEnd && std::isfinite(i.value())) { if (std::isfinite(i.normalizedCount())) { rangeSum += i.normalizedCount(); ++count; } } } return rangeSum / (count * 10.0); } aoflagger-v3.4.0/quality/collector.h0000644000175000017500000000360214507760372016164 0ustar olesoles#ifndef COLLECTOR_H #define COLLECTOR_H #include #include #include #include #include #include #include class HistogramCollection; class StatisticsCollection; class ProgressListener; class Collector { public: enum CollectingMode { CollectDefault, CollectHistograms, CollectTimeFrequency }; Collector(); ~Collector(); void Collect(const std::string& filename, StatisticsCollection& statisticsCollection, HistogramCollection& histogramCollection, ProgressListener& progressListener); void SetMode(CollectingMode mode) { _mode = mode; } void SetDataColumn(const std::string& dataColumnName) { _dataColumnName = dataColumnName; } void SetFlaggedTimesteps(size_t flaggedTimesteps) { _flaggedTimesteps = flaggedTimesteps; } void SetInterval(size_t start, size_t end) { _intervalStart = start; _intervalEnd = end; } void SetFlaggedAntennae(std::set&& flaggedAntennae) { _flaggedAntennae = flaggedAntennae; } private: struct Work { std::vector>> samples; std::vector> isRFI; size_t antenna1Index, antenna2Index, bandIndex, timestepIndex, nChan; double time; bool hasFlaggedAntenna; }; void process(aocommon::Lane* workLane, StatisticsCollection* stats, size_t polarizationCount); std::mutex _mutex; CollectingMode _mode; std::string _dataColumnName; size_t _intervalStart, _intervalEnd; size_t _flaggedTimesteps; std::set _flaggedAntennae; aocommon::UVector _correlatorFlags; aocommon::UVector _correlatorFlagsForBadAntenna; StatisticsCollection* _statisticsCollection; HistogramCollection* _histogramCollection; std::vector _threadStats; }; #endif aoflagger-v3.4.0/quality/histogramcollection.h0000644000175000017500000002516014507760372020252 0ustar olesoles#ifndef HISTOGRAM_COLLECTION_H #define HISTOGRAM_COLLECTION_H #include "loghistogram.h" #include #include #include #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../util/serializable.h" class HistogramCollection : public Serializable { public: typedef std::pair AntennaPair; HistogramCollection() : _polarizationCount(0), _totalHistograms(nullptr), _rfiHistograms(nullptr) {} explicit HistogramCollection(unsigned polarizationCount) : _polarizationCount(polarizationCount) { init(); } HistogramCollection(const HistogramCollection& source) : _polarizationCount(source._polarizationCount) { init(); for (unsigned i = 0; i < _polarizationCount; ++i) { copy(_totalHistograms[i], source._totalHistograms[i]); copy(_rfiHistograms[i], source._rfiHistograms[i]); } } ~HistogramCollection() { destruct(); } void SetPolarizationCount(unsigned polarizationCount) { destruct(); _polarizationCount = polarizationCount; init(); } void Add(const unsigned antenna1, const unsigned antenna2, const unsigned polarization, const std::complex* values, const bool* isRFI, size_t sampleCount) { LogHistogram& totalHistogram = GetTotalHistogram(antenna1, antenna2, polarization); LogHistogram& rfiHistogram = GetRFIHistogram(antenna1, antenna2, polarization); for (size_t i = 0; i < sampleCount; ++i) { const double amplitude = sqrt(values[i].real() * values[i].real() + values[i].imag() * values[i].imag()); totalHistogram.Add(amplitude); if (isRFI[i]) rfiHistogram.Add(amplitude); } } void Add(const HistogramCollection& collection) { if (collection._polarizationCount != _polarizationCount) throw std::runtime_error( "Polarization counts of histogram collections don't match"); for (unsigned p = 0; p < _polarizationCount; ++p) { add(collection, p, p); } } bool Empty() const { if (_polarizationCount == 0) return true; for (unsigned p = 0; p != _polarizationCount; ++p) { if (!_totalHistograms[p].empty() || !_rfiHistograms[p].empty()) return false; } return true; } void Add(const unsigned antenna1, const unsigned antenna2, const unsigned polarization, Image2DCPtr image, Mask2DCPtr mask); void Add(const unsigned antenna1, const unsigned antenna2, const unsigned polarization, Image2DCPtr image, Mask2DCPtr flagMask, Mask2DCPtr correlatorMask); void Add(const unsigned antenna1, const unsigned antenna2, const unsigned polarization, Image2DCPtr real, Image2DCPtr imaginary, Mask2DCPtr flagMask, Mask2DCPtr correlatorMask); LogHistogram& GetTotalHistogram(const unsigned a1, const unsigned a2, const unsigned polarization) { return getHistogram(_totalHistograms, a1, a2, polarization); } LogHistogram& GetRFIHistogram(const unsigned a1, const unsigned a2, const unsigned polarization) { return getHistogram(_rfiHistograms, a1, a2, polarization); } const std::map& GetTotalHistogram( const unsigned polarization) const { return _totalHistograms[polarization]; } const std::map& GetRFIHistogram( const unsigned polarization) const { return _rfiHistograms[polarization]; } void GetTotalHistogramForCrossCorrelations(const unsigned polarization, LogHistogram& target) const { getHistogramForCrossCorrelations(_totalHistograms, polarization, target); } void GetRFIHistogramForCrossCorrelations(const unsigned polarization, LogHistogram& target) const { getHistogramForCrossCorrelations(_rfiHistograms, polarization, target); } void Clear() { destruct(); init(); } void Save(class HistogramTablesFormatter& histogramTables); void Load(class HistogramTablesFormatter& histogramTables); unsigned PolarizationCount() const { return _polarizationCount; } virtual void Serialize(std::ostream& stream) const final override { SerializeToUInt64(stream, _polarizationCount); serializeMapArray(stream, _totalHistograms); serializeMapArray(stream, _rfiHistograms); } virtual void Unserialize(std::istream& stream) final override { destruct(); _polarizationCount = UnserializeUInt64(stream); init(); unserializeMapArray(stream, _totalHistograms); unserializeMapArray(stream, _rfiHistograms); } HistogramCollection* CreateSummedPolarizationCollection() const { HistogramCollection* newCollection = new HistogramCollection(1); for (unsigned p = 0; p < _polarizationCount; ++p) newCollection->add(*this, p, 0); return newCollection; } void Rescale(double factor) { for (unsigned p = 0; p < _polarizationCount; ++p) { for (std::map::iterator i = _totalHistograms[p].begin(); i != _totalHistograms[p].end(); ++i) { i->second->Rescale(factor); } for (std::map::iterator i = _rfiHistograms[p].begin(); i != _rfiHistograms[p].end(); ++i) { i->second->Rescale(factor); } } } void CreateMissingBins() { for (unsigned p = 0; p < _polarizationCount; ++p) { for (std::map::iterator i = _totalHistograms[p].begin(); i != _totalHistograms[p].end(); ++i) { i->second->CreateMissingBins(); } for (std::map::iterator i = _rfiHistograms[p].begin(); i != _rfiHistograms[p].end(); ++i) { i->second->CreateMissingBins(); } } } private: unsigned _polarizationCount; std::map* _totalHistograms; std::map* _rfiHistograms; void init() { if (_polarizationCount != 0) { _totalHistograms = new std::map[_polarizationCount]; _rfiHistograms = new std::map[_polarizationCount]; } else { _totalHistograms = nullptr; _rfiHistograms = nullptr; } } void destruct() { if (_polarizationCount != 0) { for (unsigned p = 0; p < _polarizationCount; ++p) { for (std::map::iterator i = _totalHistograms[p].begin(); i != _totalHistograms[p].end(); ++i) { delete i->second; } for (std::map::iterator i = _rfiHistograms[p].begin(); i != _rfiHistograms[p].end(); ++i) { delete i->second; } } delete[] _totalHistograms; delete[] _rfiHistograms; } } void serializeMapArray( std::ostream& stream, const std::map* map) const { for (unsigned p = 0; p < _polarizationCount; ++p) serializeMap(stream, map[p]); } void unserializeMapArray(std::istream& stream, std::map* map) { for (unsigned p = 0; p < _polarizationCount; ++p) unserializeMap(stream, map[p]); } void serializeMap(std::ostream& stream, const std::map& map) const { SerializeToUInt64(stream, map.size()); for (std::map::const_iterator i = map.begin(); i != map.end(); ++i) { const AntennaPair& antennae = i->first; const LogHistogram* histogram = i->second; SerializeToUInt32(stream, antennae.first); SerializeToUInt32(stream, antennae.second); histogram->Serialize(stream); } } void unserializeMap(std::istream& stream, std::map& map) { map.clear(); size_t mapSize = UnserializeUInt64(stream); std::map::iterator insertPos = map.begin(); for (size_t i = 0; i != mapSize; ++i) { std::pair p; p.first.first = UnserializeUInt32(stream); p.first.second = UnserializeUInt32(stream); p.second = new LogHistogram(); p.second->Unserialize(stream); insertPos = map.insert(insertPos, p); } } void copy(std::map& destination, const std::map& source) { for (std::map::const_iterator i = source.begin(); i != source.end(); ++i) { destination.insert(std::pair( i->first, new LogHistogram(*i->second))); } } void add(const HistogramCollection& collection, unsigned fromPolarization, unsigned toPolarization) { for (std::map::const_iterator i = collection._totalHistograms[fromPolarization].begin(); i != collection._totalHistograms[fromPolarization].end(); ++i) { LogHistogram& histogram = GetTotalHistogram(i->first.first, i->first.second, toPolarization); histogram.Add(*i->second); } for (std::map::const_iterator i = collection._rfiHistograms[fromPolarization].begin(); i != collection._rfiHistograms[fromPolarization].end(); ++i) { LogHistogram& histogram = GetRFIHistogram(i->first.first, i->first.second, toPolarization); histogram.Add(*i->second); } } LogHistogram& getHistogram(std::map* histograms, const unsigned a1, const unsigned a2, const unsigned polarization) { const AntennaPair antennae(a1, a2); std::map::iterator i = histograms[polarization].find(antennae); if (i == histograms[polarization].end()) { i = histograms[polarization] .insert(std::pair(antennae, new LogHistogram())) .first; } return *i->second; } void getHistogramForCrossCorrelations( std::map* histograms, const unsigned polarization, LogHistogram& target) const { for (std::map::const_iterator i = histograms[polarization].begin(); i != histograms[polarization].end(); ++i) { if (i->first.first != i->first.second) target.Add(*i->second); } } }; #endif aoflagger-v3.4.0/quality/statisticscollection.h0000644000175000017500000010401214507760372020441 0ustar olesoles#ifndef STATISTICS_COLLECTION_H #define STATISTICS_COLLECTION_H #include #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../util/serializable.h" #include "baselinestatisticsmap.h" #include "defaultstatistics.h" #include "qualitytablesformatter.h" #include "statisticalvalue.h" #include class StatisticsCollection : public Serializable { private: typedef std::map DoubleStatMap; public: StatisticsCollection() : _polarizationCount(0), _emptyBaselineStatisticsMap(0) {} explicit StatisticsCollection(unsigned polarizationCount) : _polarizationCount(polarizationCount), _emptyBaselineStatisticsMap(polarizationCount) {} StatisticsCollection(const StatisticsCollection& source) : _timeStatistics(source._timeStatistics), _frequencyStatistics(source._frequencyStatistics), _baselineStatistics(source._baselineStatistics), _polarizationCount(source._polarizationCount), _emptyBaselineStatisticsMap(source._polarizationCount) {} StatisticsCollection& operator=(const StatisticsCollection& source) { _timeStatistics = source._timeStatistics; _frequencyStatistics = source._frequencyStatistics; _baselineStatistics = source._baselineStatistics; _polarizationCount = source._polarizationCount; _emptyBaselineStatisticsMap = source._emptyBaselineStatisticsMap; return *this; } void Clear() { _timeStatistics.clear(); _frequencyStatistics.clear(); _baselineStatistics.clear(); } bool HasBand(unsigned band) const { return _bands.find(band) != _bands.end(); } void InitializeBand(unsigned band, const double* frequencies, unsigned channelCount) { std::vector pointers; for (unsigned i = 0; i < channelCount; ++i) { pointers.emplace_back(&getFrequencyStatistic(frequencies[i])); } _bands.emplace(band, pointers); double centralFrequency = (frequencies[0] + frequencies[channelCount - 1]) / 2.0; _centralFrequencies.emplace(band, centralFrequency); _bandFrequencies.emplace( band, std::vector(frequencies, frequencies + channelCount)); } void Add(unsigned antenna1, unsigned antenna2, double time, unsigned band, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags); void Add(unsigned antenna1, unsigned antenna2, double time, unsigned band, int polarization, const std::vector>& samples, const bool* isRFI) { const float* dataPtr = reinterpret_cast(&(samples[0])); bool origFlag = false; Add(antenna1, antenna2, time, band, polarization, dataPtr, dataPtr + 1, // real and imag parts isRFI, &origFlag, samples.size(), 2, 1, 0); } void AddToTimeFrequency(unsigned antenna1, unsigned antenna2, double time, unsigned band, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags); void AddImage(unsigned antenna1, unsigned antenna2, const double* times, unsigned band, int polarization, const Image2DCPtr& realImage, const Image2DCPtr& imagImage, const Mask2DCPtr& rfiMask, const Mask2DCPtr& correlatorMask); void Save(QualityTablesFormatter& qualityData) const { saveTime(qualityData); saveFrequency(qualityData); saveBaseline(qualityData); } void Load(QualityTablesFormatter& qualityData) { SetPolarizationCount(qualityData.GetPolarizationCount()); loadTime(qualityData); loadFrequency(qualityData); loadBaseline(qualityData); } void LoadTimeStatisticsOnly(QualityTablesFormatter& qualityData) { loadTime(qualityData); } void Add(QualityTablesFormatter& qualityData) { loadTime(qualityData); loadFrequency(qualityData); loadBaseline(qualityData); } void Add(const StatisticsCollection& collection) { addTime(collection); addFrequency(collection); addBaseline(collection); } void GetGlobalTimeStatistics(DefaultStatistics& statistics) const { statistics = getGlobalStatistics(_timeStatistics); } void GetGlobalFrequencyStatistics(DefaultStatistics& statistics) const { statistics = getGlobalStatistics(_frequencyStatistics); } void GetGlobalAutoBaselineStatistics(DefaultStatistics& statistics) const { statistics = getGlobalBaselineStatistics(); } void GetGlobalCrossBaselineStatistics(DefaultStatistics& statistics) const { statistics = getGlobalBaselineStatistics(); } void GetFrequencyRangeStatistics(DefaultStatistics& statistics, double startFrequency, double endFrequency) const { statistics = getFrequencyRangeStatistics(startFrequency, endFrequency); } const BaselineStatisticsMap& BaselineStatistics() const { if (_baselineStatistics.size() == 1) return _baselineStatistics.begin()->second; else if (_baselineStatistics.size() == 0) return _emptyBaselineStatisticsMap; else throw std::runtime_error( "Requesting single band single baseline statistics in statistics " "collection with multiple bands"); } const std::map& TimeStatistics() const { if (_timeStatistics.size() == 1) return _timeStatistics.begin()->second; else throw std::runtime_error( "Requesting single band single timestep statistics in statistics " "collection with multiple bands"); } const std::map>& AllTimeStatistics() const { return _timeStatistics; } const std::map& FrequencyStatistics() const { return _frequencyStatistics; } std::map GetAntennaStatistics() const { const BaselineStatisticsMap& map = BaselineStatistics(); std::vector> baselines = map.BaselineList(); std::map antStatistics; for (const std::pair& p : baselines) { if (p.first != p.second) { const DefaultStatistics& stats = map.GetStatistics(p.first, p.second); addAntennaStatistic(p.first, stats, antStatistics); addAntennaStatistic(p.second, stats, antStatistics); } } return antStatistics; } unsigned PolarizationCount() const { return _polarizationCount; } void SetPolarizationCount(unsigned newCount) { if (newCount != _polarizationCount) { _polarizationCount = newCount; _emptyBaselineStatisticsMap = BaselineStatisticsMap(_polarizationCount); _timeStatistics.clear(); _frequencyStatistics.clear(); _baselineStatistics.clear(); } } virtual void Serialize(std::ostream& stream) const final override { SerializeToUInt64(stream, _polarizationCount); serializeTime(stream); serializeFrequency(stream); serializeBaselines(stream); } virtual void Unserialize(std::istream& stream) final override { _polarizationCount = UnserializeUInt64(stream); _emptyBaselineStatisticsMap = BaselineStatisticsMap(_polarizationCount); unserializeTime(stream); unserializeFrequency(stream); unserializeBaselines(stream); } void IntegrateBaselinesToOneChannel() { const size_t size = _baselineStatistics.size(); if (size > 1) { BaselineStatisticsMap fullMap(_polarizationCount); double frequencySum = 0.0; for (std::map::const_iterator i = _baselineStatistics.begin(); i != _baselineStatistics.end(); ++i) { frequencySum += i->first; fullMap += i->second; } _baselineStatistics.clear(); _baselineStatistics.insert(std::pair( frequencySum / size, fullMap)); } } void IntegrateTimeToOneChannel() { const size_t size = _timeStatistics.size(); if (size > 1) { DoubleStatMap fullMap; double frequencySum = 0.0; for (std::map::const_iterator i = _timeStatistics.begin(); i != _timeStatistics.end(); ++i) { frequencySum += i->first; addToDoubleStatMap(fullMap, i->second); } _timeStatistics.clear(); _timeStatistics.insert( std::pair(frequencySum / size, fullMap)); } } void LowerTimeResolution(size_t maxSteps) { for (std::map::iterator i = _timeStatistics.begin(); i != _timeStatistics.end(); ++i) { lowerResolution(i->second, maxSteps); } } void LowerFrequencyResolution(size_t maxSteps) { lowerResolution(_frequencyStatistics, maxSteps); } /** * The regrid method will force all channels(/sub-bands) inside the collection * to have the same uniform grid. It will do this by moving around time steps, * using the first grid as reference. This is useful for raw (not NDPPP-ed) * data, that might contain slightly different time steps in the different * sub-bands, but are otherwise similarly gridded. */ void RegridTime() { if (_timeStatistics.size() > 1) { std::map::iterator i = _timeStatistics.begin(); const DoubleStatMap& referenceMap = i->second; ++i; do { regrid(referenceMap, i->second); ++i; } while (i != _timeStatistics.end()); } } private: struct StatisticSaver { QualityTablesFormatter::StatisticDimension dimension; double time; double frequency; unsigned antenna1; unsigned antenna2; QualityTablesFormatter* qualityData; void Save(StatisticalValue& value, unsigned kindIndex) { value.SetKindIndex(kindIndex); switch (dimension) { case QualityTablesFormatter::TimeDimension: qualityData->StoreTimeValue(time, frequency, value); break; case QualityTablesFormatter::FrequencyDimension: qualityData->StoreFrequencyValue(frequency, value); break; case QualityTablesFormatter::BaselineDimension: qualityData->StoreBaselineValue(antenna1, antenna2, frequency, value); break; case QualityTablesFormatter::BaselineTimeDimension: qualityData->StoreBaselineTimeValue(antenna1, antenna2, time, frequency, value); break; } } }; struct Indices { unsigned kindRFICount; unsigned kindCount; unsigned kindSum; unsigned kindSumP2; unsigned kindDCount; unsigned kindDSum; unsigned kindDSumP2; void fill(QualityTablesFormatter& qd) { kindRFICount = qd.StoreOrQueryKindIndex(QualityTablesFormatter::RFICountStatistic), kindCount = qd.StoreOrQueryKindIndex(QualityTablesFormatter::CountStatistic), kindSum = qd.StoreOrQueryKindIndex(QualityTablesFormatter::SumStatistic), kindSumP2 = qd.StoreOrQueryKindIndex(QualityTablesFormatter::SumP2Statistic), kindDCount = qd.StoreOrQueryKindIndex(QualityTablesFormatter::DCountStatistic), kindDSum = qd.StoreOrQueryKindIndex(QualityTablesFormatter::DSumStatistic), kindDSumP2 = qd.StoreOrQueryKindIndex(QualityTablesFormatter::DSumP2Statistic); } }; template void addTimeAndBaseline(unsigned antenna1, unsigned antenna2, double time, double centralFrequency, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags); template void addToTimeFrequency(double time, const double* frequencies, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags, bool shiftOneUp); template void addToStatistic(DefaultStatistics& statistic, unsigned polarization, unsigned long count, long double sum_R, long double sum_I, long double sumP2_R, long double sumP2_I, unsigned long rfiCount) { if (IsDiff) { statistic.dCount[polarization] += count; statistic.dSum[polarization] += std::complex(sum_R, sum_I); statistic.dSumP2[polarization] += std::complex(sumP2_R, sumP2_I); } else { statistic.count[polarization] += count; statistic.sum[polarization] += std::complex(sum_R, sum_I); statistic.sumP2[polarization] += std::complex(sumP2_R, sumP2_I); statistic.rfiCount[polarization] += rfiCount; } } template void addSingleNonRFISampleToStatistic(DefaultStatistics& statistic, unsigned polarization, long double sum_R, long double sum_I, long double sumP2_R, long double sumP2_I) { if (IsDiff) { ++statistic.dCount[polarization]; statistic.dSum[polarization] += std::complex(sum_R, sum_I); statistic.dSumP2[polarization] += std::complex(sumP2_R, sumP2_I); } else { ++statistic.count[polarization]; statistic.sum[polarization] += std::complex(sum_R, sum_I); statistic.sumP2[polarization] += std::complex(sumP2_R, sumP2_I); } } template void addFrequency(unsigned band, int polarization, const float* reals, const float* imags, const bool* isRFI, const bool* origFlags, unsigned nsamples, unsigned step, unsigned stepRFI, unsigned stepFlags, bool shiftOneUp); void initializeEmptyStatistics( QualityTablesFormatter& qualityData, QualityTablesFormatter::StatisticDimension dimension) const { qualityData.InitializeEmptyStatistic( dimension, QualityTablesFormatter::RFICountStatistic, _polarizationCount); qualityData.InitializeEmptyStatistic( dimension, QualityTablesFormatter::CountStatistic, _polarizationCount); qualityData.InitializeEmptyStatistic( dimension, QualityTablesFormatter::SumStatistic, _polarizationCount); qualityData.InitializeEmptyStatistic( dimension, QualityTablesFormatter::SumP2Statistic, _polarizationCount); qualityData.InitializeEmptyStatistic( dimension, QualityTablesFormatter::DCountStatistic, _polarizationCount); qualityData.InitializeEmptyStatistic( dimension, QualityTablesFormatter::DSumStatistic, _polarizationCount); qualityData.InitializeEmptyStatistic( dimension, QualityTablesFormatter::DSumP2Statistic, _polarizationCount); } void saveEachStatistic(StatisticSaver& saver, const DefaultStatistics& stat, const Indices& indices) const { StatisticalValue value(_polarizationCount); for (unsigned p = 0; p < _polarizationCount; ++p) value.SetValue(p, std::complex(stat.rfiCount[p], 0.0f)); saver.Save(value, indices.kindRFICount); for (unsigned p = 0; p < _polarizationCount; ++p) value.SetValue(p, std::complex(stat.count[p], 0.0f)); saver.Save(value, indices.kindCount); for (unsigned p = 0; p < _polarizationCount; ++p) value.SetValue(p, stat.Sum(p)); saver.Save(value, indices.kindSum); for (unsigned p = 0; p < _polarizationCount; ++p) value.SetValue(p, stat.SumP2(p)); saver.Save(value, indices.kindSumP2); for (unsigned p = 0; p < _polarizationCount; ++p) value.SetValue(p, std::complex(stat.dCount[p], 0.0f)); saver.Save(value, indices.kindDCount); for (unsigned p = 0; p < _polarizationCount; ++p) value.SetValue(p, stat.DSum(p)); saver.Save(value, indices.kindDSum); for (unsigned p = 0; p < _polarizationCount; ++p) value.SetValue(p, stat.DSumP2(p)); saver.Save(value, indices.kindDSumP2); } void saveTime(QualityTablesFormatter& qd) const; void saveFrequency(QualityTablesFormatter& qd) const; void saveBaseline(QualityTablesFormatter& qd) const; DefaultStatistics& getTimeStatistic(double time, double centralFrequency) { // We use find() to see if the value exists, and only use insert() when it // does not, because insert is slow (because a "Statistic" needs to be // created). Holds for both frequency and time maps. std::map::iterator i = _timeStatistics.find(centralFrequency); if (i == _timeStatistics.end()) { i = _timeStatistics .insert(std::pair(centralFrequency, DoubleStatMap())) .first; } DoubleStatMap& selectedTimeStatistic = i->second; return getDoubleStatMapStatistic(selectedTimeStatistic, time); } DefaultStatistics& getFrequencyStatistic(double frequency) { return getDoubleStatMapStatistic(_frequencyStatistics, frequency); } DefaultStatistics& getDoubleStatMapStatistic(DoubleStatMap& map, double key) { // Use insert() only when not exist, as it is slower then find because a // Statistic is created. DoubleStatMap::iterator i = map.find(key); if (i == map.end()) { i = map.insert(std::pair( key, DefaultStatistics(_polarizationCount))) .first; } return i->second; } DefaultStatistics& getBaselineStatistic(unsigned antenna1, unsigned antenna2, double centralFrequency) { std::map::iterator i = _baselineStatistics.find(centralFrequency); if (i == _baselineStatistics.end()) { i = _baselineStatistics .insert(std::pair( centralFrequency, BaselineStatisticsMap(_polarizationCount))) .first; } BaselineStatisticsMap& selectedBaselineStatistic = i->second; return selectedBaselineStatistic.GetStatistics(antenna1, antenna2); } template void assignOrAdd(T& value, const T otherValue) { if (PerformAdd) value += otherValue; else value = otherValue; } template void assignStatistic(DefaultStatistics& destination, const StatisticalValue& source, QualityTablesFormatter::StatisticKind kind) { for (unsigned p = 0; p < _polarizationCount; ++p) { switch (kind) { case QualityTablesFormatter::RFICountStatistic: assignOrAdd(destination.rfiCount[p], (long unsigned)source.Value(p).real()); break; case QualityTablesFormatter::CountStatistic: assignOrAdd(destination.count[p], (long unsigned)source.Value(p).real()); break; case QualityTablesFormatter::SumStatistic: assignOrAdd( destination.sum[p], std::complex(source.Value(p).real(), source.Value(p).imag())); break; case QualityTablesFormatter::SumP2Statistic: assignOrAdd( destination.sumP2[p], std::complex(source.Value(p).real(), source.Value(p).imag())); break; case QualityTablesFormatter::DCountStatistic: assignOrAdd(destination.dCount[p], (long unsigned)source.Value(p).real()); break; case QualityTablesFormatter::DSumStatistic: assignOrAdd( destination.dSum[p], std::complex(source.Value(p).real(), source.Value(p).imag())); break; case QualityTablesFormatter::DSumP2Statistic: assignOrAdd( destination.dSumP2[p], std::complex(source.Value(p).real(), source.Value(p).imag())); break; default: break; } } } void forEachDefaultStatistic(QualityTablesFormatter& qd, void (StatisticsCollection::*functionName)( QualityTablesFormatter&, QualityTablesFormatter::StatisticKind)) { (this->*functionName)(qd, QualityTablesFormatter::CountStatistic); (this->*functionName)(qd, QualityTablesFormatter::SumStatistic); (this->*functionName)(qd, QualityTablesFormatter::SumP2Statistic); (this->*functionName)(qd, QualityTablesFormatter::DCountStatistic); (this->*functionName)(qd, QualityTablesFormatter::DSumStatistic); (this->*functionName)(qd, QualityTablesFormatter::DSumP2Statistic); (this->*functionName)(qd, QualityTablesFormatter::RFICountStatistic); } template void loadSingleTimeStatistic(QualityTablesFormatter& qd, QualityTablesFormatter::StatisticKind kind) { std::vector< std::pair> values; unsigned kindIndex = qd.QueryKindIndex(kind); qd.QueryTimeStatistic(kindIndex, values); for (std::vector>::const_iterator i = values.begin(); i != values.end(); ++i) { const QualityTablesFormatter::TimePosition& position = i->first; const StatisticalValue& statValue = i->second; DefaultStatistics& stat = getTimeStatistic(position.time, position.frequency); assignStatistic(stat, statValue, kind); } } template void loadTime(QualityTablesFormatter& qd) { forEachDefaultStatistic( qd, &StatisticsCollection::loadSingleTimeStatistic); } template void loadSingleFrequencyStatistic( QualityTablesFormatter& qd, QualityTablesFormatter::StatisticKind kind) { std::vector< std::pair> values; unsigned kindIndex = qd.QueryKindIndex(kind); qd.QueryFrequencyStatistic(kindIndex, values); for (std::vector>::const_iterator i = values.begin(); i != values.end(); ++i) { const QualityTablesFormatter::FrequencyPosition& position = i->first; const StatisticalValue& statValue = i->second; DefaultStatistics& stat = getFrequencyStatistic(position.frequency); assignStatistic(stat, statValue, kind); } } template void loadFrequency(QualityTablesFormatter& qd) { forEachDefaultStatistic( qd, &StatisticsCollection::loadSingleFrequencyStatistic); } template void loadSingleBaselineStatistic(QualityTablesFormatter& qd, QualityTablesFormatter::StatisticKind kind) { std::vector< std::pair> values; unsigned kindIndex = qd.QueryKindIndex(kind); qd.QueryBaselineStatistic(kindIndex, values); for (std::vector>::const_iterator i = values.begin(); i != values.end(); ++i) { const QualityTablesFormatter::BaselinePosition& position = i->first; const StatisticalValue& statValue = i->second; DefaultStatistics& stat = getBaselineStatistic( position.antenna1, position.antenna2, position.frequency); assignStatistic(stat, statValue, kind); } } template void loadBaseline(QualityTablesFormatter& qd) { forEachDefaultStatistic( qd, &StatisticsCollection::loadSingleBaselineStatistic); } double centralFrequency() const { double min = _frequencyStatistics.begin()->first; double max = _frequencyStatistics.rbegin()->first; return (min + max) / 2.0; } DefaultStatistics getGlobalStatistics(const DoubleStatMap& statMap) const { DefaultStatistics global(_polarizationCount); for (DoubleStatMap::const_iterator i = statMap.begin(); i != statMap.end(); ++i) { const DefaultStatistics& stat = i->second; global += stat; } return global; } DefaultStatistics getGlobalStatistics( const std::map& statMap) const { DefaultStatistics global(_polarizationCount); for (std::map::const_iterator i = statMap.begin(); i != statMap.end(); ++i) { const DefaultStatistics& stat = getGlobalStatistics(i->second); global += stat; } return global; } template DefaultStatistics getGlobalBaselineStatistics() const { DefaultStatistics global(_polarizationCount); for (std::map::const_iterator f = _baselineStatistics.begin(); f != _baselineStatistics.end(); ++f) { const BaselineStatisticsMap& map = f->second; const std::vector> baselines = map.BaselineList(); for (std::vector>::const_iterator i = baselines.begin(); i != baselines.end(); ++i) { const unsigned antenna1 = i->first, antenna2 = i->second; if (((antenna1 == antenna2) && AutoCorrelations) || ((antenna1 != antenna2) && (!AutoCorrelations))) { const DefaultStatistics& stat = map.GetStatistics(antenna1, antenna2); global += stat; } } } return global; } DefaultStatistics getFrequencyRangeStatistics(double startFrequency, double endFrequency) const { DefaultStatistics rangeStats(_polarizationCount); for (DoubleStatMap::const_iterator f = _frequencyStatistics.begin(); f != _frequencyStatistics.end(); ++f) { const double frequency = f->first; const DefaultStatistics& stat = f->second; if (frequency >= startFrequency && frequency < endFrequency) rangeStats += stat; } return rangeStats; } void serializeTime(std::ostream& stream) const { SerializeToUInt64(stream, _timeStatistics.size()); for (std::map::const_iterator i = _timeStatistics.begin(); i != _timeStatistics.end(); ++i) { const double frequency = i->first; const DoubleStatMap& map = i->second; SerializeToDouble(stream, frequency); serializeDoubleStatMap(stream, map); } } void unserializeTime(std::istream& stream) { _timeStatistics.clear(); size_t count = (size_t)UnserializeUInt64(stream); std::map::iterator insertPos = _timeStatistics.begin(); for (size_t i = 0; i < count; ++i) { double frequency = UnserializeDouble(stream); insertPos = _timeStatistics.insert( insertPos, std::pair(frequency, DoubleStatMap())); unserializeDoubleStatMap(stream, insertPos->second); } } void serializeFrequency(std::ostream& stream) const { serializeDoubleStatMap(stream, _frequencyStatistics); } void unserializeFrequency(std::istream& stream) { _frequencyStatistics.clear(); unserializeDoubleStatMap(stream, _frequencyStatistics); } void serializeBaselines(std::ostream& stream) const { SerializeToUInt64(stream, _baselineStatistics.size()); for (std::map::const_iterator i = _baselineStatistics.begin(); i != _baselineStatistics.end(); ++i) { const double frequency = i->first; const BaselineStatisticsMap& map = i->second; SerializeToDouble(stream, frequency); map.Serialize(stream); } } void unserializeBaselines(std::istream& stream) { _baselineStatistics.clear(); size_t count = (size_t)UnserializeUInt64(stream); std::map::iterator insertPos = _baselineStatistics.begin(); for (size_t i = 0; i < count; ++i) { double frequency = UnserializeDouble(stream); insertPos = _baselineStatistics.insert( insertPos, std::pair( frequency, BaselineStatisticsMap(_polarizationCount))); insertPos->second.Unserialize(stream); } } void serializeDoubleStatMap(std::ostream& stream, const DoubleStatMap& statMap) const { uint64_t statCount = statMap.size(); stream.write(reinterpret_cast(&statCount), sizeof(statCount)); for (DoubleStatMap::const_iterator i = statMap.begin(); i != statMap.end(); ++i) { const double& key = i->first; const DefaultStatistics& stat = i->second; stream.write(reinterpret_cast(&key), sizeof(key)); stat.Serialize(stream); } } void unserializeDoubleStatMap(std::istream& stream, DoubleStatMap& statMap) const { size_t count = (size_t)UnserializeUInt64(stream); std::map::iterator insertPos = statMap.begin(); for (size_t i = 0; i < count; ++i) { double key = UnserializeDouble(stream); insertPos = statMap.insert( insertPos, std::pair( key, DefaultStatistics(_polarizationCount))); insertPos->second.Unserialize(stream); } } void addTime(const StatisticsCollection& collection) { for (std::map::const_iterator i = collection._timeStatistics.begin(); i != collection._timeStatistics.end(); ++i) { const double frequency = i->first; const DoubleStatMap& map = i->second; for (DoubleStatMap::const_iterator j = map.begin(); j != map.end(); ++j) { const double time = j->first; const DefaultStatistics& stat = j->second; getTimeStatistic(time, frequency) += stat; } } } void addFrequency(const StatisticsCollection& collection) { for (DoubleStatMap::const_iterator j = collection._frequencyStatistics.begin(); j != collection._frequencyStatistics.end(); ++j) { const double frequency = j->first; const DefaultStatistics& stat = j->second; getFrequencyStatistic(frequency) += stat; } } void addBaseline(const StatisticsCollection& collection) { for (std::map::const_iterator i = collection._baselineStatistics.begin(); i != collection._baselineStatistics.end(); ++i) { const double frequency = i->first; const BaselineStatisticsMap& map = i->second; std::vector> baselines = map.BaselineList(); for (std::vector>::const_iterator j = baselines.begin(); j != baselines.end(); ++j) { const unsigned antenna1 = j->first; const unsigned antenna2 = j->second; const DefaultStatistics& stat = map.GetStatistics(antenna1, antenna2); getBaselineStatistic(antenna1, antenna2, frequency) += stat; } } } void addToDoubleStatMap(DoubleStatMap& dest, const DoubleStatMap& source) { for (DoubleStatMap::const_iterator i = source.begin(); i != source.end(); ++i) { double key = i->first; const DefaultStatistics& sourceStats = i->second; getDoubleStatMapStatistic(dest, key) += sourceStats; } } void lowerResolution(DoubleStatMap& map, size_t maxSteps) const; static void regrid(const DoubleStatMap& referenceMap, DoubleStatMap& regridMap) { DoubleStatMap newMap; for (DoubleStatMap::const_iterator i = regridMap.begin(); i != regridMap.end(); ++i) { double key = i->first; // find the key in the reference map that is closest to this key, if it is // within range DoubleStatMap::const_iterator bound = referenceMap.lower_bound(key); if (bound != referenceMap.end()) { double rightKey = bound->first; if (bound != referenceMap.begin()) { --bound; double leftKey = bound->first; if (key - rightKey < leftKey - key) key = rightKey; else key = leftKey; } } newMap.insert(std::pair(key, i->second)); } regridMap = newMap; } static void addAntennaStatistic( unsigned antIndex, const DefaultStatistics& stats, std::map& antStatistics) { std::map::iterator iter = antStatistics.find(antIndex); if (iter == antStatistics.end()) antStatistics.insert(std::make_pair(antIndex, stats)); else iter->second += stats; } std::map _timeStatistics; DoubleStatMap _frequencyStatistics; std::map _baselineStatistics; std::map> _bands; std::map _centralFrequencies; std::map> _bandFrequencies; unsigned _polarizationCount; BaselineStatisticsMap _emptyBaselineStatisticsMap; }; #endif aoflagger-v3.4.0/rfigui/0000755000175000017500000000000014516225226013613 5ustar olesolesaoflagger-v3.4.0/rfigui/histogramwindow.h0000644000175000017500000000127314507760372017222 0ustar olesoles#ifndef GUI___HISTOGRAMWINDOW_H #define GUI___HISTOGRAMWINDOW_H #include "../aoqplot/histogrampage.h" #include "../aoqplot/controllers/histogrampagecontroller.h" #include #include "../quality/histogramcollection.h" class HistogramWindow : public Gtk::Window { public: explicit HistogramWindow(const HistogramCollection& histograms) : _histogramPage(&_controller) { _controller.SetHistograms(&histograms); add(_histogramPage); _histogramPage.show(); } void SetStatistics(const HistogramCollection& histograms) { _controller.SetHistograms(&histograms); } private: HistogramPageController _controller; HistogramPage _histogramPage; }; #endif aoflagger-v3.4.0/rfigui/simulatedialog.cpp0000644000175000017500000001146214507760372017334 0ustar olesoles#include "simulatedialog.h" #include "../algorithms/testsetgenerator.h" using algorithms::BackgroundTestSet; using algorithms::RFITestSet; using algorithms::TestSetGenerator; SimulateDialog::SimulateDialog() : _nTimesLabel("Number of timesteps:"), _nChannelsLabel("Number of channels:"), _bandwidthLabel("Bandwidth (MHz):"), _polarizationsLabel("Polarizations:"), _targetLabel("Target:"), _noiseLabel("Noise:"), _noiseLevelLabel("Noise level:"), _rfiLabel("RFI:") { _grid.attach(_nTimesLabel, 1, 0, 1, 1); _nTimesEntry.set_text("1000"); _grid.attach(_nTimesEntry, 2, 0, 1, 1); _grid.attach(_nChannelsLabel, 1, 1, 1, 1); _nChannelsEntry.set_text("512"); _grid.attach(_nChannelsEntry, 2, 1, 1, 1); _grid.attach(_bandwidthLabel, 1, 2, 1, 1); _bandwidthEntry.set_text("32"); _grid.attach(_bandwidthEntry, 2, 2, 1, 1); _grid.attach(_polarizationsLabel, 0, 3, 1, 1); _polarizationsSelection.append("Stokes I"); _polarizationsSelection.append("XX, YY"); _polarizationsSelection.append("XX, XY, YX, YY"); _polarizationsSelection.set_active(0); _grid.attach(_polarizationsSelection, 1, 3, 2, 1); _grid.attach(_targetLabel, 0, 4, 1, 1); _targetSelection.append("Current"); for (BackgroundTestSet bSet = algorithms::BackgroundTestSetFirst(); bSet != algorithms::BackgroundTestSetLast(); ++bSet) { _targetSelection.append(TestSetGenerator::GetDescription(bSet)); } _targetSelection.append( TestSetGenerator::GetDescription(algorithms::BackgroundTestSetLast())); _targetSelection.set_active(1); _grid.attach(_targetSelection, 1, 4, 2, 1); _grid.attach(_noiseLabel, 0, 5, 1, 1); _noiseSelection.append("None"); _noiseSelection.append("Complex Gaussian noise"); _noiseSelection.append("Rayleigh noise"); _noiseSelection.set_active(1); _grid.attach(_noiseSelection, 1, 5, 2, 1); _grid.attach(_noiseLevelLabel, 1, 6, 1, 1); _noiseLevelEntry.set_text("1"); _grid.attach(_noiseLevelEntry, 2, 6, 1, 1); _grid.attach(_rfiLabel, 0, 7, 1, 1); for (RFITestSet rSet = algorithms::RFITestSetFirst(); rSet != algorithms::RFITestSetLast(); ++rSet) { _rfiSelection.append(TestSetGenerator::GetDescription(rSet)); } _rfiSelection.append( TestSetGenerator::GetDescription(algorithms::RFITestSetLast())); _rfiSelection.set_active(0); _grid.attach(_rfiSelection, 1, 7, 2, 1); get_content_area()->add(_grid); _grid.show_all(); add_button("Cancel", Gtk::RESPONSE_CANCEL); _simulateButton = add_button("Simulate", Gtk::RESPONSE_OK); } TimeFrequencyData SimulateDialog::Make() const { const size_t width = atoi(_nTimesEntry.get_text().c_str()); const size_t height = atoi(_nChannelsEntry.get_text().c_str()); const double noiseLevel = atof(_noiseLevelEntry.get_text().c_str()); BackgroundTestSet backgroundSet = BackgroundTestSet::Empty; const bool replaceBackground = _targetSelection.get_active_row_number() != 0; if (replaceBackground) backgroundSet = BackgroundTestSet(_targetSelection.get_active_row_number() - 1); const RFITestSet rfiSet = RFITestSet(_rfiSelection.get_active_row_number()); TimeFrequencyData data; const bool isComplex = _noiseSelection.get_active_row_number() != 2; const bool addNoise = _noiseSelection.get_active_row_number() != 0; std::vector polarizations; if (_polarizationsSelection.get_active_row_number() == 0) polarizations = {aocommon::Polarization::StokesI}; else if (_polarizationsSelection.get_active_row_number() == 1) polarizations = {aocommon::Polarization::XX, aocommon::Polarization::YY}; else polarizations = {aocommon::Polarization::XX, aocommon::Polarization::XY, aocommon::Polarization::YX, aocommon::Polarization::YY}; for (const aocommon::PolarizationEnum pol : polarizations) { if (isComplex) { if (addNoise) { const Image2DPtr real = Image2D::MakePtr( TestSetGenerator::MakeNoise(width, height, noiseLevel)); const Image2DPtr imag = Image2D::MakePtr( TestSetGenerator::MakeNoise(width, height, noiseLevel)); data = TimeFrequencyData::MakeFromPolarizationCombination( data, TimeFrequencyData(pol, real, imag)); } else { const Image2DPtr zero = Image2D::CreateZeroImagePtr(width, height); data = TimeFrequencyData::MakeFromPolarizationCombination( data, TimeFrequencyData(pol, zero, zero)); } } else { const Image2DPtr amp = Image2D::MakePtr(TestSetGenerator::MakeRayleighData(width, height)); data = TimeFrequencyData::MakeFromPolarizationCombination( data, TimeFrequencyData(TimeFrequencyData::AmplitudePart, pol, amp)); } } if (replaceBackground) TestSetGenerator::MakeBackground(backgroundSet, data); TestSetGenerator::MakeTestSet(rfiSet, data); return data; } aoflagger-v3.4.0/rfigui/plotframe.cpp0000644000175000017500000000372614507760372016326 0ustar olesoles#include #include "../plot/xyplot.h" #include "plotframe.h" using aocommon::Polarization; PlotFrame::PlotFrame() : _plotData(nullptr), _selectedXStart(0), _selectedYStart(0), _selectedXEnd(0), _selectedYEnd(0) { pack_start(_plot); _plot.show(); } PlotFrame::~PlotFrame() { delete _plotData; } void PlotFrame::plot() { _plot.Clear(); if (_plotData != nullptr) delete _plotData; _plotData = new XYPlot(); bool drawn = false; if (_data.HasXX()) { plotTimeGraph(_data, "XX", Polarization::XX); drawn = true; } if (_data.HasXY()) { plotTimeGraph(_data, "XY", Polarization::XY); drawn = true; } if (_data.HasYX()) { plotTimeGraph(_data, "YX", Polarization::YX); drawn = true; } if (_data.HasYY()) { plotTimeGraph(_data, "YY", Polarization::YY); drawn = true; } if (_data.PolarizationCount() > 0 && _data.GetPolarization(0) == Polarization::StokesI) { plotTimeGraph(_data, "Stokes I"); } else if (!drawn) { plotTimeGraph(_data, "Data"); } _plot.SetPlot(*_plotData); } void PlotFrame::plotTimeGraph(const TimeFrequencyData& data, const std::string& label, aocommon::PolarizationEnum polarisation) { plotTimeGraph(data.Make(polarisation), label); } void PlotFrame::plotTimeGraph(const TimeFrequencyData& data, const std::string& label) { _plotData->StartLine(label); const Image2DCPtr image = data.GetSingleImage(); const Mask2DCPtr mask = data.GetSingleMask(); for (size_t x = 0; x < image->Width(); ++x) { size_t count = 0; num_t value = 0.0; for (size_t y = _selectedYStart; y < _selectedYEnd; ++y) { if (!mask->Value(x, y)) { ++count; value += image->Value(x, y); } } if (count > 0) _plotData->PushDataPoint(x, value / (num_t)count); else _plotData->PushDataPoint(x, std::numeric_limits::quiet_NaN()); } } aoflagger-v3.4.0/rfigui/interfaces.h0000644000175000017500000000107514507760372016120 0ustar olesoles#ifndef GUI_INTERFACES_H #define GUI_INTERFACES_H #include #include namespace imagesets { class Strategy; } class StrategyController { public: virtual ~StrategyController() = default; virtual void SetStrategy(std::unique_ptr strategy) = 0; virtual imagesets::Strategy& Strategy() = 0; virtual void NotifyChange() { _signalOnStrategyChanged(); } virtual sigc::signal SignalOnStrategyChanged() { return _signalOnStrategyChanged; } private: sigc::signal _signalOnStrategyChanged; }; #endif aoflagger-v3.4.0/rfigui/progresswindow.cpp0000644000175000017500000001235314507760372017425 0ustar olesoles#include "progresswindow.h" #include #include #include ProgressWindow::ProgressWindow() : _blockProgressSignal(false), _currentTaskTitleLabel("Current task:"), _currentTaskLabel("-"), _timeElapsedTitleLabel("Time elapsed:"), _timeElapsedLabel("-"), _timeEstimatedTitleLabel("Estimated time:"), _timeEstimatedLabel("-"), _started(false), _exceptionQueued(false), _progress(0), _maxProgress(0), _finished(false) { set_default_size(350, 60); _currentTaskTitleLabel.set_vexpand(true); _currentTaskTitleLabel.set_alignment(Gtk::ALIGN_END); _currentTaskTitleLabel.set_padding(10, 2); _grid.attach(_currentTaskTitleLabel, 0, 0, 1, 1); _currentTaskLabel.set_alignment(Gtk::ALIGN_START); _grid.attach(_currentTaskLabel, 1, 0, 1, 1); _timeElapsedTitleLabel.set_vexpand(true); _timeElapsedTitleLabel.set_alignment(Gtk::ALIGN_END); _timeElapsedTitleLabel.set_padding(10, 2); _grid.attach(_timeElapsedTitleLabel, 0, 1, 1, 1); _timeElapsedLabel.set_alignment(Gtk::ALIGN_START); _grid.attach(_timeElapsedLabel, 1, 1, 1, 1); _timeEstimatedTitleLabel.set_vexpand(true); _timeEstimatedTitleLabel.set_alignment(Gtk::ALIGN_END); _timeEstimatedTitleLabel.set_padding(10, 2); _grid.attach(_timeEstimatedTitleLabel, 0, 2, 1, 1); _timeEstimatedLabel.set_alignment(Gtk::ALIGN_START); _grid.attach(_timeEstimatedLabel, 1, 2, 1, 1); _progressBar.set_hexpand(true); _progressBar.set_vexpand(true); _grid.attach(_progressBar, 0, 3, 2, 1); add(_grid); _grid.show_all(); _progressChangeSignal.connect( sigc::mem_fun(*this, &ProgressWindow::updateProgress)); } ProgressWindow::~ProgressWindow() = default; void ProgressWindow::updateProgress() { if (!_blockProgressSignal) { if (!_started) { _startTime = boost::posix_time::microsec_clock::local_time(); _lastUpdate = _startTime - boost::posix_time::time_duration(0, 0, 1); _started = true; } std::unique_lock lock(_mutex); const boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time(); const boost::posix_time::time_duration sinceLast = now - _lastUpdate; const boost::posix_time::time_duration updTime = boost::posix_time::millisec(100); const bool doUpdate = sinceLast >= updTime; if (doUpdate) { _lastUpdate = now; const boost::posix_time::time_duration duration = now - _startTime; std::stringstream timeStr; timeStr << duration; _timeElapsedLabel.set_text(timeStr.str()); const std::string taskDesc = _taskDescription; const double progress = std::min( 1.0, std::max(0.0, double(_progress) / double(_maxProgress))); _currentTaskLabel.set_text(taskDesc); _progressBar.set_fraction(progress); if (progress > 0.0) { std::stringstream estimatedTimeStr; boost::posix_time::time_duration estimated = (boost::posix_time::microsec_clock::local_time() - _startTime) * (int)(1000000.0 * (1.0 - progress)) / (int)(1000000.0 * progress); estimated = boost::posix_time::seconds(estimated.total_seconds()); estimatedTimeStr << estimated; _timeEstimatedLabel.set_text(estimatedTimeStr.str()); } } const bool hasException = _exceptionQueued; if (hasException) { _exceptionQueued = false; _blockProgressSignal = true; if (_signalError.empty()) { // Default handler: show a message dialog const std::string errMsg = std::string("An exception was thrown of type '") + _exceptionType + ("' -- ") + _exceptionDescription; lock.unlock(); Gtk::MessageDialog dialog(*this, errMsg, false, Gtk::MESSAGE_ERROR); dialog.run(); } else { const std::string errDescr = _exceptionDescription; // local copy to unlock mutex lock.unlock(); _signalError(errDescr); } _signalFinished(false); lock.lock(); _blockProgressSignal = false; } else if (_finished) { _finished = false; // Reset in case window is reused lock.unlock(); _currentTaskLabel.set_text("-"); _timeEstimatedLabel.set_text("-"); _progressBar.set_fraction(1.0); // Parent might delete this window in this call -- don't do anything // after. _signalFinished(true); } } } void ProgressWindow::OnStartTask(const std::string& description) { std::unique_lock lock(_mutex); _taskDescription = description; lock.unlock(); _progressChangeSignal(); } void ProgressWindow::OnFinish() { std::unique_lock lock(_mutex); _finished = true; lock.unlock(); _progressChangeSignal(); } void ProgressWindow::OnProgress(size_t progress, size_t maxProgress) { std::unique_lock lock(_mutex); _progress = progress; _maxProgress = maxProgress; lock.unlock(); _progressChangeSignal(); } void ProgressWindow::OnException(std::exception& thrownException) { std::unique_lock lock(_mutex); _exceptionQueued = true; _exceptionDescription = thrownException.what(); _exceptionType = typeid(thrownException).name(); lock.unlock(); _progressChangeSignal(); } aoflagger-v3.4.0/rfigui/gotowindow.h0000644000175000017500000000413314507760372016173 0ustar olesoles#ifndef GOTOWINDOW_H #define GOTOWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include "../imagesets/indexableset.h" class GoToWindow : public Gtk::Window { public: explicit GoToWindow(class RFIGuiWindow& rfiGuiWindow); ~GoToWindow(); private: void onLoadClicked(); void onChange(); std::optional getIndex(); Gtk::ButtonBox _buttonBox; Gtk::VBox _vBox; Gtk::HBox _hBox, _hBottomBox; Gtk::VBox _bandFrameBox; Gtk::Frame _antenna1Frame, _antenna2Frame, _bandFrame, _sequenceFrame; Gtk::TreeView _antenna1View, _antenna2View, _bandView, _sequenceView; Gtk::ScrolledWindow _antenna1Scroll, _antenna2Scroll, _bandScroll, _sequenceScroll; Gtk::Label _label; Gtk::Button _loadButton; Gtk::CheckButton _keepOpenCB; class AntennaModelColumns : public Gtk::TreeModelColumnRecord { public: AntennaModelColumns() { add(antennaIndex); add(antennaName); } Gtk::TreeModelColumn antennaIndex; Gtk::TreeModelColumn antennaName; }; class BandModelColumns : public Gtk::TreeModelColumnRecord { public: BandModelColumns() { add(bandIndex); add(bandDescription); } Gtk::TreeModelColumn bandIndex; Gtk::TreeModelColumn bandDescription; }; class SequenceModelColumns : public Gtk::TreeModelColumnRecord { public: SequenceModelColumns() { add(sequenceIndex); add(sequenceDescription); } Gtk::TreeModelColumn sequenceIndex; Gtk::TreeModelColumn sequenceDescription; }; AntennaModelColumns _antennaModelColumns; BandModelColumns _bandModelColumns; SequenceModelColumns _sequenceModelColumns; Glib::RefPtr _antennaeStore, _bandStore, _sequenceStore; RFIGuiWindow& _rfiGuiWindow; imagesets::IndexableSet* _imageSet; }; #endif aoflagger-v3.4.0/rfigui/rfiguiwindow.cpp0000644000175000017500000014020114507760372017040 0ustar olesoles#include "rfiguiwindow.h" #include #include #include #include #include #include "../msio/baselinematrixloader.h" #include "../structures/image2d.h" #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "../structures/segmentedimage.h" #include "../lua/telescopefile.h" #include "../imagesets/msimageset.h" #include "../algorithms/baselineselector.h" #include "../algorithms/morphology.h" #include "../algorithms/fringetestcreater.h" #include "../algorithms/polarizationstatistics.h" #include "../algorithms/resampling.h" #include "../algorithms/thresholdtools.h" #include "../algorithms/timefrequencystatistics.h" #include "controllers/imagecomparisoncontroller.h" #include "controllers/rfiguicontroller.h" #include "gotowindow.h" #include "histogramwindow.h" #include "imagepropertieswindow.h" #include "numinputdialog.h" #include "opendialog.h" #include "plotwindow.h" #include "progresswindow.h" #include "rfiguimenu.h" #include "simulatedialog.h" #include "../imaging/model.h" #include "../imaging/observatorium.h" #include "../quality/histogramcollection.h" #include #include using algorithms::FringeTestCreater; using algorithms::Morphology; using algorithms::ThresholdConfig; using algorithms::ThresholdTools; using algorithms::TimeFrequencyStatistics; RFIGuiWindow::RFIGuiWindow(RFIGuiController* controller, const std::string& argv0) : _controller(controller), _mainVBox(Gtk::ORIENTATION_VERTICAL), _timeFrequencyWidget(_controller->TFController().Plot()), _plotWindow(new PlotWindow(_controller->PlotManager())), _menu() { _controller->AttachWindow(this); const Glib::RefPtr iconTheme = Gtk::IconTheme::get_default(); const std::filesystem::path argv0Root = std::filesystem::path(argv0).remove_filename(); if (!std::filesystem::equivalent( argv0Root / "..", std::filesystem::path(AOFLAGGER_INSTALL_PATH))) { const std::filesystem::path iconPathC = std::filesystem::path(AOFLAGGER_INSTALL_PATH) / "share/icons"; iconTheme->prepend_search_path(iconPathC.string()); } const std::filesystem::path iconPathA = argv0Root / "../share/icons"; iconTheme->prepend_search_path(iconPathA.string()); const std::filesystem::path iconPathB = argv0Root / "../data/icons"; iconTheme->prepend_search_path(iconPathB.string()); // Now that the icon search path is correct, the menu can be created _menu.reset(new RFIGuiMenu()); set_default_size(800, 600); set_default_icon_name("aoflagger"); _menu->SetOriginalFlagsActive(_controller->AreOriginalFlagsShown()); _menu->SetAlternativeFlagsActive(_controller->AreAlternativeFlagsShown()); // File _menu->OnOpen.connect([&]() { onOpen(); }); _menu->OnSaveBaselineFlags.connect([&]() { onSaveBaselineFlags(); }); _menu->OnClose.connect([&]() { onClose(); }); _menu->OnExportBaseline.connect([&]() { onExportBaseline(); }); _menu->OnQuit.connect([&]() { onQuit(); }); _menu->OnAbout.connect([&]() { onHelpAbout(); }); _menu->OnOpenRecent.connect([&](size_t index) { onOpenRecent(index); }); // View _menu->OnViewData.connect([&]() { onViewData(); }); _menu->OnViewStrategy.connect([&]() { onViewStrategy(); }); _menu->OnViewTimePlot.connect([&]() { onViewTimePlot(); }); _menu->OnImagePropertiesPressed.connect( [&]() { onImagePropertiesPressed(); }); _menu->OnToggleFlags.connect([&]() { onToggleFlags(); }); _menu->OnZoomFit.connect([&]() { onZoomFit(); }); _menu->OnZoomIn.connect([&]() { onZoomIn(); }); _menu->OnZoomOut.connect([&]() { onZoomOut(); }); _menu->OnZoomSelect.connect([&]() { onZoomSelect(); }); _menu->OnShowStats.connect([&]() { onShowStats(); }); // Strategy _menu->OnExecuteLuaStrategy.connect([&]() { onExecuteLuaStrategy(); }); _menu->OnExecutePythonStrategy.connect([&]() { onExecutePythonStrategy(); }); _menu->OnStrategyNewEmpty.connect([&]() { onStrategyNewEmpty(); }); _menu->OnStrategyNewTemplate.connect([&]() { onStrategyNewTemplate(); }); _menu->OnStrategyNewDefault.connect([&]() { onStrategyNewDefault(); }); _menu->OnStrategyOpen.connect([&]() { onStrategyOpen(); }); _menu->OnStrategyOpenDefault.connect( [&](const std::string& name) { onStrategyOpenDefault(name); }); _menu->OnStrategySave.connect([&]() { onStrategySave(); }); _menu->OnStrategySaveAs.connect([&]() { onStrategySaveAs(); }); // Plot _menu->OnPlotDistPressed.connect([&]() { onPlotDistPressed(); }); _menu->OnPlotLogLogDistPressed.connect([&]() { onPlotLogLogDistPressed(); }); _menu->OnPlotMeanSpectrumPressed.connect( [&]() { onPlotMeanSpectrumPressed(); }); _menu->OnPlotSumSpectrumPressed.connect( [&]() { onPlotSumSpectrumPressed(); }); _menu->OnPlotPowerSpectrumPressed.connect( [&]() { onPlotPowerSpectrumPressed(); }); _menu->OnPlotFrequencyScatterPressed.connect( [&]() { onPlotFrequencyScatterPressed(); }); _menu->OnPlotTimeMeanPressed.connect([&]() { onPlotTimeMeanPressed(); }); _menu->OnPlotTimeScatterPressed.connect( [&]() { onPlotTimeScatterPressed(); }); _menu->OnPlotSingularValuesPressed.connect( [&]() { onPlotSingularValuesPressed(); }); // Browse _menu->OnLoadPrevious.connect([&]() { onLoadPrevious(); }); _menu->OnReloadPressed.connect([&]() { onReloadPressed(); }); _menu->OnLoadNext.connect([&]() { onLoadNext(); }); _menu->OnGoToPressed.connect([&]() { onGoToPressed(); }); _menu->OnLoadLongestBaselinePressed.connect( [&]() { onLoadExtremeBaseline(true); }); _menu->OnLoadMedianBaselinePressed.connect([&]() { onLoadMedianBaseline(); }); _menu->OnLoadShortestBaselinePressed.connect( [&]() { onLoadExtremeBaseline(false); }); // Simulate _menu->OnSimulate.connect([&]() { onSimulate(); }); _menu->OnOpenTestSetA.connect([&]() { onOpenTestSetA(); }); _menu->OnOpenTestSetB.connect([&]() { onOpenTestSetB(); }); _menu->OnOpenTestSetC.connect([&]() { onOpenTestSetC(); }); _menu->OnOpenTestSetD.connect([&]() { onOpenTestSetD(); }); _menu->OnOpenTestSetE.connect([&]() { onOpenTestSetE(); }); _menu->OnOpenTestSetF.connect([&]() { onOpenTestSetF(); }); _menu->OnOpenTestSetG.connect([&]() { onOpenTestSetG(); }); _menu->OnOpenTestSetH.connect([&]() { onOpenTestSetH(); }); _menu->OnOpenTestSetNoise.connect([&]() { onOpenTestSetNoise(); }); _menu->OnAddStaticFringe.connect([&]() { onAddStaticFringe(); }); _menu->OnAdd1SigmaFringe.connect([&]() { onAdd1SigmaFringe(); }); _menu->OnSetToOne.connect([&]() { onSetToOne(); }); _menu->OnSetToI.connect([&]() { onSetToI(); }); _menu->OnSetToOnePlusI.connect([&]() { onSetToOnePlusI(); }); _menu->OnAddCorrelatorFault.connect([&]() { onAddCorrelatorFault(); }); _menu->OnAddNaNs.connect([&]() { onAddNaNs(); }); _menu->OnMultiplyData.connect([&]() { onMultiplyData(); }); // Data _menu->OnVisualizedToOriginalPressed.connect( [&]() { onVisualizedToOriginalPressed(); }); _menu->OnKeepRealPressed.connect([&]() { onKeepRealPressed(); }); _menu->OnKeepImaginaryPressed.connect([&]() { onKeepImaginaryPressed(); }); _menu->OnKeepPhasePressed.connect([&]() { onKeepPhasePressed(); }); _menu->OnUnrollPhaseButtonPressed.connect( [&]() { onUnrollPhaseButtonPressed(); }); _menu->OnKeepStokesIPressed.connect([&]() { onKeepStokesIPressed(); }); _menu->OnKeepStokesQPressed.connect([&]() { onKeepStokesQPressed(); }); _menu->OnKeepStokesUPressed.connect([&]() { onKeepStokesUPressed(); }); _menu->OnKeepStokesVPressed.connect([&]() { onKeepStokesVPressed(); }); _menu->OnKeepRRPressed.connect([&]() { onKeepRRPressed(); }); _menu->OnKeepRLPressed.connect([&]() { onKeepRLPressed(); }); _menu->OnKeepLRPressed.connect([&]() { onKeepLRPressed(); }); _menu->OnKeepLLPressed.connect([&]() { onKeepLLPressed(); }); _menu->OnKeepXXPressed.connect([&]() { onKeepXXPressed(); }); _menu->OnKeepXYPressed.connect([&]() { onKeepXYPressed(); }); _menu->OnKeepYXPressed.connect([&]() { onKeepYXPressed(); }); _menu->OnKeepYYPressed.connect([&]() { onKeepYYPressed(); }); _menu->OnStoreData.connect([&]() { onStoreData(); }); _menu->OnRecallData.connect([&]() { onRecallData(); }); _menu->OnSubtractDataFromMem.connect([&]() { onSubtractDataFromMem(); }); _menu->OnClearOriginalFlagsPressed.connect( [&]() { onClearOriginalFlagsPressed(); }); _menu->OnClearAltFlagsPressed.connect([&]() { onClearAltFlagsPressed(); }); _menu->OnTemporalAveragingPressed.connect([&]() { handleAveraging(false); }); _menu->OnSpectralAveragingPressed.connect([&]() { handleAveraging(true); }); // Actions _menu->OnSegment.connect([&]() { onSegment(); }); _menu->OnCluster.connect([&]() { onCluster(); }); _menu->OnClassify.connect([&]() { onClassify(); }); _menu->OnRemoveSmallSegments.connect([&]() { onRemoveSmallSegments(); }); // Toolbar signals (some are already covered) _menu->OnTogglePolarizations.connect([&]() { onTogglePolarizations(); }); _menu->OnToggleImage.connect([&]() { onToggleImage(); }); _menu->OnSelectImage.connect([&]() { onSelectImage(); }); _mainVBox.pack_start(_menu->Menu(), Gtk::PACK_SHRINK); _mainVBox.pack_start(_menu->Toolbar(), Gtk::PACK_SHRINK); _mainVBox.pack_start(_timeFrequencyWidget, Gtk::PACK_EXPAND_WIDGET); _timeFrequencyWidget.GetHeatMapWidget().OnMouseMovedEvent().connect( sigc::mem_fun(*this, &RFIGuiWindow::onTFWidgetMouseMoved)); _timeFrequencyWidget.GetHeatMapWidget().OnMouseLeaveEvent().connect( sigc::mem_fun(*this, &RFIGuiWindow::setSetNameInStatusBar)); _timeFrequencyWidget.GetHeatMapWidget().OnScrollEvent().connect( sigc::mem_fun(*this, &RFIGuiWindow::onTFScroll)); _timeFrequencyWidget.GetHeatMapWidget().Plot().OnZoomChanged().connect( sigc::mem_fun(*this, &RFIGuiWindow::onTFZoomChanged)); MaskedHeatMap& map = _timeFrequencyWidget.GetMaskedHeatMap(); map.SetShowXAxisDescription(false); map.SetXAxisType(AxisType::kTime); map.SetShowYAxisDescription(false); map.SetShowZAxisDescription(false); _strategyEditor.SetText(_controller->GetWorkStrategyText()); _strategyEditor.ResetChangedStatus(); _mainVBox.pack_start(_strategyEditor, Gtk::PACK_EXPAND_WIDGET); _controller->TFController().VisualizationListChange().connect( sigc::mem_fun(*this, &RFIGuiWindow::updateTFVisualizationMenu)); _mainVBox.pack_end(_statusbar, Gtk::PACK_SHRINK); _statusbar.push("Ready. For suggestions, contact offringa@gmail.com ."); add(_mainVBox); _mainVBox.show_all(); _strategyEditor.hide(); _timeFrequencyWidget.DisableTimePlot(); onTFZoomChanged(); _controller->SignalStateChange().connect( sigc::mem_fun(*this, &RFIGuiWindow::onControllerStateChange)); _controller->SignalRecentFilesChanged().connect( sigc::mem_fun(*this, &RFIGuiWindow::updateRecentFiles)); updateTFVisualizationMenu(); updateRecentFiles(); updateOpenStrategyMenu(); signal_delete_event().connect( [&](GdkEventAny* event) { return onClose(event); }); } RFIGuiWindow::~RFIGuiWindow() {} bool RFIGuiWindow::onClose(GdkEventAny* event) { return !askToSaveChanges(); } bool RFIGuiWindow::askToSaveChanges() { if (_strategyEditor.IsChanged()) { Gtk::MessageDialog dialog( "The strategy was changed without saving. Do you want to save your " "changes?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE); dialog.add_button("Don't save", Gtk::RESPONSE_CLOSE); dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_YES); const int result = dialog.run(); if (result == Gtk::RESPONSE_CANCEL) { return false; } else if (result == Gtk::RESPONSE_CLOSE) { return true; } else { onStrategySave(); // In case the strategy had no name yet, the onStrategySave() call will // show a file dialog where the user might press cancel. In that case, // the operation is cancelled: return !_strategyEditor.IsChanged(); } } else { return true; } } void RFIGuiWindow::onOpen() { OpenDialog openDialog(*this); const int result = openDialog.run(); if (result == Gtk::RESPONSE_OK) { OpenMS(openDialog.Selection(), openDialog.GetOptions()); } } void RFIGuiWindow::onOpenRecent(size_t index) { OpenPaths(std::vector{_controller->RecentFiles()[index]}); } void RFIGuiWindow::updateRecentFiles() { const std::vector files = _controller->RecentFiles(); std::vector leafs; leafs.reserve(files.size()); for (const std::string& f : files) { std::error_code err_code; std::filesystem::path path = std::filesystem::canonical(std::filesystem::path(f), err_code); if (!err_code) leafs.emplace_back(path.filename().string()); } _menu->SetRecentFiles(leafs); } void RFIGuiWindow::updateOpenStrategyMenu() { const std::vector telescopeIds = TelescopeFile::List(); std::vector strategies; for (const TelescopeFile::TelescopeId id : telescopeIds) { strategies.emplace_back(TelescopeFile::TelescopeName(id)); } _menu->SetStrategyDefaults(strategies); } void RFIGuiWindow::onClose() { _controller->CloseImageSet(); } void RFIGuiWindow::onExportBaseline() { Gtk::FileChooserDialog dialog("Select baseline file", Gtk::FILE_CHOOSER_ACTION_SAVE); dialog.set_transient_for(*this); dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("_Save", Gtk::RESPONSE_ACCEPT); auto filter_rfibl = Gtk::FileFilter::create(); filter_rfibl->set_name("Baseline files (*.rfibl)"); filter_rfibl->add_mime_type("application/rfibl"); filter_rfibl->add_pattern("*.rfibl"); dialog.add_filter(filter_rfibl); auto filter_npy = Gtk::FileFilter::create(); filter_npy->set_name("Numpy array (*.npy)"); filter_npy->add_mime_type("application/npy"); filter_npy->add_pattern("*.npy"); dialog.add_filter(filter_npy); dialog.set_do_overwrite_confirmation(true); const int result = dialog.run(); if (result == Gtk::RESPONSE_ACCEPT) { if (dialog.get_filter() == filter_rfibl) _controller->SaveBaselineAsRfibl(dialog.get_filename()); else _controller->SaveBaselineAsNpy(dialog.get_filename()); } } void RFIGuiWindow::OpenPaths(const std::vector& paths) { if (paths.size() > 1 || imagesets::ImageSet::IsMSFile(paths.front())) { OpenDialog openDialog(*this); openDialog.SetSelection(paths); openDialog.ActivateOptionsTab(); const int result = openDialog.run(); if (result == Gtk::RESPONSE_OK) { OpenMS(openDialog.Selection(), openDialog.GetOptions()); } } else { _controller->Open(paths); if (dynamic_cast(&_controller->GetImageSet()) != nullptr) OpenGotoWindow(); else loadWithProgress(); } } void RFIGuiWindow::OpenMS(const std::vector& filenames, const MSOptions& options) { try { _controller->OpenMS(filenames, options); if (dynamic_cast(&_controller->GetImageSet()) != nullptr) OpenGotoWindow(); else loadWithProgress(); } catch (std::exception& e) { Gtk::MessageDialog dialog(*this, e.what(), false, Gtk::MESSAGE_ERROR); dialog.run(); } } void RFIGuiWindow::onSaveBaselineFlags() { Gtk::MessageDialog dialog(*this, "Are you sure you want to change the currently " "opened dataset and write the flags as displayed?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true); if (dialog.run() == Gtk::RESPONSE_OK) _controller->SaveBaselineFlags(); } TimeFrequencyData RFIGuiWindow::GetActiveData() const { return _controller->TFController().GetActiveData(); } const TimeFrequencyData& RFIGuiWindow::GetOriginalData() const { return _controller->TFController().OriginalData(); } ThresholdConfig& RFIGuiWindow::HighlightConfig() { return _controller->TFController().Plot().HighlightConfig(); } void RFIGuiWindow::SetHighlighting(bool newValue) { _controller->TFController().Plot().SetHighlighting(newValue); } TimeFrequencyMetaDataCPtr RFIGuiWindow::SelectedMetaData() { return _controller->TFController().Plot().GetSelectedMetaData(); } void RFIGuiWindow::onToggleFlags() { _controller->SetShowOriginalFlags(_menu->OriginalFlagsActive()); _controller->SetShowAlternativeFlags(_menu->AlternativeFlagsActive()); } void RFIGuiWindow::onTogglePolarizations() { _controller->SetShowPP(_menu->ShowPPActive()); _controller->SetShowPQ(_menu->ShowPQActive()); _controller->SetShowQP(_menu->ShowQPActive()); _controller->SetShowQQ(_menu->ShowQQActive()); } void RFIGuiWindow::setSetNameInStatusBar() { if (_controller->HasImageSet()) { _statusbar.pop(); _statusbar.push(_imageSetName + ": " + _imageSetIndexDescription); } } void RFIGuiWindow::SetImageSetIndex( const imagesets::ImageSetIndex& newImageSetIndex) { _controller->SetImageSetIndex(newImageSetIndex); loadWithProgress(); } void RFIGuiWindow::loadWithProgress() { _menu->ActivateDataMode(); set_sensitive(false); _progressWindow.reset(new ProgressWindow()); _progressWindow->SignalFinished().connect([&](bool success) { _taskThread.join(); _progressWindow.reset(); set_sensitive(true); _controller->LoadCurrentTFDataFinish(success); }); _progressWindow->present(); _taskThread = std::thread( [&]() { _controller->LoadCurrentTFDataAsync(*_progressWindow); }); } void RFIGuiWindow::onLoadPrevious() { if (_controller->HasImageSet()) { std::unique_lock lock(_controller->IOMutex()); imagesets::ImageSetIndex index = _controller->GetImageSetIndex(); index.Previous(); _controller->SetImageSetIndex(index); lock.unlock(); loadWithProgress(); } } void RFIGuiWindow::onLoadNext() { if (_controller->HasImageSet()) { std::unique_lock lock(_controller->IOMutex()); imagesets::ImageSetIndex index = _controller->GetImageSetIndex(); index.Next(); _controller->SetImageSetIndex(index); lock.unlock(); loadWithProgress(); } } void RFIGuiWindow::onViewData() { _timeFrequencyWidget.show(); _strategyEditor.hide(); } void RFIGuiWindow::onViewStrategy() { _timeFrequencyWidget.hide(); _strategyEditor.show(); } void RFIGuiWindow::onViewTimePlot() { const bool viewTime = _menu->ViewTimePlot(); if (viewTime) { _timeFrequencyWidget.EnableTimePlot(); _controller->DrawTimeMean(_timeFrequencyWidget.TimePlot()); } else { _timeFrequencyWidget.DisableTimePlot(); } } void RFIGuiWindow::onExecuteLuaStrategy() { _controller->SetWorkStrategyText(_strategyEditor.GetText()); _progressWindow.reset(new ProgressWindow()); _progressWindow->SignalFinished().connect( [&](bool successfull) { onExecuteStrategyFinished(successfull); }); _progressWindow->SignalError().connect( [&](const std::string& err) { onExecuteStrategyError(err); }); _progressWindow->present(); _menu->EnableRunButtons(false); _controller->ExecuteLuaStrategy(*_progressWindow); } void RFIGuiWindow::onExecuteStrategyFinished(bool successfull) { _controller->JoinLuaThread(); if (successfull) _menu->ActivateDataMode(); _menu->EnableRunButtons(true); _progressWindow.reset(); } void RFIGuiWindow::onExecuteStrategyError(const std::string& error) { _menu->ActivateStrategyMode(); const size_t colon = error.find(':'); if (colon != error.npos) { const size_t lineNr = std::atoi(error.substr(colon + 1).c_str()); _strategyEditor.HighlightLine(lineNr); } Gtk::MessageDialog dialog(*this, error, false, Gtk::MESSAGE_ERROR); dialog.run(); } void RFIGuiWindow::openTestSet(algorithms::RFITestSet rfiSet, algorithms::BackgroundTestSet backgroundSet) { _controller->OpenTestSet(rfiSet, backgroundSet); } void RFIGuiWindow::onClearOriginalFlagsPressed() { TimeFrequencyData data = _controller->TFController().GetVisualizationData(0); data.SetMasksToValue(); _controller->TFController().SetVisualizationData(0, std::move(data)); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onClearAltFlagsPressed() { TimeFrequencyData data(_controller->TFController().AltMaskData()); data.SetMasksToValue(); _controller->TFController().SetAltMaskData(data); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onVisualizedToOriginalPressed() { if (HasImage()) { const TimeFrequencyData data(_controller->TFController().GetActiveData()); _controller->TFController().SetNewData( std::move(data), _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); } } void RFIGuiWindow::onAddStaticFringe() { try { if (HasImage()) { const TimeFrequencyMetaDataCPtr metaData = SelectedMetaData(); TimeFrequencyData data(GetActiveData()); FringeTestCreater::AddStaticFringe(data, metaData, 1.0L); _controller->TFController().SetNewData(data, metaData); _timeFrequencyWidget.Update(); } } catch (std::exception& e) { showError(e.what()); } } void RFIGuiWindow::onAdd1SigmaFringe() { try { if (HasImage()) { const TimeFrequencyMetaDataCPtr metaData = SelectedMetaData(); num_t mean, stddev; TimeFrequencyData data(GetActiveData()); ThresholdTools::MeanAndStdDev(data.GetRealPart().get(), data.GetSingleMask().get(), mean, stddev); FringeTestCreater::AddStaticFringe(data, metaData, stddev); _controller->TFController().SetNewData( data, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } } catch (std::exception& e) { showError(e.what()); } } void RFIGuiWindow::onSetToOne() { try { const TimeFrequencyData data(GetActiveData()); std::array images = data.GetSingleComplexImage(); Image2DPtr real = Image2D::MakePtr(*images[0]), imaginary = Image2D::MakePtr(*images[1]); real->SetAll(1.0); imaginary->SetAll(0.0); TimeFrequencyData newData(data.GetPolarization(0), real, imaginary); newData.SetMask(data); _controller->TFController().SetNewData( newData, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } catch (std::exception& e) { showError(e.what()); } } void RFIGuiWindow::onSetToI() { try { const TimeFrequencyData data(GetActiveData()); std::array images = data.GetSingleComplexImage(); Image2DPtr real = Image2D::MakePtr(*images[0]), imaginary = Image2D::MakePtr(*images[0]); real->SetAll(0.0); imaginary->SetAll(1.0); TimeFrequencyData newData(data.GetPolarization(0), real, imaginary); newData.SetMask(data); _controller->TFController().SetNewData( newData, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } catch (std::exception& e) { showError(e.what()); } } void RFIGuiWindow::onSetToOnePlusI() { try { const TimeFrequencyData data(GetActiveData()); std::array images = data.GetSingleComplexImage(); Image2DPtr real = Image2D::MakePtr(*images[0]), imaginary = Image2D::MakePtr(*images[0]); real->SetAll(1.0); imaginary->SetAll(1.0); TimeFrequencyData newData(data.GetPolarization(0), real, imaginary); newData.SetMask(data); _controller->TFController().SetNewData( newData, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } catch (std::exception& e) { showError(e.what()); } } void RFIGuiWindow::onAddCorrelatorFault() { Gtk::MessageDialog dialog(*this, "Enter affected timerange (ratios):", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true); Gtk::Entry startTime; Gtk::Box hBox; startTime.set_text("0.25"); hBox.pack_start(startTime); Gtk::Label dashLabel("-"); hBox.pack_start(dashLabel); Gtk::Entry endTime; endTime.set_text("0.5"); hBox.pack_start(endTime); Gtk::Box* box = dialog.get_content_area(); box->pack_start(hBox); box->show_all_children(); if (dialog.run() == Gtk::RESPONSE_OK) { TimeFrequencyData data(GetActiveData()); const double startRatio = std::atof(startTime.get_text().c_str()); const double endRatio = std::atof(endTime.get_text().c_str()); const size_t startIndex = data.ImageWidth() * startRatio; const size_t endIndex = data.ImageWidth() * endRatio; for (size_t i = 0; i != data.ImageCount(); ++i) { Image2DPtr image(new Image2D(*data.GetImage(i))); const num_t addValue = 10.0 * image->GetStdDev(); for (size_t y = 0; y != image->Height(); ++y) { for (size_t x = startIndex; x != endIndex; ++x) image->AddValue(x, y, addValue); } data.SetImage(i, std::move(image)); } for (size_t i = 0; i != data.MaskCount(); ++i) { Mask2DPtr mask(new Mask2D(*data.GetMask(i))); for (size_t y = 0; y != mask->Height(); ++y) { for (size_t x = startIndex; x != endIndex; ++x) mask->SetValue(x, y, true); } data.SetMask(i, std::move(mask)); } _controller->TFController().SetNewData( data, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } } void RFIGuiWindow::onAddNaNs() { TimeFrequencyData data(GetActiveData()); const size_t start_time = data.ImageWidth() * 1 / 4; const size_t end_time = data.ImageWidth() * 2 / 4; const size_t start_channel = data.ImageHeight() * 1 / 4; const size_t end_channel = data.ImageHeight() * 2 / 4; for (size_t i = 0; i != data.ImageCount(); ++i) { Image2DPtr image(new Image2D(*data.GetImage(i))); for (size_t y = start_channel; y != end_channel; ++y) { for (size_t x = start_time; x != end_time; ++x) image->SetValue(x, y, std::numeric_limits::quiet_NaN()); } data.SetImage(i, std::move(image)); } for (size_t i = 0; i != data.MaskCount(); ++i) { Mask2DPtr mask(new Mask2D(*data.GetMask(i))); for (size_t y = start_channel; y != end_channel; ++y) { for (size_t x = start_time; x != end_time; ++x) mask->SetValue(x, y, true); } data.SetMask(i, std::move(mask)); } _controller->TFController().SetNewData( data, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onShowStats() { if (_timeFrequencyWidget.HasImage()) { const TimeFrequencyData activeData = GetActiveData(); TimeFrequencyStatistics statistics(activeData); std::stringstream s; s << "Percentage flagged: " << TimeFrequencyStatistics::FormatRatio(statistics.GetFlaggedRatio()) << "\n"; Mask2DCPtr original = _controller->TFController().Plot().OriginalMask(), alternative = _controller->TFController().Plot().AlternativeMask(); Mask2DPtr intersect; if (original != nullptr && alternative != nullptr) { intersect = Mask2D::MakePtr(*original); intersect->Intersect(*alternative); const unsigned intCount = intersect->GetCount(); if (intCount != 0) { if (*original != *alternative) { s << "Overlap between original and alternative: " << TimeFrequencyStatistics::FormatRatio( (double)intCount / ((double)(original->Width() * original->Height()))) << "\n" << "(relative to alternative flags: " << TimeFrequencyStatistics::FormatRatio( (double)intCount / ((double)(alternative->GetCount()))) << ")\n"; } } } const Image2DCPtr powerImg = activeData.GetSingleImage(); const Mask2DCPtr mask = activeData.GetSingleMask(); double power = 0.0; for (unsigned y = 0; y < powerImg->Height(); ++y) { for (unsigned x = 0; x < powerImg->Width(); ++x) { if (!mask->Value(x, y) && std::isfinite(powerImg->Value(x, y))) { power += powerImg->Value(x, y); } } } s << "Total unflagged power: " << power << "\n"; Gtk::MessageDialog dialog(*this, s.str(), false, Gtk::MESSAGE_INFO); dialog.run(); } } void RFIGuiWindow::onPlotDistPressed() { _controller->PlotDist(); } void RFIGuiWindow::onPlotLogLogDistPressed() { _controller->PlotLogLogDist(); } void RFIGuiWindow::onPlotPowerSpectrumPressed() { _controller->PlotPowerSpectrum(); } void RFIGuiWindow::onPlotFrequencyScatterPressed() { _controller->PlotFrequencyScatter(); } void RFIGuiWindow::onPlotTimeMeanPressed() { _controller->PlotTimeMean(); } void RFIGuiWindow::onPlotTimeScatterPressed() { _controller->PlotTimeScatter(); } void RFIGuiWindow::onPlotSingularValuesPressed() { _controller->PlotSingularValues(); } void RFIGuiWindow::ShowHistogram(HistogramCollection& histogramCollection) { if (_histogramWindow == nullptr) _histogramWindow.reset(new HistogramWindow(histogramCollection)); else _histogramWindow->SetStatistics(histogramCollection); _histogramWindow->show(); } void RFIGuiWindow::onImagePropertiesPressed() { _imagePropertiesWindow.reset( new ImagePropertiesWindow(_timeFrequencyWidget.GetHeatMapWidget(), "Time-frequency plotting options")); _imagePropertiesWindow->show(); } void RFIGuiWindow::onPlotMeanSpectrumPressed() { _controller->PlotMeanSpectrum(); } void RFIGuiWindow::onPlotSumSpectrumPressed() { _controller->PlotSumSpectrum(); } void RFIGuiWindow::keepPhasePart( enum TimeFrequencyData::ComplexRepresentation phaseRepresentation) { if (HasImage()) { try { _controller->TFController().SetNewData( _controller->TFController().GetActiveData().Make(phaseRepresentation), _controller->TFController().Plot().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } catch (std::exception& e) { std::stringstream errstr; errstr << "The data that was currently in memory could not be converted " "to the requested " "type. The error given by the converter was:\n" << e.what() << "\n\n" << "Note that if the original data should be convertable to this " "type, but " "you have already used one of the 'Keep ..' buttons, you first " "need to reload " "the full data with Goto -> Load.\n\n" "(alternatively, if loading takes a lot of time, you can use " "the Store and Recall" " options in the Data menu)"; showError(errstr.str()); } } } void RFIGuiWindow::updatePolarizations() { _controller->CheckPolarizations(); bool pp, pq, qp, qq; _controller->GetAvailablePolarizations(pp, pq, qp, qq); _menu->SetShowPPSensitive(pp); _menu->SetShowPQSensitive(pq); _menu->SetShowQPSensitive(qp); _menu->SetShowQQSensitive(qq); } void RFIGuiWindow::keepPolarisation(aocommon::PolarizationEnum polarisation) { if (HasImage()) { try { _controller->TFController().SetNewData( _controller->TFController().GetActiveData().Make(polarisation), _controller->TFController().Plot().GetSelectedMetaData()); updatePolarizations(); _timeFrequencyWidget.Update(); } catch (std::exception& e) { std::stringstream errstr; errstr << "The data that was currently in memory could not be converted " "to the requested " "polarization. The error given by the converter was:\n" << e.what() << "\n\n" << "Note that if the original data should be convertable to this " "polarization, but " "you have already used one of the 'Keep ..' buttons, you first " "need to reload " "the full data with Goto -> Load.\n\n" "(alternatively, if loading takes a lot of time, you can use " "the Store and Recall" " options in the Data menu)"; showError(errstr.str()); } } } void RFIGuiWindow::onGoToPressed() { if (_controller->HasImageSet()) { _menu->ActivateDataMode(); imagesets::IndexableSet* msSet = dynamic_cast(&_controller->GetImageSet()); if (msSet != nullptr) { _gotoWindow.reset(new GoToWindow(*this)); _gotoWindow->present(); } else { showError("Can not goto in this image set; format does not support goto"); } } } void RFIGuiWindow::onReloadPressed() { if (_controller->HasImageSet()) { loadWithProgress(); } } void RFIGuiWindow::onLoadExtremeBaseline(bool longest) { if (_controller->HasImageSet()) { imagesets::ImageSetIndex index = _controller->GetImageSetIndex(); const bool available = imagesets::IndexableSet::FindExtremeBaseline( &_controller->GetImageSet(), index, longest); if (available) { _controller->SetImageSetIndex(index); loadWithProgress(); } } } void RFIGuiWindow::onLoadMedianBaseline() { if (_controller->HasImageSet()) { imagesets::ImageSetIndex index = _controller->GetImageSetIndex(); const bool available = imagesets::IndexableSet::FindMedianBaseline( &_controller->GetImageSet(), index); if (available) { _controller->SetImageSetIndex(index); loadWithProgress(); } } } void RFIGuiWindow::onTFWidgetMouseMoved(double x, double y) { const MaskedHeatMap& heatMap = _timeFrequencyWidget.GetMaskedHeatMap(); const Image2DCPtr image = heatMap.GetImage2D(); size_t imageX; size_t imageY; if (heatMap.UnitToImage(x, y, imageX, imageY)) { const num_t v = image->Value(imageX, imageY); _statusbar.pop(); std::stringstream s; s << "x=" << imageX << ",y=" << imageY << ",value=" << v; const TimeFrequencyMetaDataCPtr metaData = _timeFrequencyWidget.GetMaskedHeatMap().GetFullMetaData(); if (metaData != nullptr) { if (metaData->HasObservationTimes() && metaData->HasBand()) { const std::vector& times = metaData->ObservationTimes(); s << " (t=" << Date::AipsMJDToString(times[imageX]) << ", f=" << Frequency::ToString(metaData->Band().channels[imageY].frequencyHz); } if (metaData->HasUVW()) { const UVW uvw = metaData->UVW()[imageX]; s << ", uvw=" << uvw.u << "," << uvw.v << "," << uvw.w; } s << ')'; } _statusbar.push(s.str(), 0); } } void RFIGuiWindow::onMultiplyData() { TimeFrequencyData data(GetActiveData()); data.MultiplyImages(2.0L); _controller->TFController().SetNewData( data, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onSegment() { const SegmentedImagePtr segmentedImage = SegmentedImage::CreateUnsetPtr( GetOriginalData().ImageWidth(), GetOriginalData().ImageHeight()); Morphology morphology; morphology.SegmentByLengthRatio(GetActiveData().GetSingleMask().get(), segmentedImage); _timeFrequencyWidget.GetMaskedHeatMap().SetSegmentedImage(segmentedImage); Update(); } void RFIGuiWindow::onCluster() { const SegmentedImagePtr segmentedImage = _timeFrequencyWidget.GetMaskedHeatMap().GetSegmentedImage(); if (segmentedImage) { Morphology morphology; morphology.Cluster(segmentedImage); _timeFrequencyWidget.GetMaskedHeatMap().SetSegmentedImage(segmentedImage); Update(); } } void RFIGuiWindow::onClassify() { const SegmentedImagePtr segmentedImage = _timeFrequencyWidget.GetMaskedHeatMap().GetSegmentedImage(); if (segmentedImage) { Morphology morphology; morphology.Classify(segmentedImage); _timeFrequencyWidget.GetMaskedHeatMap().SetSegmentedImage(segmentedImage); Update(); } } void RFIGuiWindow::onRemoveSmallSegments() { const SegmentedImagePtr segmentedImage = _timeFrequencyWidget.GetMaskedHeatMap().GetSegmentedImage(); if (segmentedImage) { Morphology morphology; morphology.RemoveSmallSegments(segmentedImage, 4); _timeFrequencyWidget.GetMaskedHeatMap().SetSegmentedImage(segmentedImage); Update(); } } void RFIGuiWindow::onTFScroll(double x, double y, int direction) { if (direction < 0) { _timeFrequencyWidget.GetMaskedHeatMap().ZoomInOn(x, y); _timeFrequencyWidget.Update(); } else if (direction > 0) { _timeFrequencyWidget.GetMaskedHeatMap().ZoomOut(); _timeFrequencyWidget.Update(); } } void RFIGuiWindow::onUnrollPhaseButtonPressed() { if (HasImage()) { TimeFrequencyData data = GetActiveData().Make(TimeFrequencyData::PhasePart); for (unsigned i = 0; i < data.ImageCount(); ++i) { const Image2DPtr image = Image2D::MakePtr(*data.GetImage(i)); ThresholdTools::UnrollPhase(image.get()); data.SetImage(i, image); } _controller->TFController().SetNewData( data, _timeFrequencyWidget.GetMaskedHeatMap().GetSelectedMetaData()); _timeFrequencyWidget.Update(); } } void RFIGuiWindow::showError(const std::string& description) { Gtk::MessageDialog dialog(*this, description, false, Gtk::MESSAGE_ERROR); dialog.run(); } void RFIGuiWindow::onSimulate() { SimulateDialog simDialog; if (simDialog.run() == Gtk::RESPONSE_OK) { _controller->TFController().SetNewData( simDialog.Make(), TimeFrequencyMetaDataPtr(new TimeFrequencyMetaData())); const char* name = "Simulated test set"; _controller->TFController().Plot().SetTitleText(name); SetBaselineInfo(true, false, name, name); } } void RFIGuiWindow::onStoreData() { if (HasImage()) { _storedData = _controller->TFController().GetActiveData(); _storedMetaData = _controller->TFController().Plot().GetSelectedMetaData(); } } void RFIGuiWindow::onRecallData() { _controller->TFController().SetNewData(_storedData, _storedMetaData); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onSubtractDataFromMem() { if (HasImage()) { const TimeFrequencyData diffData = TimeFrequencyData::MakeFromDiff( _storedData, _controller->TFController().GetActiveData()); _controller->TFController().SetNewData(diffData, _storedMetaData); _timeFrequencyWidget.Update(); } } void RFIGuiWindow::onControllerStateChange() { _menu->BlockVisualizationSignals(); _menu->SetOriginalFlagsActive(_controller->AreOriginalFlagsShown()); _timeFrequencyWidget.GetMaskedHeatMap().SetShowOriginalMask( _controller->AreOriginalFlagsShown()); _menu->SetAlternativeFlagsActive(_controller->AreAlternativeFlagsShown()); _timeFrequencyWidget.GetMaskedHeatMap().SetShowAlternativeMask( _controller->AreAlternativeFlagsShown()); _menu->SetShowPPActive(_controller->IsPPShown()); _menu->SetShowPQActive(_controller->IsPQShown()); _menu->SetShowQPActive(_controller->IsQPShown()); _menu->SetShowQQActive(_controller->IsQQShown()); _controller->TFController().SetVisualizedPolarization( _controller->IsPPShown(), _controller->IsPQShown(), _controller->IsQPShown(), _controller->IsQQShown()); _menu->UnblockVisualizationSignals(); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onZoomFit() { _timeFrequencyWidget.GetMaskedHeatMap().ZoomFit(); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onZoomIn() { if (_timeFrequencyWidget.GetHeatMapWidget().IsMouseInImage()) _timeFrequencyWidget.GetMaskedHeatMap().ZoomInOn( _timeFrequencyWidget.GetHeatMapWidget().MouseX(), _timeFrequencyWidget.GetHeatMapWidget().MouseY()); else _timeFrequencyWidget.GetMaskedHeatMap().ZoomIn(); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onZoomOut() { _timeFrequencyWidget.GetMaskedHeatMap().ZoomOut(); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onZoomSelect() { MaskedHeatMap& heatMap = _timeFrequencyWidget.GetMaskedHeatMap(); if (!heatMap.HasImage()) return; const Image2DCPtr image = heatMap.GetImage2D(); const size_t nTimes = image->Width(); const size_t nChannels = image->Height(); std::unique_ptr dialog( new NumInputDialog("Select zoom region", "Start timestep: ", 0.0)); if (dialog->run() != Gtk::RESPONSE_OK) return; const double startTimestep = dialog->Value(); dialog.reset( new NumInputDialog("Select zoom region", "End timestep: ", nTimes)); if (dialog->run() != Gtk::RESPONSE_OK) return; const double endTimestep = dialog->Value(); dialog.reset( new NumInputDialog("Select zoom region", "Start channel: ", 0.0)); if (dialog->run() != Gtk::RESPONSE_OK) return; const double startChannel = dialog->Value(); dialog.reset( new NumInputDialog("Select zoom region", "End channel: ", nChannels)); if (dialog->run() != Gtk::RESPONSE_OK) return; const double endChannel = dialog->Value(); double x1, y1, x2, y2; heatMap.ImageToUnit(startTimestep, startChannel, x1, y1); heatMap.ImageToUnit(endTimestep, endChannel, x2, y2); heatMap.ZoomTo(x1, y1, x2, y2); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onTFZoomChanged() { const bool s = !_timeFrequencyWidget.GetMaskedHeatMap().IsZoomedOut(); const bool i = _timeFrequencyWidget.GetMaskedHeatMap().HasImage(); _menu->SetZoomToFitSensitive(s && i); _menu->SetZoomOutSensitive(s && i); _menu->SetZoomInSensitive(i); } void RFIGuiWindow::onHelpAbout() { Gtk::AboutDialog aboutDialog; std::vector authors; authors.push_back("André Offringa "); aboutDialog.set_authors(authors); const std::string release_year = std::string(AOFLAGGER_VERSION_DATE_STR).substr(0, 4); aboutDialog.set_copyright("Copyright 2008 - " + release_year + " A. R. Offringa"); aboutDialog.set_license_type(Gtk::LICENSE_GPL_3_0); aboutDialog.set_logo_icon_name("aoflagger"); aboutDialog.set_program_name("AOFlagger's RFI Gui"); aboutDialog.set_version("AOFlagger " AOFLAGGER_VERSION_STR " (" AOFLAGGER_VERSION_DATE_STR ") "); aboutDialog.set_website("https://readthedocs.org/projects/aoflagger/"); aboutDialog.run(); } void RFIGuiWindow::onExecutePythonStrategy() { try { _controller->ExecutePythonStrategy(); } catch (std::exception& e) { showError(e.what()); } } void RFIGuiWindow::SetBaselineInfo(bool isEmpty, bool hasMultipleBaselines, const std::string& name, const std::string& description) { _menu->SetPreviousSensitive(!isEmpty && hasMultipleBaselines); _menu->SetReloadSensitive(!isEmpty); _menu->SetNextSensitive(!isEmpty && hasMultipleBaselines); _imageSetName = name; _imageSetIndexDescription = description; setSetNameInStatusBar(); updatePolarizations(); _timeFrequencyWidget.Update(); } void RFIGuiWindow::onSelectImage() { const size_t index = getActiveTFVisualization(); _controller->TFController().SetVisualization(index); _timeFrequencyWidget.Update(); } void RFIGuiWindow::updateTFVisualizationMenu() { Gtk::Menu& menu = _menu->VisualizationMenu(); const std::vector children = menu.get_children(); for (Gtk::Widget* child : children) menu.remove(*child); _tfVisualizationMenuItems.clear(); Gtk::RadioButtonGroup group; for (size_t i = 0; i != _controller->TFController().VisualizationCount(); ++i) { const std::string label = _controller->TFController().GetVisualizationLabel(i); _tfVisualizationMenuItems.emplace_back(std::unique_ptr( new Gtk::RadioMenuItem(group, label))); Gtk::RadioMenuItem& item = *_tfVisualizationMenuItems.back(); item.signal_activate().connect( sigc::mem_fun(*this, &RFIGuiWindow::onSelectImage)); menu.add(item); } _menu->SetSelectVisualizationSensitive(_tfVisualizationMenuItems.size() > 1); _tfVisualizationMenuItems.front()->activate(); menu.show_all_children(); } void RFIGuiWindow::onToggleImage() { size_t index = getActiveTFVisualization(); ++index; if (index == _tfVisualizationMenuItems.size()) index = 0; _tfVisualizationMenuItems[index]->set_active(true); } size_t RFIGuiWindow::getActiveTFVisualization() { for (size_t index = 0; index != _tfVisualizationMenuItems.size(); ++index) { if (_tfVisualizationMenuItems[index]->get_active()) return index; } return 0; } void RFIGuiWindow::onStrategyNewEmpty() { if (askToSaveChanges()) { _controller->NewEmptyStrategy(); _strategyEditor.SetText(""); _strategyEditor.ResetChangedStatus(); _menu->ActivateStrategyMode(); } } void RFIGuiWindow::onStrategyNewTemplate() { if (askToSaveChanges()) { _controller->NewTemplateStrategy(); _strategyEditor.SetText(_controller->GetWorkStrategyText()); _strategyEditor.ResetChangedStatus(); _menu->ActivateStrategyMode(); } } void RFIGuiWindow::onStrategyNewDefault() { if (askToSaveChanges()) { _controller->NewDefaultStrategy(); _strategyEditor.SetText(_controller->GetWorkStrategyText()); _strategyEditor.ResetChangedStatus(); _menu->ActivateStrategyMode(); } } void RFIGuiWindow::onStrategyOpen() { if (askToSaveChanges()) { Gtk::FileChooserDialog dialog("Select strategy to open"); dialog.set_transient_for(*this); auto filter_text = Gtk::FileFilter::create(); filter_text->set_name("Lua strategy files (*.lua)"); filter_text->add_mime_type("text/x-lua"); dialog.add_filter(filter_text); // Add response buttons the the dialog: dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("_Open", Gtk::RESPONSE_OK); const int result = dialog.run(); if (result == Gtk::RESPONSE_OK) { _controller->OpenStrategy(dialog.get_filename()); _strategyEditor.SetText(_controller->GetWorkStrategyText()); _strategyEditor.ResetChangedStatus(); _menu->ActivateStrategyMode(); } } } void RFIGuiWindow::onStrategyOpenDefault(const std::string& name) { if (askToSaveChanges()) { const TelescopeFile::TelescopeId id = TelescopeFile::TelescopeIdFromName(name); const std::string filename = TelescopeFile::FindStrategy(id); if (filename.empty()) { showError("Could not find default strategy file for telescope '" + name + "' -- aoflagger is probably not installed properly"); } else { _controller->OpenStrategy(filename); _strategyEditor.SetText(_controller->GetWorkStrategyText()); _strategyEditor.ResetChangedStatus(); _menu->ActivateStrategyMode(); } } } void RFIGuiWindow::onStrategySave() { if (_controller->HasOpenStrategy()) { _controller->SetWorkStrategyText(_strategyEditor.GetText()); _controller->SaveStrategy(); _strategyEditor.ResetChangedStatus(); } else { onStrategySaveAs(); } } void RFIGuiWindow::onStrategySaveAs() { Gtk::FileChooserDialog dialog("Select filename for strategy", Gtk::FILE_CHOOSER_ACTION_SAVE); dialog.set_transient_for(*this); dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("_Save", Gtk::RESPONSE_ACCEPT); auto filter_text = Gtk::FileFilter::create(); filter_text->set_name("Lua strategy files (*.lua)"); filter_text->add_mime_type("text/x-lua"); dialog.add_filter(filter_text); dialog.set_do_overwrite_confirmation(true); if (_controller->HasOpenStrategy()) dialog.set_current_name(_controller->StrategyFilename()); const int result = dialog.run(); if (result == Gtk::RESPONSE_ACCEPT) { _controller->SetWorkStrategyText(_strategyEditor.GetText()); _controller->SaveStrategyAs(dialog.get_filename()); _strategyEditor.ResetChangedStatus(); } } void RFIGuiWindow::handleAveraging(bool spectrally) { if (HasImage()) { Gtk::MessageDialog dialog("Enter averaging factor", false, Gtk::MessageType::MESSAGE_QUESTION, Gtk::ButtonsType::BUTTONS_OK_CANCEL); Gtk::Entry entry; entry.set_text("2"); entry.set_max_width_chars(8); dialog.get_message_area()->pack_end(entry); entry.show(); if (dialog.run() == Gtk::RESPONSE_OK) { const int factor = std::atoi(entry.get_text().c_str()); if (factor > 1) { TimeFrequencyData data = _controller->TFController().GetActiveDataFullSize(); const TimeFrequencyMetaDataPtr meta(new TimeFrequencyMetaData( *_timeFrequencyWidget.GetMaskedHeatMap().GetFullMetaData())); if (spectrally) algorithms::downsample_masked(data, meta.get(), 1, factor); else algorithms::downsample_masked(data, meta.get(), factor, 1); _controller->TFController().SetNewData(data, meta); _timeFrequencyWidget.Update(); } } } } aoflagger-v3.4.0/rfigui/plotframe.h0000644000175000017500000000161214507760372015763 0ustar olesoles#ifndef PLOTFRAME_H #define PLOTFRAME_H #include #include "../structures/timefrequencydata.h" #include "../plot/plotwidget.h" class XYPlot; class PlotFrame : public Gtk::HBox { public: PlotFrame(); ~PlotFrame(); void SetTimeFrequencyData(const TimeFrequencyData& data) { _data = data; } void SetSelectedSample(size_t x, size_t y) { _selectedXStart = x; _selectedYStart = y; _selectedXEnd = x + 1; _selectedYEnd = y + 1; } void Update() { plot(); } private: TimeFrequencyData _data; PlotWidget _plot; XYPlot* _plotData; size_t _selectedXStart, _selectedYStart; size_t _selectedXEnd, _selectedYEnd; void plot(); void plotTimeGraph(const TimeFrequencyData& data, const std::string& label, aocommon::PolarizationEnum polarisation); void plotTimeGraph(const TimeFrequencyData& data, const std::string& label); }; #endif aoflagger-v3.4.0/rfigui/maskedheatmap.h0000644000175000017500000000556314507760372016607 0ustar olesoles#ifndef MASKED_HEAT_MAP_H #define MASKED_HEAT_MAP_H #include "plotimage.h" #include "../plot/heatmap.h" #include "../structures/mask2d.h" #include "../structures/segmentedimage.h" #include "../structures/timefrequencymetadata.h" namespace algorithms { class ThresholdConfig; } class MaskedHeatMap : public HeatMap { public: MaskedHeatMap(); ~MaskedHeatMap(); void Clear(); TimeFrequencyMetaDataCPtr GetSelectedMetaData() const; const TimeFrequencyMetaDataCPtr& GetFullMetaData() const { return _metaData; } void SetMetaData(const TimeFrequencyMetaDataCPtr& metaData); Mask2DCPtr OriginalMask() const { return _originalMask; } void SetOriginalMask(Mask2DCPtr mask) { _originalMask = mask; Invalidate(); } Mask2DCPtr AlternativeMask() const { return _alternativeMask; } void SetAlternativeMask(Mask2DCPtr mask) { _alternativeMask = mask; Invalidate(); } bool ShowOriginalMask() const { return _showOriginalMask; } void SetShowOriginalMask(bool newValue) { _showOriginalMask = newValue; Invalidate(); } bool ShowAlternativeMask() const { return _showAlternativeMask; } void SetShowAlternativeMask(bool newValue) { _showAlternativeMask = newValue; Invalidate(); } Mask2DCPtr GetActiveMask() const; void SetHighlighting(bool newValue) { _highlighting = newValue; Invalidate(); } algorithms::ThresholdConfig& HighlightConfig() { return *_highlightConfig; } SegmentedImagePtr GetSegmentedImage() const { return _segmentedImage; } void SetSegmentedImage(SegmentedImagePtr segmentedImage) { _segmentedImage = segmentedImage; } bool ManualXAxisDescription() const { return _manualXAxisDescription; } void SetManualXAxisDescription(bool manualDesc) { _manualXAxisDescription = manualDesc; Invalidate(); } bool ManualYAxisDescription() const { return _manualYAxisDescription; } void SetManualYAxisDescription(bool manualDesc) { _manualYAxisDescription = manualDesc; Invalidate(); } bool ManualZAxisDescription() const { return _manualZAxisDescription; } void SetManualZAxisDescription(bool manualDesc) { _manualZAxisDescription = manualDesc; Invalidate(); } void SaveText(const std::string& filename) const; void SaveByExtension(const std::string& filename, size_t width, size_t height); Image2DCPtr GetImage2D() const { return static_cast(Image()).Get(); } private: TimeFrequencyMetaDataCPtr _metaData; Mask2DCPtr _originalMask; Mask2DCPtr _alternativeMask; SegmentedImagePtr _segmentedImage; bool _showOriginalMask; bool _showAlternativeMask; bool _highlighting; std::unique_ptr _highlightConfig; bool _manualXAxisDescription; bool _manualYAxisDescription; bool _manualZAxisDescription; void signalDrawImage(const Cairo::RefPtr& surface) const; }; #endif aoflagger-v3.4.0/rfigui/gotowindow.cpp0000644000175000017500000002105314507760372016526 0ustar olesoles#include "gotowindow.h" #include #include #include "../imagesets/msimageset.h" #include "../imagesets/multibandmsimageset.h" #include "controllers/rfiguicontroller.h" #include "rfiguiwindow.h" static const std::vector& GetSequences( const imagesets::IndexableSet* image_set) { if (const auto* multi_band_image_set = dynamic_cast(image_set)) return multi_band_image_set->Sequences(); return image_set->Reader()->MetaData().GetSequences(); } GoToWindow::GoToWindow(RFIGuiWindow& rfiGuiWindow) : Gtk::Window(), _antenna1Frame("Antenna 1"), _antenna2Frame("Antenna 2"), _bandFrame("Band"), _sequenceFrame("Time sequence"), _loadButton("Load"), _keepOpenCB("Keep window open"), _rfiGuiWindow(rfiGuiWindow), _imageSet(&static_cast( rfiGuiWindow.Controller().GetImageSet())) { set_default_size(0, 500); _antennaeStore = Gtk::ListStore::create(_antennaModelColumns); _bandStore = Gtk::ListStore::create(_bandModelColumns); _sequenceStore = Gtk::ListStore::create(_sequenceModelColumns); const std::vector& _sequences = GetSequences(_imageSet); const imagesets::ImageSetIndex& setIndex = _rfiGuiWindow.Controller().GetImageSetIndex(); const unsigned antenna1Index = _imageSet->GetAntenna1(setIndex); const unsigned antenna2Index = _imageSet->GetAntenna2(setIndex); const unsigned bandIndex = _imageSet->GetBand(setIndex); const unsigned sequenceIndex = _imageSet->GetSequenceId(setIndex); // First, the sequences are iterated to get all antenna indices. std::set set; for (const MSMetaData::Sequence& seq : _sequences) { set.insert(seq.antenna1); set.insert(seq.antenna2); } Gtk::TreeModel::iterator a1Row, a2Row, bandRow, sequenceRow; // Now we make a store that contains all antennas. This store is shared for // both a1 and a2 views. for (std::set::const_iterator i = set.begin(); i != set.end(); ++i) { const Gtk::TreeModel::iterator iter = _antennaeStore->append(); (*iter)[_antennaModelColumns.antennaIndex] = *i; const AntennaInfo antenna = _imageSet->GetAntennaInfo(*i); (*iter)[_antennaModelColumns.antennaName] = antenna.name; if (antenna1Index == *i) a1Row = iter; if (antenna2Index == *i) a2Row = iter; } const size_t bandCount = _imageSet->BandCount(); for (size_t i = 0; i < bandCount; ++i) { const Gtk::TreeModel::iterator iter = _bandStore->append(); (*iter)[_bandModelColumns.bandIndex] = i; std::stringstream desc; BandInfo band = _imageSet->GetBandInfo(i); desc << Frequency::ToString(band.channels.front().frequencyHz); desc << " - "; desc << Frequency::ToString(band.channels.back().frequencyHz); (*iter)[_bandModelColumns.bandDescription] = desc.str(); if (i == bandIndex) bandRow = iter; } const size_t sequenceIdCount = _imageSet->SequenceCount(); size_t lastSeqIndex = 0; for (size_t i = 0; i < sequenceIdCount; ++i) { const Gtk::TreeModel::iterator iter = _sequenceStore->append(); (*iter)[_sequenceModelColumns.sequenceIndex] = i; std::stringstream desc; // Find some index that has this sequence. while (_sequences[lastSeqIndex].sequenceId != i) { ++lastSeqIndex; } std::optional index(_imageSet->Index( _sequences[lastSeqIndex].antenna1, _sequences[lastSeqIndex].antenna2, _sequences[lastSeqIndex].spw, i)); const size_t fIndex = _imageSet->GetField(*index); const FieldInfo field = _imageSet->GetFieldInfo(fIndex); desc << field.name << " (" << fIndex << ')'; (*iter)[_sequenceModelColumns.sequenceDescription] = desc.str(); if (i == sequenceIndex) sequenceRow = iter; } _antenna1View.set_model(_antennaeStore); _antenna1View.append_column("Index", _antennaModelColumns.antennaIndex); _antenna1View.append_column("Name", _antennaModelColumns.antennaName); _antenna1View.set_size_request(150, 512); _antenna1View.get_selection()->select(a1Row); _antenna1View.get_selection()->signal_changed().connect([&] { onChange(); }); _antenna1Scroll.add(_antenna1View); _antenna1Frame.add(_antenna1Scroll); _antenna1Scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); _hBox.pack_start(_antenna1Frame); _antenna2View.set_model(_antennaeStore); _antenna2View.append_column("Index", _antennaModelColumns.antennaIndex); _antenna2View.append_column("Name", _antennaModelColumns.antennaName); _antenna2View.set_size_request(150, 512); _antenna2View.get_selection()->select(a2Row); _antenna2View.get_selection()->signal_changed().connect([&] { onChange(); }); _antenna2Scroll.add(_antenna2View); _antenna2Frame.add(_antenna2Scroll); _antenna2Scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); _hBox.pack_start(_antenna2Frame); _bandView.set_model(_bandStore); _bandView.append_column("Index", _bandModelColumns.bandIndex); _bandView.append_column("Description", _bandModelColumns.bandDescription); //_bandView.set_size_request(-1, 512); _bandView.get_selection()->select(bandRow); _bandView.get_selection()->signal_changed().connect([&] { onChange(); }); _bandScroll.add(_bandView); _bandFrame.add(_bandScroll); _bandScroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); _bandFrameBox.pack_start(_bandFrame); _sequenceView.set_model(_sequenceStore); _sequenceView.append_column("Index", _sequenceModelColumns.sequenceIndex); _sequenceView.append_column("Source", _sequenceModelColumns.sequenceDescription); //_sequenceView.set_size_request(-1, 512); _sequenceView.get_selection()->select(sequenceRow); _sequenceView.get_selection()->signal_changed().connect([&] { onChange(); }); _sequenceScroll.add(_sequenceView); _sequenceFrame.add(_sequenceScroll); _sequenceScroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); _bandFrameBox.pack_start(_sequenceFrame); _hBox.pack_start(_bandFrameBox); _vBox.pack_start(_hBox); _hBottomBox.pack_start(_keepOpenCB, false, false); _hBottomBox.pack_start(_label); _loadButton.signal_clicked().connect( sigc::mem_fun(*this, &GoToWindow::onLoadClicked)); _buttonBox.pack_start(_loadButton); _hBottomBox.pack_end(_buttonBox); _vBox.pack_start(_hBottomBox, Gtk::PACK_SHRINK, 0); add(_vBox); _vBox.show_all(); onChange(); } GoToWindow::~GoToWindow() {} std::optional GoToWindow::getIndex() { const Glib::RefPtr a1 = _antenna1View.get_selection(); const Gtk::TreeModel::iterator iterA1 = a1->get_selected(); const Glib::RefPtr a2 = _antenna2View.get_selection(); const Gtk::TreeModel::iterator iterA2 = a2->get_selected(); const Glib::RefPtr b = _bandView.get_selection(); const Gtk::TreeModel::iterator iterB = b->get_selected(); const Glib::RefPtr s = _sequenceView.get_selection(); const Gtk::TreeModel::iterator iterS = s->get_selected(); if (iterA1 && iterA2 && iterB && iterS) { const Gtk::TreeModel::Row a1Row = *iterA1; const Gtk::TreeModel::Row a2Row = *iterA2; const Gtk::TreeModel::Row bRow = *iterB; const Gtk::TreeModel::Row sRow = *iterS; const size_t a1Index = a1Row[_antennaModelColumns.antennaIndex]; const size_t a2Index = a2Row[_antennaModelColumns.antennaIndex]; const size_t bIndex = bRow[_bandModelColumns.bandIndex]; const size_t sIndex = sRow[_sequenceModelColumns.sequenceIndex]; return _imageSet->Index(a1Index, a2Index, bIndex, sIndex); } return std::optional(); } void GoToWindow::onChange() { std::optional index = getIndex(); if (index) { const size_t a1Index = _imageSet->GetAntenna1(*index), a2Index = _imageSet->GetAntenna2(*index); const AntennaInfo a1 = _imageSet->GetAntennaInfo(a1Index), a2 = _imageSet->GetAntennaInfo(a2Index); const double distance = a1.position.Distance(a2.position); std::ostringstream str; str << a1.name + " x " + a2.name + " ("; if (distance < 1000) str << std::round(distance) << " m"; else str << std::round(distance / 100.0) / 10.0 << " km"; str << ")"; _label.set_text(str.str()); _loadButton.set_sensitive(true); } else { _loadButton.set_sensitive(false); } } void GoToWindow::onLoadClicked() { std::optional index = getIndex(); if (index) { _rfiGuiWindow.SetImageSetIndex(*index); if (!_keepOpenCB.get_active()) hide(); } } aoflagger-v3.4.0/rfigui/plotwindow.h0000644000175000017500000000212114507760372016174 0ustar olesoles#ifndef PLOTWINDOW_H #define PLOTWINDOW_H #include #include #include #include #include #include "../plot/plotwidget.h" class PlotWindow : public Gtk::Window { public: explicit PlotWindow(class PlotManager& plotManager); ~PlotWindow(); private: class PlotListColumns : public Gtk::TreeModel::ColumnRecord { public: PlotListColumns() { add(_index); add(_name); } Gtk::TreeModelColumn _index; Gtk::TreeModelColumn _name; } _plotListColumns; void onSelectedPlotChange(); void onClearPlotsPressed(); void onEditPlottingPropertiesPressed(); void onPlotPropertiesChanged(); void handleUpdate(); void updatePlotList(); PlotWidget _plotWidget; class PlotManager& _plotManager; Gtk::HBox _hBox; Gtk::VBox _sideBox; Gtk::Toolbar _toolbar; Gtk::ToolButton _clearButton, _editButton; Glib::RefPtr _plotListStore; Gtk::TreeView _plotListView; class PlotPropertiesWindow* _plotPropertiesWindow; }; #endif aoflagger-v3.4.0/rfigui/plotimage.h0000644000175000017500000000121414507760372015751 0ustar olesoles#ifndef PLOT_IMAGE_H #define PLOT_IMAGE_H #include "../plot/imageinterface.h" #include "../structures/image2d.h" class PlotImage final : public ImageInterface { public: PlotImage() : ImageInterface() {} PlotImage(const Image2DCPtr& image) : ImageInterface(image->Width(), image->Height(), image->Stride()), _image(image) {} PlotImage(Image2DCPtr&& image) : ImageInterface(image->Width(), image->Height(), image->Stride()), _image(std::move(image)) {} const float* Data() const override { return _image->Data(); } const Image2DCPtr& Get() const { return _image; } private: Image2DCPtr _image; }; #endif aoflagger-v3.4.0/rfigui/opendialog.cpp0000644000175000017500000002566414507760372016463 0ustar olesoles#include "opendialog.h" #include "rfiguiwindow.h" OpenDialog::OpenDialog(RFIGuiWindow& rfiGuiWindow) : _rfiGuiWindow(rfiGuiWindow), _selectButton("Select"), _unselectButton("Unselect"), // File tab elements _fileScroller(), _fileList(1, false, Gtk::SELECTION_SINGLE), // Options tab elements _dataColumnLabel("Data column: "), _otherColumnLabel("Other column: "), _combineSPWsCB("Combine SPWs"), _concatenateFrequency("Spectrally concatenate multiple measurement sets"), _readingModeLabel("Reading mode: "), _readingModeExplanation( "Set how the measurement set is read: in direct mode, the " "information for one baseline is gathered by scanning through the " "entire baseline " "each time a baseline is requested. It is the recommended mode " "for interactive experimentation. The indirect and memory modes " "reorder the baselines " "in a temporary file or memory, respectively, which takes time at " "the start, but allows " "faster browsing through the baselines."), _baselineAveragingCB("Average baselines together"), _baselineAveragingCombo(), _baIncludeAutosCB("Include auto-correlations"), _baIncludeFlaggedCB("Include flagged values"), _baNoDifference("Use sample values"), _baTimeDifference("Use time difference"), _baFrequencyDifference("Use frequency difference"), _intervalCB("Interval"), _intervalExplanation( "Limit the timeslots that are read. If only an interval start is " "entered, the data set is read to the end.") { get_content_area()->pack_start(_notebook); _notebook.append_page(_fileTab, "Files"); _fileChooser.signal_file_activated().connect([&]() { onSelectFile(); }); _fileChooser.set_size_request(800, 400); _fileTab.pack_start(_fileChooser); _unselectButton.set_hexpand(false); _unselectButton.set_vexpand(false); _unselectButton.set_sensitive(false); _unselectButton.signal_clicked().connect([&]() { onUnselectFile(); }); _fileButtonBox.pack_start(_unselectButton); _selectButton.set_hexpand(false); _selectButton.set_vexpand(false); _selectButton.signal_clicked().connect([&]() { onSelectFile(); }); _fileButtonBox.pack_end(_selectButton); _fileButtonBox.set_hexpand(false); _fileButtonBox.set_vexpand(false); _fileTab.pack_start(_fileButtonBox, false, false); _fileList.set_column_title(0, "Selected file(s)"); _fileList.set_size_request(0, 100); _fileList.get_selection()->signal_changed().connect( [&]() { onFileListSelectionChanged(); }); _fileScroller.add(_fileList); _fileTab.pack_start(_fileScroller); _notebook.append_page(_optionsTab, "Options"); _optionsTab.set_hexpand(true); _optionsTab.set_halign(Gtk::ALIGN_FILL); _optionsTab.set_column_spacing(15); _optionsTab.set_row_spacing(5); _optionsTab.set_margin_top(10); _optionsTab.set_margin_left(10); _optionsTab.set_margin_right(10); size_t gridRow = 0; initDataColumnButtons(gridRow); initReadingModeButtons(gridRow); initBaselineAveragingButtons(gridRow); _optionsTab.attach(_intervalCB, 0, gridRow, 1, 1); auto onChange = [&]() { const bool enabled = _intervalCB.get_active(); _intervalStartEntry.set_sensitive(enabled); _intervalEndEntry.set_sensitive(enabled); }; _intervalCB.signal_clicked().connect(onChange); onChange(); _intervalStartEntry.set_width_chars(5); _intervalStartEntry.set_text("0"); _intervalBox.pack_start(_intervalStartEntry, false, false, 5); _intervalEndEntry.set_width_chars(5); _intervalEndEntry.set_text("..."); _intervalBox.pack_start(_intervalEndEntry, false, false, 5); _optionsTab.attach(_intervalBox, 1, gridRow, 1, 1); ++gridRow; _intervalExplanation.set_max_width_chars(80); _intervalExplanation.set_line_wrap(true); _optionsTab.attach(_intervalExplanation, 0, gridRow, 2, 1); ++gridRow; _optionsTab.attach(_bottomButtonBox, 0, gridRow, 2, 1); ++gridRow; get_content_area()->show_all(); add_button("Cancel", Gtk::RESPONSE_CANCEL); _openButton = add_button("Open", Gtk::RESPONSE_OK); _openButton->set_sensitive(false); } void OpenDialog::initDataColumnButtons(size_t& gridRow) { _optionsTab.attach(_dataColumnLabel, 0, gridRow, 1, 1); _dataColumnCombo.append("DATA"); _dataColumnCombo.append("CORRECTED_DATA"); _dataColumnCombo.append("MODEL_DATA"); _dataColumnCombo.append("other..."); _dataColumnCombo.signal_changed().connect([&]() { const bool isOther = _dataColumnCombo.get_active_row_number() == 3; _otherColumnLabel.set_sensitive(isOther); _otherColumnEntry.set_sensitive(isOther); }); _dataColumnCombo.set_active(0); _dataColumnCombo.set_hexpand(true); _dataColumnCombo.set_halign(Gtk::ALIGN_FILL); _optionsTab.attach(_dataColumnCombo, 1, gridRow, 1, 1); _otherColumnLabel.set_halign(Gtk::ALIGN_END); _otherColumnGrid.attach(_otherColumnLabel, 0, 0, 1, 1); _otherColumnEntry.set_hexpand(true); _otherColumnEntry.set_halign(Gtk::ALIGN_FILL); _otherColumnGrid.attach(_otherColumnEntry, 1, 0, 1, 1); _otherColumnGrid.set_margin_bottom(10); _optionsTab.attach(_otherColumnGrid, 1, gridRow + 1, 1, 1); gridRow += 2; _optionsTab.attach(_combineSPWsCB, 0, gridRow, 2, 1); _combineSPWsCB.signal_toggled().connect([&] { // The Combine SPWs and Concatenate Frequency are mutually exclusive. _concatenateFrequency.set_sensitive(!_combineSPWsCB.get_active()); }); ++gridRow; _optionsTab.attach(_concatenateFrequency, 0, gridRow, 2, 1); _concatenateFrequency.signal_toggled().connect([&] { // The Combine SPWs and Concatenate Frequency are mutually exclusive. _combineSPWsCB.set_sensitive(!_concatenateFrequency.get_active()); }); ++gridRow; _optionsTab.attach(_columnSeparator, 0, gridRow, 4, 1); ++gridRow; } void OpenDialog::initReadingModeButtons(size_t& gridRow) { _readingModeLabel.set_hexpand(false); _optionsTab.attach(_readingModeLabel, 0, gridRow, 1, 1); _optionsTab.attach(_readingModeCombo, 1, gridRow, 1, 1); ++gridRow; _readingModeCombo.append("Direct"); _readingModeCombo.append("Indirect"); _readingModeCombo.append("Memory"); _readingModeCombo.set_active(0); _readingModeExplanation.set_line_wrap(true); _readingModeExplanation.set_max_width_chars(80); _readingModeExplanation.set_margin_bottom(10); _optionsTab.attach(_readingModeExplanation, 0, gridRow, 2, 1); ++gridRow; _optionsTab.attach(_readingSeparator, 0, gridRow, 2, 1); ++gridRow; } void OpenDialog::initBaselineAveragingButtons(size_t& gridRow) { _optionsTab.attach(_baselineAveragingCB, 0, gridRow, 2, 1); auto onChange = [&]() { const bool enabled = _baselineAveragingCB.get_active(); _baselineAveragingCombo.set_sensitive(enabled); _baIncludeAutosCB.set_sensitive(enabled); _baIncludeFlaggedCB.set_sensitive(enabled); _baNoDifference.set_sensitive(enabled); _baTimeDifference.set_sensitive(enabled); _baFrequencyDifference.set_sensitive(enabled); }; _baselineAveragingCB.signal_clicked().connect(onChange); onChange(); ++gridRow; _baselineAveragingCombo.append("Normal average"); _baselineAveragingCombo.append("Average of absolute values"); _baselineAveragingCombo.append("Average of squared values"); _baselineAveragingCombo.append("Standard deviation"); _baselineAveragingCombo.set_active(0); _optionsTab.attach(_baselineAveragingCombo, 1, gridRow, 1, 1); ++gridRow; _optionsTab.attach(_baIncludeAutosCB, 1, gridRow, 1, 1); ++gridRow; _optionsTab.attach(_baIncludeFlaggedCB, 1, gridRow, 1, 1); ++gridRow; Gtk::RadioButton::Group group; _baNoDifference.set_group(group); _baTimeDifference.set_group(group); _baFrequencyDifference.set_group(group); _optionsTab.attach(_baNoDifference, 1, gridRow, 1, 1); ++gridRow; _optionsTab.attach(_baTimeDifference, 1, gridRow, 1, 1); ++gridRow; _optionsTab.attach(_baFrequencyDifference, 1, gridRow, 1, 1); ++gridRow; _optionsTab.attach(_baselineAveragingSeparator, 0, gridRow, 2, 1); ++gridRow; } void OpenDialog::SetSelection(const std::vector& selection) { _selection = selection; _fileList.clear_items(); for (const std::string& f : _selection) _fileList.append(f); _openButton->set_sensitive(!_selection.empty()); } void OpenDialog::onSelectFile() { _selection.push_back(_fileChooser.get_file()->get_path()); _fileList.append(_selection.back()); _openButton->set_sensitive(true); } void OpenDialog::onUnselectFile() { const std::vector unselectList = _fileList.get_selected(); for (std::vector::const_reverse_iterator i = unselectList.rbegin(); i != unselectList.rend(); ++i) { _selection.erase(_selection.begin() + *i); } _fileList.clear_items(); for (const std::string& f : _selection) _fileList.append(f); _openButton->set_sensitive(!_selection.empty()); } void OpenDialog::onFileListSelectionChanged() { const bool hasSelection = _fileList.get_selection()->count_selected_rows() != 0; _unselectButton.set_sensitive(hasSelection); } MSOptions OpenDialog::GetOptions() const { MSOptions options; switch (_readingModeCombo.get_active_row_number()) { case 0: options.ioMode = DirectReadMode; break; case 1: options.ioMode = ReorderingReadMode; break; case 2: options.ioMode = MemoryReadMode; break; } options.combineSPWs = _combineSPWsCB.get_active(); options.concatenateFrequency = _concatenateFrequency.get_active(); options.dataColumnName = _dataColumnCombo.get_active_text(); if (options.dataColumnName == "other...") options.dataColumnName = _otherColumnEntry.get_text(); if (_intervalCB.get_active()) { options.intervalStart = atoi(_intervalStartEntry.get_text().c_str()); const std::string endStr = _intervalEndEntry.get_text(); if (!endStr.empty() && endStr != "...") options.intervalEnd = atoi(_intervalEndEntry.get_text().c_str()); } options.baselineIntegration.enable = _baselineAveragingCB.get_active(); options.baselineIntegration.withAutos = _baIncludeAutosCB.get_active(); options.baselineIntegration.withFlagged = _baIncludeFlaggedCB.get_active(); options.baselineIntegration.mode = BaselineIntegration::Average; switch (_baselineAveragingCombo.get_active_row_number()) { case 0: options.baselineIntegration.mode = BaselineIntegration::Average; break; case 1: options.baselineIntegration.mode = BaselineIntegration::AverageAbs; break; case 2: options.baselineIntegration.mode = BaselineIntegration::Squared; break; case 3: options.baselineIntegration.mode = BaselineIntegration::Stddev; break; } if (_baTimeDifference.get_active()) options.baselineIntegration.differencing = BaselineIntegration::TimeDifference; else if (_baFrequencyDifference.get_active()) options.baselineIntegration.differencing = BaselineIntegration::FrequencyDifference; else options.baselineIntegration.differencing = BaselineIntegration::NoDifference; return options; } aoflagger-v3.4.0/rfigui/maskedheatmap.cpp0000644000175000017500000002204314507760372017132 0ustar olesoles#include "maskedheatmap.h" #include "../algorithms/thresholdconfig.h" #include #include using algorithms::ThresholdConfig; MaskedHeatMap::MaskedHeatMap() : _showOriginalMask(true), _showAlternativeMask(true), _highlighting(false), _highlightConfig(new ThresholdConfig()), _manualXAxisDescription(false), _manualYAxisDescription(false), _manualZAxisDescription(false) { _highlightConfig->InitializeLengthsSingleSample(); SetCairoFilter(Cairo::FILTER_NEAREST); SignalDrawImage().connect( [&](const Cairo::RefPtr& surface) { signalDrawImage(surface); }); } MaskedHeatMap::~MaskedHeatMap() {} void MaskedHeatMap::Clear() { _originalMask.reset(); _alternativeMask.reset(); _segmentedImage.reset(); _highlightConfig.reset(new ThresholdConfig()); _highlightConfig->InitializeLengthsSingleSample(); _metaData.reset(); HeatMap::Clear(); } Mask2DCPtr MaskedHeatMap::GetActiveMask() const { if (!HasImage()) throw std::runtime_error("GetActiveMask() called without image"); const bool originalActive = _showOriginalMask && _originalMask; const bool altActive = _showAlternativeMask && _alternativeMask; if (originalActive) { if (altActive) { Mask2DPtr mask = Mask2D::MakePtr(*_originalMask); mask->Join(*_alternativeMask); return mask; } else { return _originalMask; } } else { if (altActive) return _alternativeMask; else return Mask2D::CreateSetMaskPtr(Image().Width(), Image().Height()); } } TimeFrequencyMetaDataCPtr MaskedHeatMap::GetSelectedMetaData() const { TimeFrequencyMetaDataCPtr metaData = _metaData; if (metaData) { if (XZoomStart() != 0 && metaData->HasObservationTimes()) { size_t startTime = std::round(XZoomStart() * Image().Width()); TimeFrequencyMetaData* newData = new TimeFrequencyMetaData(*metaData); metaData = TimeFrequencyMetaDataCPtr(newData); std::vector obsTimes = newData->ObservationTimes(); obsTimes.erase(obsTimes.begin(), obsTimes.begin() + startTime); newData->SetObservationTimes(obsTimes); } if (YZoomStart() != 0 && metaData->HasBand()) { size_t startChannel = std::round(YZoomStart() * Image().Height()); TimeFrequencyMetaData* newData = new TimeFrequencyMetaData(*metaData); metaData = TimeFrequencyMetaDataCPtr(newData); BandInfo band = newData->Band(); band.channels.erase(band.channels.begin(), band.channels.begin() + startChannel); newData->SetBand(band); } } return metaData; } void MaskedHeatMap::SetMetaData(const TimeFrequencyMetaDataCPtr& metaData) { _metaData = metaData; if (_metaData) { if (_metaData->HasObservationTimes()) { SetXAxisMin(_metaData->ObservationTimes().front()); SetXAxisMax(_metaData->ObservationTimes().back()); SetXAxisDescription("Time (UTC, hh:mm:ss)"); } if (_metaData->HasBand() && !_metaData->Band().channels.empty()) { SetYAxisMin(_metaData->Band().channels.front().frequencyHz * 1e-6); SetYAxisMax(_metaData->Band().channels.back().frequencyHz * 1e-6); SetYAxisDescription("Frequency (MHz)"); } if (!_manualZAxisDescription && !_metaData->ValueDescription().empty()) { std::string description = _metaData->ValueDescription(); if (!_metaData->ValueUnits().empty()) description = description + " (" + _metaData->ValueUnits() + ")"; SetZAxisDescription(description); } } } void MaskedHeatMap::signalDrawImage( const Cairo::RefPtr& surface) const { Mask2DCPtr mask = GetActiveMask(); Mask2DCPtr originalMask = _originalMask; Mask2DCPtr alternativeMask = _alternativeMask; Mask2DPtr highlightMask; if (_highlighting) { highlightMask = Mask2D::CreateSetMaskPtr(Image().Width(), Image().Height()); _highlightConfig->Execute(GetImage2D().get(), highlightMask.get(), true, 10.0, 10.0); } const size_t xFactor = ImageToSurfaceXFactor(); if (xFactor > 1) { mask = Mask2D::MakePtr(mask->ShrinkHorizontally(xFactor)); if (originalMask) { originalMask = Mask2D::MakePtr(originalMask->ShrinkHorizontally(xFactor)); } if (alternativeMask) { alternativeMask = Mask2D::MakePtr(alternativeMask->ShrinkHorizontally(xFactor)); } if (highlightMask) { highlightMask = Mask2D::MakePtr(highlightMask->ShrinkHorizontally(xFactor)); } } const size_t yFactor = ImageToSurfaceYFactor(); if (yFactor > 1) { mask = Mask2D::MakePtr(mask->ShrinkVertically(yFactor)); if (originalMask) { originalMask = Mask2D::MakePtr(originalMask->ShrinkVertically(yFactor)); } if (alternativeMask) { alternativeMask = Mask2D::MakePtr(alternativeMask->ShrinkVertically(yFactor)); } if (highlightMask) { highlightMask = Mask2D::MakePtr(highlightMask->ShrinkVertically(yFactor)); } } const bool originalActive = _showOriginalMask && originalMask; const bool altActive = _showAlternativeMask && alternativeMask; int orMaskR, orMaskG, orMaskB; int altMaskR, altMaskG, altMaskB; if (GetColorMap() == ColorMap::Viridis) { orMaskR = 0; orMaskG = 0; orMaskB = 0; altMaskR = 255; altMaskG = 255; altMaskB = 255; } else { orMaskR = 255; orMaskG = 0; orMaskB = 255; altMaskR = 255; altMaskG = 255; altMaskB = 0; } unsigned char* data = surface->get_data(); const size_t rowStride = surface->get_stride(); const std::array imageXRange = ImageXRange(); const std::array imageYRange = ImageYRange(); const std::array surfaceXRange = {imageXRange[0] / xFactor, imageXRange[1] / xFactor}; const std::array surfaceYRange = {imageYRange[0] / yFactor, imageYRange[1] / yFactor}; if (_highlighting || originalActive || altActive) { for (size_t y = surfaceYRange[0]; y != surfaceYRange[1]; ++y) { guint8* rowpointer = data + rowStride * (surfaceYRange[1] - y - 1); for (size_t x = surfaceXRange[0]; x != surfaceXRange[1]; ++x) { const size_t xa = (x - surfaceXRange[0]) * 4; if (_highlighting && highlightMask->Value(x, y)) { rowpointer[xa + 0] = 0; rowpointer[xa + 1] = 0; rowpointer[xa + 2] = 255; rowpointer[xa + 3] = 255; } else if (originalActive && originalMask->Value(x, y)) { rowpointer[xa + 0] = orMaskB; rowpointer[xa + 1] = orMaskG; rowpointer[xa + 2] = orMaskR; rowpointer[xa + 3] = 255; } else if (altActive && alternativeMask->Value(x, y)) { rowpointer[xa + 0] = altMaskB; rowpointer[xa + 1] = altMaskG; rowpointer[xa + 2] = altMaskR; rowpointer[xa + 3] = 255; } } } } if (xFactor == 1 && yFactor == 1 && _segmentedImage != nullptr) { for (size_t y = imageYRange[0]; y < imageXRange[1]; ++y) { guint8* rowpointer = data + rowStride * (imageXRange[1] - y - 1); for (size_t x = imageXRange[0]; x < imageXRange[1]; ++x) { if (_segmentedImage->Value(x, y) != 0) { int xa = (x - imageXRange[0]) * 4; rowpointer[xa] = IntMap::R(_segmentedImage->Value(x, y)); rowpointer[xa + 1] = IntMap::G(_segmentedImage->Value(x, y)); rowpointer[xa + 2] = IntMap::B(_segmentedImage->Value(x, y)); rowpointer[xa + 3] = IntMap::A(_segmentedImage->Value(x, y)); } } } } } void MaskedHeatMap::SaveByExtension(const std::string& filename, size_t width, size_t height) { const char* eMsg = "Saving image to file failed: could not determine file type from " "filename extension -- maybe the type is not supported. Supported types " "are .png, .svg or .pdf."; if (filename.size() < 4) throw std::runtime_error(eMsg); std::string ext = filename.substr(filename.size() - 4); boost::to_lower(ext); if (ext == ".png") SavePng(filename, width, height); else if (ext == ".svg") SaveSvg(filename, width, height); else if (ext == ".pdf") SavePdf(filename, width, height); else throw std::runtime_error(eMsg); } void MaskedHeatMap::SaveText(const std::string& filename) const { if (HasImage()) { const Image2DCPtr image = GetImage2D(); const size_t startX = (size_t)std::round(XZoomStart() * image->Width()); const size_t startY = (size_t)std::round(YZoomStart() * image->Height()); const size_t endX = (size_t)std::round(XZoomEnd() * image->Width()); const size_t endY = (size_t)std::round(YZoomEnd() * image->Height()); const size_t imageWidth = endX - startX; const size_t imageHeight = endY - startY; std::ofstream file(filename.c_str()); file << imageWidth << '\n' << imageHeight << '\n'; for (size_t y = startY; y != endY; ++y) { for (size_t x = startX; x != endX; ++x) { file << image->Value(x, y) << '\n'; } } } } aoflagger-v3.4.0/rfigui/strategyeditor.h0000644000175000017500000000172614507760372017051 0ustar olesoles#ifndef STRATEGY_EDITOR_H #define STRATEGY_EDITOR_H #include #include class StrategyEditor : public Gtk::ScrolledWindow { public: StrategyEditor(); void SetText(const std::string& text); std::string GetText() const; void HighlightLine(size_t index) { _highlightLine = index; updateHighlighting(); } void ResetChangedStatus() { _isChanged = false; } bool IsChanged() { return _isChanged; } private: struct ParseInfo { enum { Clear, FunctionStart } state; }; Gtk::TextView _text; Glib::RefPtr _tagKeyword, _tagComment, _tagString, _tagFunctionName, _tagHighlight; void parseWord(ParseInfo& p, Gtk::TextBuffer::iterator start, Gtk::TextBuffer::iterator end); void updateChanges() { _highlightLine = 0; updateHighlighting(); _isChanged = true; } void updateHighlighting(); std::size_t _highlightLine; bool _isChanged; }; #endif aoflagger-v3.4.0/rfigui/timefrequencywidget.h0000644000175000017500000000270414507760372020061 0ustar olesoles#ifndef TIME_FREQUENCY_WIDGET_H #define TIME_FREQUENCY_WIDGET_H #include "../rfigui/maskedheatmap.h" #include "../plot/plotwidget.h" #include "../plot/xyplot.h" #include class TimeFrequencyWidget : public Gtk::VBox { public: explicit TimeFrequencyWidget(MaskedHeatMap& plot) : _heatMap() { _heatMap.SetPlot(plot); _timePlotWidget.SetPlot(_timePlot); _timePlotWidget.set_size_request(200, 60); _timePlot.XAxis().SetShow(false); pack_start(_timePlotWidget, Gtk::PACK_EXPAND_WIDGET); EnableTimePlot(); GetMaskedHeatMap().SetShowTitle(true); _heatMap.set_size_request(200, 200); pack_start(_heatMap, Gtk::PACK_EXPAND_WIDGET); _heatMap.show(); } void Update() { _heatMap.Update(); _timePlotWidget.Update(); } bool HasImage() const { return GetMaskedHeatMap().HasImage(); } PlotWidget& GetHeatMapWidget() { return _heatMap; } MaskedHeatMap& GetMaskedHeatMap() { return static_cast(_heatMap.Plot()); } const MaskedHeatMap& GetMaskedHeatMap() const { return static_cast(_heatMap.Plot()); } void EnableTimePlot() { _timePlot.LinkHorizontally(_heatMap.Plot()); _timePlotWidget.show(); Update(); } void DisableTimePlot() { _timePlotWidget.hide(); _timePlot.UnlinkHorizontally(); } XYPlot& TimePlot() { return _timePlot; } private: PlotWidget _heatMap; PlotWidget _timePlotWidget; XYPlot _timePlot; }; #endif aoflagger-v3.4.0/rfigui/simulatedialog.h0000644000175000017500000000205314507760372016775 0ustar olesoles#ifndef SIMULATE_WINDOW_H #define SIMULATE_WINDOW_H #include #include #include #include #include #include #include #include "../structures/timefrequencydata.h" class SimulateDialog : public Gtk::Dialog { public: SimulateDialog(); ~SimulateDialog() {} TimeFrequencyData Make() const; private: void onSimulateClicked(); void onCloseClicked(); Gtk::Grid _grid; Gtk::Label _nTimesLabel; Gtk::Entry _nTimesEntry; Gtk::Label _nChannelsLabel; Gtk::Entry _nChannelsEntry; Gtk::Label _bandwidthLabel; Gtk::Entry _bandwidthEntry; Gtk::Label _polarizationsLabel; Gtk::ComboBoxText _polarizationsSelection; Gtk::Label _targetLabel; Gtk::ComboBoxText _targetSelection; Gtk::Label _noiseLabel; Gtk::ComboBoxText _noiseSelection; Gtk::Label _noiseLevelLabel; Gtk::Entry _noiseLevelEntry; Gtk::Label _rfiLabel; Gtk::ComboBoxText _rfiSelection; Gtk::Button* _simulateButton; }; #endif // IMAGEPROPERTIESWINDOW_H aoflagger-v3.4.0/rfigui/settings.cpp0000644000175000017500000000631314507760372016170 0ustar olesoles#include "settings.h" #include #include #include #include #include "../lua/default-strategy.h" #include "../util/logger.h" Settings::Settings() { initStrArray("recent-files", std::vector(10)); initStrArray("recent-strategies", std::vector(10)); } std::string Settings::getConfigFilename() { return (std::filesystem::path(GetConfigDir()) / "settings").string(); } std::string Settings::GetStrategyFilename() const { return (std::filesystem::path(GetConfigDir()) / "strategy.lua").string(); } std::string Settings::GetConfigDir() { std::filesystem::path configPath = std::filesystem::path(Glib::get_user_config_dir()) / "aoflagger"; if (!std::filesystem::is_directory(configPath)) { // We don't want to crash if the dir can't be created; we will just report // an error to the cmd line try { std::filesystem::create_directories(configPath); } catch (std::exception& exception) { Logger::Error << "Failed to create config directory: " << exception.what() << '\n'; } } return configPath.string(); } void Settings::InitializeWorkStrategy() { std::string filename = GetStrategyFilename(); std::ofstream str(filename); str.write(reinterpret_cast(data_strategies_generic_default_lua), data_strategies_generic_default_lua_len); if (!str) throw std::runtime_error( "Failed to write working file for Lua strategy: " + filename + ", size " + std::to_string(data_strategies_generic_default_lua_len)); } void Settings::Load() { std::string configFilename = getConfigFilename(); if (std::filesystem::exists(configFilename)) { std::ifstream file(configFilename); std::string line; std::getline(file, line); while (file) { boost::algorithm::trim(line); if (!line.empty() && line[0] != '#') { size_t sep = line.find('='); if (sep == std::string::npos) throw std::runtime_error("Invalid key-value pair in config file " + configFilename); std::string key = boost::algorithm::trim_copy(line.substr(0, sep)); std::string value = boost::algorithm::trim_copy(line.substr(sep + 1)); if (key.empty() || value.empty()) throw std::runtime_error("Empty key or value in config file " + configFilename); set(key, value); } std::getline(file, line); } } } void Settings::Save() const { std::string configFilename = getConfigFilename(); std::ofstream file(configFilename); if (!file) throw std::runtime_error("Error opening config file: " + configFilename); file << "# This is the user settings file for the AOFlagger software package\n" "# Any unchanged settings will be preceded by a hash symbol (#)\n" "# Some of these settings can be found in the 'rfigui' application " "under\n" "# menu 'edit', option 'preferences'.\n" "\n"; for (const auto& item : _settings) { if (!item.second.HasValue()) file << "# "; file << item.first << '=' << item.second.ValueOrDefault().ValueToString() << '\n'; } } aoflagger-v3.4.0/rfigui/rfiguimenu.h0000644000175000017500000003264014507760372016151 0ustar olesoles#include "../structures/timefrequencydata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class RFIGuiMenu { public: RFIGuiMenu(); Gtk::MenuBar& Menu() { return _menuBar; } Gtk::Toolbar& Toolbar() { return _toolbar; } // File sigc::signal OnOpen; sigc::signal OnOpenRecent; sigc::signal OnSaveBaselineFlags, OnExportBaseline, OnClose, OnQuit, OnAbout; // View sigc::signal OnViewMode, OnViewData, OnViewStrategy, OnViewTimePlot, OnImagePropertiesPressed, OnToggleFlags, OnHightlightPressed; sigc::signal OnZoomFit, OnZoomIn, OnZoomOut, OnZoomSelect; sigc::signal OnShowStats; // Strategy sigc::signal OnExecutePythonStrategy, OnExecuteLuaStrategy, OnStrategyNewEmpty, OnStrategyNewTemplate, OnStrategyNewDefault, OnStrategyOpen; sigc::signal OnStrategyOpenDefault; sigc::signal OnStrategySave, OnStrategySaveAs; // Plot sigc::signal OnPlotDistPressed; sigc::signal OnPlotLogLogDistPressed; sigc::signal OnPlotMeanSpectrumPressed; sigc::signal OnPlotSumSpectrumPressed; sigc::signal OnPlotPowerSpectrumPressed; sigc::signal OnPlotFrequencyScatterPressed; sigc::signal OnPlotTimeMeanPressed; sigc::signal OnPlotTimeScatterPressed; sigc::signal OnPlotSingularValuesPressed; // Browse sigc::signal OnLoadPrevious; sigc::signal OnReloadPressed; sigc::signal OnLoadNext; sigc::signal OnGoToPressed; sigc::signal OnLoadLongestBaselinePressed; sigc::signal OnLoadShortestBaselinePressed; sigc::signal OnLoadMedianBaselinePressed; // Simulate sigc::signal OnOpenTestSetA; sigc::signal OnOpenTestSetB; sigc::signal OnOpenTestSetC; sigc::signal OnOpenTestSetD; sigc::signal OnOpenTestSetE; sigc::signal OnOpenTestSetF; sigc::signal OnOpenTestSetG; sigc::signal OnOpenTestSetH; sigc::signal OnOpenTestSetNoise; sigc::signal OnAddStaticFringe; sigc::signal OnAdd1SigmaFringe; sigc::signal OnSetToOne; sigc::signal OnSetToI; sigc::signal OnSetToOnePlusI; sigc::signal OnAddCorrelatorFault; sigc::signal OnAddNaNs; sigc::signal OnMultiplyData; sigc::signal OnSimulate; // Data sigc::signal OnVisualizedToOriginalPressed; sigc::signal OnKeepRealPressed; sigc::signal OnKeepImaginaryPressed; sigc::signal OnKeepPhasePressed; sigc::signal OnUnrollPhaseButtonPressed; sigc::signal OnKeepStokesIPressed; sigc::signal OnKeepStokesQPressed; sigc::signal OnKeepStokesUPressed; sigc::signal OnKeepStokesVPressed; sigc::signal OnKeepRRPressed; sigc::signal OnKeepRLPressed; sigc::signal OnKeepLRPressed; sigc::signal OnKeepLLPressed; sigc::signal OnKeepXXPressed; sigc::signal OnKeepXYPressed; sigc::signal OnKeepYXPressed; sigc::signal OnKeepYYPressed; sigc::signal OnStoreData; sigc::signal OnRecallData; sigc::signal OnSubtractDataFromMem; sigc::signal OnClearOriginalFlagsPressed; sigc::signal OnClearAltFlagsPressed; sigc::signal OnTemporalAveragingPressed; sigc::signal OnSpectralAveragingPressed; // Segmentation sigc::signal OnSegment; sigc::signal OnCluster; sigc::signal OnClassify; sigc::signal OnRemoveSmallSegments; // Toolbar signals (some are already covered) sigc::signal OnTogglePolarizations; sigc::signal OnToggleImage; sigc::signal OnSelectImage; sigc::signal openTestSet; bool OriginalFlagsActive() const { return _tbOriginalFlags.get_active(); } bool AlternativeFlagsActive() const { return _tbAlternativeFlags.get_active(); } void SetOriginalFlagsActive(bool originalFlags) { _tbOriginalFlags.set_active(originalFlags); } void SetAlternativeFlagsActive(bool alternativeFlags) { _tbAlternativeFlags.set_active(alternativeFlags); } bool ShowPPActive() const { return _tbDisplayPP.get_active(); } bool ShowPQActive() const { return _tbDisplayPQ.get_active(); } bool ShowQPActive() const { return _tbDisplayQP.get_active(); } bool ShowQQActive() const { return _tbDisplayQQ.get_active(); } bool ViewTimePlot() const { return _miViewTimePlot.get_active(); } void SetShowPPActive(bool active) { _tbDisplayPP.set_active(active); } void SetShowPQActive(bool active) { _tbDisplayPQ.set_active(active); } void SetShowQPActive(bool active) { _tbDisplayQP.set_active(active); } void SetShowQQActive(bool active) { _tbDisplayQQ.set_active(active); } void SetShowPPSensitive(bool sensitive) { _tbDisplayPP.set_sensitive(sensitive); } void SetShowPQSensitive(bool sensitive) { _tbDisplayPQ.set_sensitive(sensitive); } void SetShowQPSensitive(bool sensitive) { _tbDisplayQP.set_sensitive(sensitive); } void SetShowQQSensitive(bool sensitive) { _tbDisplayQQ.set_sensitive(sensitive); } void SetZoomToFitSensitive(bool sensitive) { _tbZoomFit.set_sensitive(sensitive); } void SetZoomOutSensitive(bool sensitive) { _tbZoomOut.set_sensitive(sensitive); } void SetZoomInSensitive(bool sensitive) { _tbZoomIn.set_sensitive(sensitive); } void SetPreviousSensitive(bool sensitive) { _tbPrevious.set_sensitive(sensitive); } void SetNextSensitive(bool sensitive) { _tbNext.set_sensitive(sensitive); } void SetReloadSensitive(bool sensitive) { _tbReload.set_sensitive(sensitive); } void SetSelectVisualizationSensitive(bool sensitive) { _tbSelectVisualization.set_sensitive(sensitive); } void SetRecentFiles(const std::vector& recentFiles); void SetStrategyDefaults(const std::vector& recentFiles); Gtk::Menu& VisualizationMenu() { return _tfVisualizationMenu; } void BlockVisualizationSignals() { _blockVisualizationSignals = true; } void UnblockVisualizationSignals() { _blockVisualizationSignals = false; } void EnableRunButtons(bool sensitive); void ActivateDataMode() { _miViewData.activate(); } void ActivateStrategyMode() { _miViewStrategy.activate(); } private: struct ImgMenuItem { Gtk::ImageMenuItem item; Gtk::HBox box; Gtk::AccelLabel label; Gtk::Image image; }; void topMenu(Gtk::Menu& menu, Gtk::MenuItem& item, const char* label) { item.set_submenu(menu); item.set_label(label); item.set_use_underline(true); _menuBar.append(item); } void addItem(Gtk::Menu& menu, Gtk::SeparatorMenuItem& sep) { menu.append(sep); } void addItem(Gtk::Menu& menu, Gtk::MenuItem& item, const char* label) { item.set_label(label); item.set_use_underline(true); menu.append(item); } void addItem(Gtk::Menu& menu, ImgMenuItem& item, const char* label, const char* icon) { item.image.set_from_icon_name(icon, Gtk::BuiltinIconSize::ICON_SIZE_MENU); item.item.set_label(label); item.item.set_use_underline(true); item.item.set_image(item.image); menu.append(item.item); } template void addItem(Gtk::Menu& menu, Gtk::MenuItem& item, const SigType& sig, const char* label) { item.set_label(label); item.set_use_underline(true); item.signal_activate().connect(sig); menu.append(item); } template void addItem(Gtk::Menu& menu, ImgMenuItem& item, const SigType& sig, const char* label, const char* icon) { // item.box.set_halign(Gtk::ALIGN_START); item.image.set_from_icon_name(icon, Gtk::BuiltinIconSize::ICON_SIZE_MENU); // item.box.pack_start(item.image); // item.label.set_label(label); // item.box.pack_start(item.label); item.item.set_label(label); item.item.set_use_underline(true); item.item.set_image(item.image); item.item.signal_activate().connect(sig); // item.item.add(item.box); menu.append(item.item); } template void addTool(Gtk::ToolButton& tool, const SigType& sig, const char* label, const char* tooltip, const char* icon) { tool.set_label(label); tool.set_tooltip_text(tooltip); tool.set_icon_name(icon); tool.signal_clicked().connect(sig); _toolbar.append(tool); } void tooltip(ImgMenuItem& item, const char* tooltipStr) {} void onTBModeData(); void onTBModeStrategy(); void onMIViewData(); void onMIViewStrategy(); void makeFileMenu(); void makeViewMenu(); void makeStrategyMenu(); void makePlotMenu(); void makeBrowseMenu(); void makeSimulateMenu(); void makeDataMenu(); void makeSegmentationMenu(); void makeToolbarActions(); Gtk::MenuBar _menuBar; Gtk::Toolbar _toolbar; Gtk::Menu _menuFile, _menuView, _menuStrategy, _menuPlot, _menuBrowse, _menuSimulate, _menuData, _menuSelectComplex, _menuSelectStokes, _menuSelectCircular, _menuSelectLinear, _menuSegmentation, _menuRecentFiles; Gtk::MenuItem _miFile, _miView, _miStrategy, _miPlot, _miBrowse, _miSimulateMenu, _miData; ImgMenuItem _miRecentFiles; // File menu Gtk::SeparatorMenuItem _miFileSep1, _miFileSep2, _miFileSep3; ImgMenuItem _miFileOpen; ImgMenuItem _miSaveBaselineFlags; Gtk::MenuItem _miFileExportBaseline; ImgMenuItem _miFileClose, _miHelpAbout, _miFileQuit; std::vector _miRecentFileChoices; // View menu Gtk::RadioButtonGroup _viewModeGroup; Gtk::Menu _menuViewMode; Gtk::MenuItem _miViewMode; Gtk::RadioMenuItem _miViewData, _miViewStrategy; Gtk::MenuItem _miViewProperties; Gtk::CheckMenuItem _miViewTimePlot; ImgMenuItem _miViewOriginalFlags, _miViewAlternativeFlags; Gtk::SeparatorMenuItem _miViewSep1, _miViewSep2, _miViewSep3; ImgMenuItem _miViewZoomFit, _miViewZoomIn, _miViewZoomOut; Gtk::MenuItem _miViewSelectZoom; Gtk::MenuItem _miViewStats; // Strategy menu Gtk::SeparatorMenuItem _miStrategySep1, _miStrategySep2, _miStrategySep3, _miStrategySep4; ImgMenuItem _miStrategyNew, _miStrategyOpen, _miStrategyOpenDefault, _miStrategySave, _miStrategySaveAs; Gtk::Menu _menuStrategyNew, _menuStrategyOpenDefault; std::vector _miStrategyDefaults; Gtk::MenuItem _miStrategyNewEmpty, _miStrategyNewTemplate, _miStrategyNewDefault; ImgMenuItem _miExecuteLuaStrategy; Gtk::MenuItem _miExecutePythonStrategy; // Plot menu Gtk::MenuItem _miPlotTime, _miPlotFrequency; Gtk::Menu _menuPlotTime, _menuPlotFrequency; Gtk::MenuItem _miPlotDistribution, _miPlotLogLogDistribution, _miPlotMeanSpectrum; Gtk::MenuItem _miPlotSumSpectrum, _miPlotPowerSpectrum, _miPlotFrequencyScatter, _miPlotTimeMean; Gtk::MenuItem _miPlotTimeScatter, _miPlotSingularValues; // Browse menu Gtk::SeparatorMenuItem _miBrowseSep1, _miBrowseSep2; ImgMenuItem _miBrowsePrevious, _miBrowseReload, _miBrowseNext; Gtk::MenuItem _miBrowseGoto, _miBrowseLongestBaseline, _miBrowseMedianBaseline, _miBrowseShortestBaseline; // Simulate menu Gtk::MenuItem _miSimulate; Gtk::Menu _menuTestSets; Gtk::MenuItem _miTestSetSubMenu; Gtk::MenuItem _miTestA, _miTestB, _miTestC, _miTestD, _miTestE; Gtk::MenuItem _miTestF, _miTestG, _miTestH, _miTestNoise; Gtk::Menu _menuModify; Gtk::MenuItem _miSimulateModify; Gtk::MenuItem _miModifyStaticFringe, _miModify1SigmaStaticFringe; Gtk::MenuItem _miModifyToOne, _miModifyToI, _miModifyToOnePlusI; Gtk::MenuItem _miModifyCorrelatorFault, _miModifyAddNaNs, _miModifyMultiply; Gtk::SeparatorMenuItem _miSimSep1, _miSimSep2; // Data menu Gtk::MenuItem _miDataToOriginal; Gtk::SeparatorMenuItem _miDataSep1, _miDataSep2, _miDataSep3, _miDataSep4; Gtk::MenuItem _miSelectComplex; Gtk::MenuItem _miDataReal, _miDataImaginary, _miDataPhase, _miDataUnrollPhase; Gtk::MenuItem _miSelectStokes; Gtk::MenuItem _miDataStokesI, _miDataStokesQ, _miDataStokesU, _miDataStokesV; Gtk::MenuItem _miSelectCircular; Gtk::MenuItem _miDataRR, _miDataRL, _miDataLR, _miDataLL; Gtk::MenuItem _miSelectLinear; Gtk::MenuItem _miDataXX, _miDataXY, _miDataYX, _miDataYY; Gtk::MenuItem _miSegmentationSubMenu; Gtk::MenuItem _miDataStore, _miDataRecall, _miDataSubtract; Gtk::MenuItem _miDataClearOriginalFlags, _miDataClearAltFlags; Gtk::MenuItem _miTemporalAveraging; Gtk::MenuItem _miSpectralAveraging; // Segmentation menu Gtk::MenuItem _miSegmSegment, _miSegmCluster, _miSegmClassify, _miSegmRemoveSmallSegments; // Toolbar Gtk::RadioToolButton::Group _tbModeGroup; Gtk::SeparatorToolItem _tbSep1, _tbSep2, _tbSep3, _tbSep4, _tbSep5; Gtk::ToolButton _tbOpen, _tbExecuteStrategy; Gtk::RadioToolButton _tbModeData, _tbModeStrategy; Gtk::ToggleToolButton _tbOriginalFlags, _tbAlternativeFlags; Gtk::MenuToolButton _tbSelectVisualization; Gtk::ToolButton _tbPrevious, _tbReload, _tbNext; Gtk::ToolButton _tbZoomFit, _tbZoomIn, _tbZoomOut; Gtk::ToggleToolButton _tbDisplayPP, _tbDisplayPQ, _tbDisplayQP, _tbDisplayQQ; bool _inStrategyMode; bool _blockVisualizationSignals; Gtk::Menu _tfVisualizationMenu; }; aoflagger-v3.4.0/rfigui/rfiguimenu.cpp0000644000175000017500000004227214507760372016506 0ustar olesoles#include "rfiguimenu.h" #include RFIGuiMenu::RFIGuiMenu() : // older versions of gtkmm don't have the 'empty' Gtk::RadioMenuItem() // constructor, so we have to initialize them here. _miViewData(_viewModeGroup), _miViewStrategy(_viewModeGroup), _tbModeData(_tbModeGroup), _tbModeStrategy(_tbModeGroup), _inStrategyMode(false), _blockVisualizationSignals(false) { topMenu(_menuFile, _miFile, "_File"); topMenu(_menuView, _miView, "_View"); topMenu(_menuStrategy, _miStrategy, "_Strategy"); topMenu(_menuPlot, _miPlot, "_Plot"); topMenu(_menuBrowse, _miBrowse, "_Browse"); topMenu(_menuSimulate, _miSimulateMenu, "S_imulate"); topMenu(_menuData, _miData, "_Data"); makeFileMenu(); makeViewMenu(); makeStrategyMenu(); makePlotMenu(); makeBrowseMenu(); makeSimulateMenu(); makeDataMenu(); makeToolbarActions(); if (Gtk::IconTheme::get_default()->has_icon("aoflagger")) { _toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS); _toolbar.set_icon_size(Gtk::ICON_SIZE_LARGE_TOOLBAR); } else { _toolbar.set_toolbar_style(Gtk::TOOLBAR_TEXT); _toolbar.set_icon_size(Gtk::ICON_SIZE_SMALL_TOOLBAR); } } void RFIGuiMenu::makeFileMenu() { // Gtk::AccelKey("O") addItem(_menuFile, _miFileOpen, OnOpen, "_Open...", "document-open"); _miRecentFiles.item.set_submenu(_menuRecentFiles); addItem(_menuFile, _miRecentFiles, "Open _recent", "document-open"); addItem(_menuFile, _miFileSep1); addItem(_menuFile, _miSaveBaselineFlags, OnSaveBaselineFlags, "Write baseline flags", "document-save"); addItem(_menuFile, _miFileExportBaseline, OnExportBaseline, "Export baseline..."); addItem(_menuFile, _miFileSep2); addItem(_menuFile, _miFileClose, OnClose, "Close", "window-close"); // Q addItem(_menuFile, _miFileSep3); addItem(_menuFile, _miHelpAbout, OnAbout, "_About", "aoflagger"); addItem(_menuFile, _miFileQuit, OnQuit, "_Quit", "application-exit"); } void RFIGuiMenu::makeViewMenu() { addItem( _menuViewMode, _miViewData, [&]() { onMIViewData(); }, "Data"); // F8 addItem( _menuViewMode, _miViewStrategy, [&]() { onMIViewStrategy(); }, "Strategy"); _miViewMode.set_submenu(_menuViewMode); addItem(_menuView, _miViewMode, "Mode"); addItem(_menuView, _miViewTimePlot, OnViewTimePlot, "Time plot"); // P addItem(_menuView, _miViewProperties, OnImagePropertiesPressed, "Plot properties..."); addItem(_menuView, _miViewSep1); addItem( _menuView, _miViewOriginalFlags, [&]() { if (!_blockVisualizationSignals) OnToggleFlags(); }, "Ori. flags", "showoriginalflags"); addItem( _menuView, _miViewAlternativeFlags, [&]() { if (!_blockVisualizationSignals) OnToggleFlags(); }, "Alt. flags", "showalternativeflags"); addItem(_menuView, _miViewSep2); addItem( _menuView, _miViewZoomFit, [&]() { if (!_blockVisualizationSignals) OnZoomFit(); }, "Zoom _fit", "zoom-fit-best"); addItem( _menuView, _miViewZoomIn, [&]() { if (!_blockVisualizationSignals) OnZoomIn(); }, "Zoom in", "zoom-in"); addItem( _menuView, _miViewZoomOut, [&]() { if (!_blockVisualizationSignals) OnZoomOut(); }, "Zoom out", "zoom-out"); addItem( _menuView, _miViewSelectZoom, [&]() { if (!_blockVisualizationSignals) OnZoomSelect(); }, "Select zoom..."); addItem(_menuView, _miViewSep3); // F2 addItem(_menuView, _miViewStats, OnShowStats, "Statistics"); } void RFIGuiMenu::makeStrategyMenu() { addItem(_menuStrategyNew, _miStrategyNewEmpty, OnStrategyNewEmpty, "Empty"); addItem(_menuStrategyNew, _miStrategyNewTemplate, OnStrategyNewTemplate, "Template"); addItem(_menuStrategyNew, _miStrategyNewDefault, OnStrategyNewDefault, "Default"); _miStrategyNew.item.set_submenu(_menuStrategyNew); addItem(_menuStrategy, _miStrategyNew, "New", "document-new"); addItem(_menuStrategy, _miStrategySep1); addItem(_menuStrategy, _miStrategyOpen, OnStrategyOpen, "Open...", "document-open"); _miStrategyOpenDefault.item.set_submenu(_menuStrategyOpenDefault); addItem(_menuStrategy, _miStrategyOpenDefault, "Open _default", "document-open"); addItem(_menuStrategy, _miStrategySep2); addItem(_menuStrategy, _miStrategySave, OnStrategySave, "Save", "document-save"); addItem(_menuStrategy, _miStrategySaveAs, OnStrategySaveAs, "Save as...", "document-save-as"); addItem(_menuStrategy, _miStrategySep3); // F9 addItem(_menuStrategy, _miExecuteLuaStrategy, OnExecuteLuaStrategy, "E_xecute strategy", "system-run"); addItem(_menuStrategy, _miStrategySep4); addItem(_menuStrategy, _miExecutePythonStrategy, OnExecutePythonStrategy, "Execute _python script"); // TODO Functionality is broken and should be removed, but // it might be interesting to do a comparison of Lua vs Python strategies // first _miExecutePythonStrategy.set_sensitive(false); } void RFIGuiMenu::makePlotMenu() { _miPlotTime.set_submenu(_menuPlotTime); addItem(_menuPlot, _miPlotTime, "Time"); addItem(_menuPlotTime, _miPlotTimeMean, OnPlotTimeMeanPressed, "_Mean (low res)"); addItem(_menuPlotTime, _miPlotTimeScatter, OnPlotTimeScatterPressed, "Mean (_scatter)"); _miPlotFrequency.set_submenu(_menuPlotFrequency); addItem(_menuPlot, _miPlotFrequency, "Frequency"); addItem(_menuPlotFrequency, _miPlotPowerSpectrum, OnPlotPowerSpectrumPressed, "_Power (low res)"); addItem(_menuPlotFrequency, _miPlotFrequencyScatter, OnPlotFrequencyScatterPressed, "_Power (scatter)"); addItem(_menuPlotFrequency, _miPlotMeanSpectrum, OnPlotMeanSpectrumPressed, "_Mean"); addItem(_menuPlotFrequency, _miPlotSumSpectrum, OnPlotSumSpectrumPressed, "_S_um"); addItem(_menuPlot, _miPlotDistribution, OnPlotDistPressed, "Plot _distribution"); addItem(_menuPlot, _miPlotLogLogDistribution, OnPlotLogLogDistPressed, "Plot _log-log dist"); addItem(_menuPlot, _miPlotSingularValues, OnPlotSingularValuesPressed, "Plot _singular values"); } void RFIGuiMenu::makeBrowseMenu() { // F6 addItem(_menuBrowse, _miBrowsePrevious, OnLoadPrevious, "Previous", "go-previous"); _miBrowsePrevious.item.set_sensitive(false); // F5 addItem(_menuBrowse, _miBrowseReload, OnReloadPressed, "_Reload", "view-refresh"); _miBrowseReload.item.set_sensitive(false); // F7 addItem(_menuBrowse, _miBrowseNext, OnLoadPrevious, "Next", "go-next"); _miBrowseNext.item.set_sensitive(false); addItem(_menuBrowse, _miBrowseSep1); // "G" addItem(_menuBrowse, _miBrowseGoto, OnGoToPressed, "_Go to..."); addItem(_menuBrowse, _miBrowseSep2); addItem(_menuBrowse, _miBrowseLongestBaseline, OnLoadLongestBaselinePressed, "Longest baseline"); addItem(_menuBrowse, _miBrowseMedianBaseline, OnLoadMedianBaselinePressed, "Median baseline"); addItem(_menuBrowse, _miBrowseShortestBaseline, OnLoadShortestBaselinePressed, "Shortest baseline"); } void RFIGuiMenu::makeSimulateMenu() { addItem(_menuSimulate, _miSimulate, OnSimulate, "Simulate..."); _miTestSetSubMenu.set_submenu(_menuTestSets); addItem(_menuSimulate, _miTestSetSubMenu, "Open _testset"); addItem(_menuTestSets, _miTestA, OnOpenTestSetA, "A Full spikes"); addItem(_menuTestSets, _miTestB, OnOpenTestSetB, "B Half spikes"); addItem(_menuTestSets, _miTestC, OnOpenTestSetC, "C Varying spikes"); addItem(_menuTestSets, _miTestD, OnOpenTestSetD, "D 3 srcs + spikes"); addItem(_menuTestSets, _miTestE, OnOpenTestSetE, "E 5 srcs + spikes"); addItem(_menuTestSets, _miTestF, OnOpenTestSetF, "F 5 srcs + spikes"); addItem(_menuTestSets, _miTestG, OnOpenTestSetG, "G Test set G"); addItem(_menuTestSets, _miTestH, OnOpenTestSetH, "H filtered srcs + spikes"); addItem(_menuTestSets, _miTestNoise, OnOpenTestSetNoise, "Noise"); _miSimulateModify.set_submenu(_menuModify); addItem(_menuSimulate, _miSimulateModify, "Modify"); addItem(_menuModify, _miModifyStaticFringe, OnAddStaticFringe, "Static fringe"); addItem(_menuModify, _miModify1SigmaStaticFringe, OnAdd1SigmaFringe, "Static 1 sigma fringe"); addItem(_menuModify, _miModifyToOne, OnSetToOne, "Set to 1"); addItem(_menuModify, _miModifyToI, OnSetToI, "Set to i"); addItem(_menuModify, _miModifyToOnePlusI, OnSetToOnePlusI, "Set to 1+i"); addItem(_menuModify, _miModifyCorrelatorFault, OnAddCorrelatorFault, "Add correlator fault"); addItem(_menuModify, _miModifyAddNaNs, OnAddNaNs, "Add NaNs"); addItem(_menuModify, _miModifyMultiply, OnMultiplyData, "Multiply data..."); } void RFIGuiMenu::makeDataMenu() { makeSegmentationMenu(); addItem(_menuData, _miDataToOriginal, OnVisualizedToOriginalPressed, "Select current view"); addItem(_menuData, _miDataSep1); _miSelectComplex.set_submenu(_menuSelectComplex); addItem(_menuData, _miSelectComplex, "Select _complex"); addItem(_menuSelectComplex, _miDataReal, OnKeepRealPressed, "_Real part"); addItem(_menuSelectComplex, _miDataImaginary, OnKeepImaginaryPressed, "_Imaginary part"); addItem(_menuSelectComplex, _miDataPhase, OnKeepPhasePressed, "_Phase part"); addItem(_menuSelectComplex, _miDataUnrollPhase, OnUnrollPhaseButtonPressed, "_Unroll phase"); _miSelectStokes.set_submenu(_menuSelectStokes); addItem(_menuData, _miSelectStokes, "Select _stokes"); addItem(_menuSelectStokes, _miDataStokesI, OnKeepStokesIPressed, "Stokes _I"); addItem(_menuSelectStokes, _miDataStokesQ, OnKeepStokesQPressed, "Stokes _Q"); addItem(_menuSelectStokes, _miDataStokesU, OnKeepStokesUPressed, "Stokes _U"); addItem(_menuSelectStokes, _miDataStokesV, OnKeepStokesVPressed, "Stokes _V"); _miSelectCircular.set_submenu(_menuSelectCircular); addItem(_menuData, _miSelectCircular, "Select circ_ular"); addItem(_menuSelectCircular, _miDataRR, OnKeepRRPressed, "_RR"); addItem(_menuSelectCircular, _miDataRL, OnKeepRLPressed, "RL"); addItem(_menuSelectCircular, _miDataLR, OnKeepLRPressed, "LR"); addItem(_menuSelectCircular, _miDataLL, OnKeepLLPressed, "_LL"); _miSelectLinear.set_submenu(_menuSelectLinear); addItem(_menuData, _miSelectLinear, "Select _linear"); addItem(_menuSelectLinear, _miDataXX, OnKeepXXPressed, "_XX"); addItem(_menuSelectLinear, _miDataXY, OnKeepXYPressed, "XY"); addItem(_menuSelectLinear, _miDataYX, OnKeepYXPressed, "YX"); addItem(_menuSelectLinear, _miDataYY, OnKeepYYPressed, "_YY"); _miSegmentationSubMenu.set_submenu(_menuSegmentation); addItem(_menuData, _miSegmentationSubMenu, "_Segmentation"); addItem(_menuData, _miDataSep2); addItem(_menuData, _miDataStore, OnStoreData, "Store"); addItem(_menuData, _miDataRecall, OnRecallData, "Recall"); addItem(_menuData, _miDataSubtract, OnSubtractDataFromMem, "Subtract from mem"); addItem(_menuData, _miDataSep3); addItem(_menuData, _miTemporalAveraging, OnTemporalAveragingPressed, "Temporal averaging..."); addItem(_menuData, _miSpectralAveraging, OnSpectralAveragingPressed, "Spectral averaging..."); addItem(_menuData, _miDataSep4); addItem(_menuData, _miDataClearOriginalFlags, OnClearOriginalFlagsPressed, "Clear ori. flags"); addItem(_menuData, _miDataClearAltFlags, OnClearAltFlagsPressed, "Clear alt. flags"); } void RFIGuiMenu::makeSegmentationMenu() { addItem(_menuSegmentation, _miSegmSegment, OnSegment, "Segment"); addItem(_menuSegmentation, _miSegmCluster, OnCluster, "Cluster"); addItem(_menuSegmentation, _miSegmClassify, OnClassify, "Classify"); addItem(_menuSegmentation, _miSegmRemoveSmallSegments, OnRemoveSmallSegments, "Remove small segments"); } void RFIGuiMenu::makeToolbarActions() { addTool(_tbOpen, OnOpen, "Open", "Open a file or directory on disk", "document-open"); _toolbar.append(_tbSep1); addTool( _tbModeData, [&]() { onTBModeData(); }, "Data", "Switch to data-viewing mode.", "spectrum"); addTool( _tbModeStrategy, [&]() { onTBModeStrategy(); }, "Strategy", "Switch to the strategy editor.", "lua-editor"); _toolbar.append(_tbSep2); // Gtk::AccelKey("F9") addTool(_tbExecuteStrategy, OnExecuteLuaStrategy, "E_xecute strategy", "Run the Lua strategy script. This will not write to the opened set. " "The flagging results are displayed in the plot as yellow " "('alternative') flag mask.", "system-run"); // F3 addTool(_tbOriginalFlags, OnToggleFlags, "Ori flags", "Display the first flag mask on top of the visibilities. These flags " "are displayed in purple and indicate the flags as they originally " "were stored in the measurement set.", "showoriginalflags"); // F4 addTool(_tbAlternativeFlags, OnToggleFlags, "Alt flags", "Display the second flag mask on top of the visibilities. These " "flags are displayed in yellow and indicate flags found by running " "the strategy.", "showalternativeflags"); addTool(_tbSelectVisualization, OnToggleImage, "Change visualization", "Switch visualization", "showoriginalvisibilities"); _tbSelectVisualization.set_menu(_tfVisualizationMenu); _toolbar.append(_tbSep3); // F6 addTool(_tbPrevious, OnLoadPrevious, "Previous", "Load and display the previous baseline. Normally, this steps from " "the baseline between antennas (i) and (j) to (i) and (j-1).", "go-previous"); _tbPrevious.set_sensitive(false); // F5 addTool(_tbReload, OnReloadPressed, "Reload", "Reload the currently displayed baseline. This will reset the purple " "flags to the measurement set flags, and clear the yellow flags.", "view-refresh"); _tbReload.set_sensitive(false); // F7 addTool(_tbNext, OnLoadNext, "Next", "Load and display the next baseline. Normally, this steps from the " "baseline between antennas (i) and (j) to (i) and (j+1).", "go-next"); _tbNext.set_sensitive(false); _toolbar.append(_tbSep4); // 0 addTool(_tbZoomFit, OnZoomFit, "Fit", "Zoom fit", "zoom-fit-best"); addTool(_tbZoomIn, OnZoomIn, "+", "Zoom in", "zoom-in"); addTool(_tbZoomOut, OnZoomOut, "-", "Zoom out", "zoom-out"); _toolbar.append(_tbSep5); auto sig = [&]() { if (!_blockVisualizationSignals) OnTogglePolarizations(); }; addTool(_tbDisplayPP, sig, "PP", "Display the PP polarization. Depending on the polarization " "configuration of the measurement set, this will show XX or RR", "showpp"); addTool(_tbDisplayPQ, sig, "PQ", "Display the PQ polarization. Depending on the polarization " "configuration of the measurement set, this will show XY or RL", "showpq"); addTool(_tbDisplayQP, sig, "QP", "Display the QP polarization. Depending on the polarization " "configuration of the measurement set, this will show YX or LR", "showqp"); addTool(_tbDisplayQQ, sig, "QQ", "Display the QQ polarization. Depending on the polarization " "configuration of the measurement set, this will show YY or LL", "showqq"); _tbDisplayPP.set_active(true); _tbDisplayQQ.set_active(true); } void RFIGuiMenu::EnableRunButtons(bool sensitive) { _menuFile.set_sensitive(sensitive); _miExecuteLuaStrategy.item.set_sensitive(sensitive); _miExecutePythonStrategy.set_sensitive(sensitive); _tbOpen.set_sensitive(sensitive); _tbExecuteStrategy.set_sensitive(sensitive); } void RFIGuiMenu::SetRecentFiles(const std::vector& recentFiles) { _miRecentFileChoices.clear(); const size_t n = std::min(recentFiles.size(), size_t(10)); _miRecentFileChoices.resize(n); for (size_t i = 0; i != n; ++i) { addItem( _menuRecentFiles, _miRecentFileChoices[i], [&, i]() { OnOpenRecent(i); }, recentFiles[i].c_str()); _miRecentFileChoices[i].set_use_underline(false); } _menuRecentFiles.show_all_children(); } void RFIGuiMenu::SetStrategyDefaults( const std::vector& strategyDefaults) { _miStrategyDefaults.resize(strategyDefaults.size()); for (size_t i = 0; i != strategyDefaults.size(); ++i) { const std::string label = strategyDefaults[i]; addItem( _menuStrategyOpenDefault, _miStrategyDefaults[i], [&, label]() { OnStrategyOpenDefault(label); }, label.c_str()); _miStrategyDefaults[i].set_use_underline(false); } _menuStrategyOpenDefault.show_all_children(); } void RFIGuiMenu::onTBModeData() { if (_inStrategyMode && _tbModeData.get_active()) { _inStrategyMode = false; _miViewData.set_active(true); OnViewData(); } } void RFIGuiMenu::onTBModeStrategy() { if (!_inStrategyMode && _tbModeStrategy.get_active()) { _inStrategyMode = true; _miViewStrategy.set_active(true); OnViewStrategy(); } } void RFIGuiMenu::onMIViewData() { if (_inStrategyMode && _miViewData.get_active()) { _inStrategyMode = false; _tbModeData.set_active(true); OnViewData(); } } void RFIGuiMenu::onMIViewStrategy() { if (!_inStrategyMode && _miViewStrategy.get_active()) { _inStrategyMode = true; _tbModeStrategy.set_active(true); OnViewStrategy(); } } aoflagger-v3.4.0/rfigui/imagepropertieswindow.cpp0000644000175000017500000003276014507760372020764 0ustar olesoles#include #include #include #include "../util/gtkmm-compat.h" #include "../plot/plotwidget.h" #include "imagepropertieswindow.h" #include "maskedheatmap.h" ImagePropertiesWindow::ImagePropertiesWindow(PlotWidget& imageWidget, const std::string& title) : Gtk::Window(), _plotWidget(imageWidget), _applyButton("_Apply", true), _exportButton("_Export", true), _exportDataButton("Export _data", true), _closeButton("_Close", true), _colorMapFrame("Color map"), _scaleFrame("Scale"), _minMaxScaleButton("From min to max"), _winsorizedScaleButton("Winsorized min and max"), _specifiedScaleButton("Specified:"), _scaleMinLabel("Scale minimum:"), _scaleMaxLabel("Scale maximum:"), _scaleMinEntry(), _scaleMaxEntry(), _optionsFrame("Options"), _normalOptionsButton("Normal scale"), _logScaleButton("Logarithmic scale"), _filterFrame("Interpolation"), _bestFilterButton("Best"), _nearestFilterButton("Nearest"), _axesFrame("Title & axes"), _showXYAxes("Show XY axes"), _showColorScale("Show color scale"), _showTitleButton("Show title"), _showXAxisDescriptionButton("x-axis desc"), _showYAxisDescriptionButton("y-axis desc"), _showZAxisDescriptionButton("z-axis desc"), _manualXAxisDescription("manual"), _manualYAxisDescription("manual"), _manualZAxisDescription("manual") { _maskedHeatMap = dynamic_cast(&_plotWidget.Plot()); if (!_maskedHeatMap) { throw std::invalid_argument( "ImagePropertiesWindow called for a plot that is not a heat map"); } set_title(title); initColorMapButtons(); initScaleWidgets(); initOptionsWidgets(); initFilterWidgets(); _framesHBox.pack_start(_filterAndOptionsBox); initAxisWidgets(); gtkmm_set_image_from_icon_name(_applyButton, "gtk-apply"); _applyButton.signal_clicked().connect( sigc::mem_fun(*this, &ImagePropertiesWindow::onApplyClicked)); _bottomButtonBox.pack_start(_applyButton); gtkmm_set_image_from_icon_name(_exportButton, "document-save-as"); _exportButton.signal_clicked().connect( sigc::mem_fun(*this, &ImagePropertiesWindow::onExportClicked)); _bottomButtonBox.pack_start(_exportButton); _exportDataButton.signal_clicked().connect( sigc::mem_fun(*this, &ImagePropertiesWindow::onExportDataClicked)); _bottomButtonBox.pack_start(_exportDataButton); gtkmm_set_image_from_icon_name(_closeButton, "window-close"); _closeButton.signal_clicked().connect( sigc::mem_fun(*this, &ImagePropertiesWindow::onCloseClicked)); _bottomButtonBox.pack_start(_closeButton); _topVBox.pack_start(_framesHBox); _topVBox.pack_start(_bottomButtonBox); add(_topVBox); _topVBox.show_all(); } void ImagePropertiesWindow::initColorMapButtons() { _colorMapStore = Gtk::ListStore::create(_colorMapColumns); addColorMap("Grayscale", ColorMap::Grayscale); addColorMap("Inverted grayscale", ColorMap::Inverted); addColorMap("Hot/cold", ColorMap::HotCold); addColorMap("Red/blue", ColorMap::RedBlue); addColorMap("Black/red", ColorMap::BlackRed); addColorMap("Red/Yellow/Blue", ColorMap::RedYellowBlue); addColorMap("Fire", ColorMap::Fire); addColorMap("Cool", ColorMap::Cool); addColorMap("Cubehelix", ColorMap::CubeHelix); addColorMap("Cubehelix+", ColorMap::CubeHelixColourful); addColorMap("Viridis", ColorMap::Viridis); addColorMap("Rainbow", ColorMap::Rainbow); _colorMapCombo.set_model(_colorMapStore); _colorMapCombo.pack_start(_colorMapColumns.name); const ColorMap::Type selectedMap = _maskedHeatMap->GetColorMap(); const Gtk::ListStore::Children children = _colorMapStore->children(); for (auto row : children) { if (row[_colorMapColumns.colorMap] == selectedMap) { _colorMapCombo.set_active(row); break; } } _colorMapBox.pack_start(_colorMapCombo, false, false); _colorMapFrame.add(_colorMapBox); _framesHBox.pack_start(_colorMapFrame); } void ImagePropertiesWindow::initScaleWidgets() { _scaleFrame.add(_scaleBox); Gtk::RadioButton::Group group; _scaleBox.pack_start(_minMaxScaleButton); _minMaxScaleButton.set_group(group); _minMaxScaleButton.signal_clicked().connect( sigc::mem_fun(*this, &ImagePropertiesWindow::onScaleChanged)); _scaleBox.pack_start(_winsorizedScaleButton); _winsorizedScaleButton.set_group(group); _winsorizedScaleButton.signal_clicked().connect( sigc::mem_fun(*this, &ImagePropertiesWindow::onScaleChanged)); _scaleBox.pack_start(_specifiedScaleButton); _specifiedScaleButton.set_group(group); _specifiedScaleButton.signal_clicked().connect( sigc::mem_fun(*this, &ImagePropertiesWindow::onScaleChanged)); switch (_maskedHeatMap->ZRange().minimum) { default: case RangeLimit::Extreme: _minMaxScaleButton.set_active(true); break; case RangeLimit::Winsorized: _winsorizedScaleButton.set_active(true); break; case RangeLimit::Specified: _specifiedScaleButton.set_active(true); break; } onScaleChanged(); updateMinMaxEntries(); _scaleBox.pack_start(_scaleMinLabel); _scaleBox.pack_start(_scaleMinEntry); _scaleBox.pack_start(_scaleMaxLabel); _scaleBox.pack_start(_scaleMaxEntry); _framesHBox.pack_start(_scaleFrame); } void ImagePropertiesWindow::initOptionsWidgets() { Gtk::RadioButton::Group group; _optionsBox.pack_start(_normalOptionsButton); _normalOptionsButton.set_group(group); _optionsBox.pack_start(_logScaleButton); _logScaleButton.set_group(group); if (_maskedHeatMap->LogZScale()) { _logScaleButton.set_active(true); } else { _normalOptionsButton.set_active(true); } _optionsFrame.add(_optionsBox); _filterAndOptionsBox.pack_start(_optionsFrame); } void ImagePropertiesWindow::initFilterWidgets() { Gtk::RadioButton::Group group; _filterBox.pack_start(_bestFilterButton); _bestFilterButton.set_group(group); _filterBox.pack_start(_nearestFilterButton); _nearestFilterButton.set_group(group); switch (_maskedHeatMap->CairoFilter()) { default: case Cairo::FILTER_BEST: _bestFilterButton.set_active(true); break; case Cairo::FILTER_NEAREST: _nearestFilterButton.set_active(true); break; } _filterFrame.add(_filterBox); _filterAndOptionsBox.pack_start(_filterFrame); } void ImagePropertiesWindow::initAxisWidgets() { const MaskedHeatMap& maskedHeatMap = static_cast(_plotWidget.Plot()); _showXYAxes.set_active(maskedHeatMap.ShowXAxis() || maskedHeatMap.ShowYAxis()); _axesGeneralBox.pack_start(_showXYAxes); _showColorScale.set_active(maskedHeatMap.ShowColorScale()); _axesGeneralBox.pack_start(_showColorScale); _axesHBox.pack_start(_axesGeneralBox); _showTitleButton.set_active(maskedHeatMap.ShowTitle()); _titleBox.pack_start(_showTitleButton); _titleEntry.set_text(maskedHeatMap.TitleText()); _titleBox.pack_start(_titleEntry); _axesVisibilityBox.pack_start(_titleBox); _showXAxisDescriptionButton.set_active(maskedHeatMap.ShowXAxisDescription()); _xAxisBox.pack_start(_showXAxisDescriptionButton); _manualXAxisDescription.set_active(maskedHeatMap.ManualXAxisDescription()); _xAxisBox.pack_start(_manualXAxisDescription); _xAxisDescriptionEntry.set_text(maskedHeatMap.XAxisDescription()); _xAxisBox.pack_start(_xAxisDescriptionEntry); _axesVisibilityBox.pack_start(_xAxisBox); _showYAxisDescriptionButton.set_active(maskedHeatMap.ShowYAxisDescription()); _yAxisBox.pack_start(_showYAxisDescriptionButton); _manualYAxisDescription.set_active(maskedHeatMap.ManualYAxisDescription()); _yAxisBox.pack_start(_manualYAxisDescription); _yAxisDescriptionEntry.set_text(maskedHeatMap.YAxisDescription()); _yAxisBox.pack_start(_yAxisDescriptionEntry); _axesVisibilityBox.pack_start(_yAxisBox); _showZAxisDescriptionButton.set_active(maskedHeatMap.ShowZAxisDescription()); _zAxisBox.pack_start(_showZAxisDescriptionButton); _manualZAxisDescription.set_active(maskedHeatMap.ManualZAxisDescription()); _zAxisBox.pack_start(_manualZAxisDescription); _zAxisDescriptionEntry.set_text(maskedHeatMap.ZAxisDescription()); _zAxisBox.pack_start(_zAxisDescriptionEntry); _axesVisibilityBox.pack_start(_zAxisBox); _axesHBox.pack_start(_axesVisibilityBox); _axesFrame.add(_axesHBox); _topVBox.pack_start(_axesFrame); } void ImagePropertiesWindow::updateMinMaxEntries() { std::stringstream minStr; minStr << _maskedHeatMap->Min(); _scaleMinEntry.set_text(minStr.str()); std::stringstream maxStr; maxStr << _maskedHeatMap->Max(); _scaleMaxEntry.set_text(maxStr.str()); } void ImagePropertiesWindow::onApplyClicked() { MaskedHeatMap& maskedHeatMap = static_cast(_plotWidget.Plot()); maskedHeatMap.SetColorMap( (*_colorMapCombo.get_active())[_colorMapColumns.colorMap]); if (_minMaxScaleButton.get_active()) { maskedHeatMap.SetZRange(FullRange()); } else if (_winsorizedScaleButton.get_active()) { maskedHeatMap.SetZRange(WinsorizedRange()); } else if (_specifiedScaleButton.get_active()) { RangeConfiguration range; range.minimum = RangeLimit::Specified; range.maximum = RangeLimit::Specified; range.specified_min = atof(_scaleMinEntry.get_text().c_str()); range.specified_max = atof(_scaleMaxEntry.get_text().c_str()); maskedHeatMap.SetZRange(range); } maskedHeatMap.SetLogZScale(_logScaleButton.get_active()); if (_bestFilterButton.get_active()) maskedHeatMap.SetCairoFilter(Cairo::FILTER_BEST); else if (_nearestFilterButton.get_active()) maskedHeatMap.SetCairoFilter(Cairo::FILTER_NEAREST); maskedHeatMap.SetShowTitle(_showTitleButton.get_active()); maskedHeatMap.SetTitleText(_titleEntry.get_text()); maskedHeatMap.SetShowXAxis(_showXYAxes.get_active()); maskedHeatMap.SetShowYAxis(_showXYAxes.get_active()); maskedHeatMap.SetShowXAxisDescription( _showXAxisDescriptionButton.get_active()); maskedHeatMap.SetShowYAxisDescription( _showYAxisDescriptionButton.get_active()); maskedHeatMap.SetShowZAxisDescription( _showZAxisDescriptionButton.get_active()); maskedHeatMap.SetManualXAxisDescription(_manualXAxisDescription.get_active()); if (_manualXAxisDescription.get_active()) maskedHeatMap.SetXAxisDescription(_xAxisDescriptionEntry.get_text()); maskedHeatMap.SetManualYAxisDescription(_manualYAxisDescription.get_active()); if (_manualYAxisDescription.get_active()) maskedHeatMap.SetYAxisDescription(_yAxisDescriptionEntry.get_text()); maskedHeatMap.SetManualZAxisDescription(_manualZAxisDescription.get_active()); if (_manualZAxisDescription.get_active()) maskedHeatMap.SetZAxisDescription(_zAxisDescriptionEntry.get_text()); maskedHeatMap.SetShowColorScale(_showColorScale.get_active()); _plotWidget.Update(); updateMinMaxEntries(); } void ImagePropertiesWindow::onCloseClicked() { hide(); } void ImagePropertiesWindow::onExportClicked() { if (_maskedHeatMap->HasImage()) { Gtk::FileChooserDialog dialog("Specify image filename", Gtk::FILE_CHOOSER_ACTION_SAVE); dialog.set_transient_for(*this); // Add response buttons the the dialog: dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("_Save", Gtk::RESPONSE_OK); const Glib::RefPtr pdfFilter = Gtk::FileFilter::create(); const std::string pdfName = "Portable Document Format (*.pdf)"; pdfFilter->set_name(pdfName); pdfFilter->add_pattern("*.pdf"); pdfFilter->add_mime_type("application/pdf"); dialog.add_filter(pdfFilter); const Glib::RefPtr svgFilter = Gtk::FileFilter::create(); const std::string svgName = "Scalable Vector Graphics (*.svg)"; svgFilter->set_name(svgName); svgFilter->add_pattern("*.svg"); svgFilter->add_mime_type("image/svg+xml"); dialog.add_filter(svgFilter); const Glib::RefPtr pngFilter = Gtk::FileFilter::create(); const std::string pngName = "Portable Network Graphics (*.png)"; pngFilter->set_name(pngName); pngFilter->add_pattern("*.png"); pngFilter->add_mime_type("image/png"); dialog.add_filter(pngFilter); const int result = dialog.run(); if (result == Gtk::RESPONSE_OK) { const Glib::RefPtr filter = dialog.get_filter(); if (filter->get_name() == pdfName) _plotWidget.SavePdf(dialog.get_filename()); else if (filter->get_name() == svgName) _plotWidget.SaveSvg(dialog.get_filename()); else _plotWidget.SavePng(dialog.get_filename()); } } } void ImagePropertiesWindow::onExportDataClicked() { if (_maskedHeatMap->HasImage()) { Gtk::FileChooserDialog dialog("Specify data filename", Gtk::FILE_CHOOSER_ACTION_SAVE); dialog.set_transient_for(*this); // Add response buttons the the dialog: dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("_Save", Gtk::RESPONSE_OK); const Glib::RefPtr pdfFilter = Gtk::FileFilter::create(); const std::string pdfName = "Text format: width; height; data1; data2... (*.txt)"; pdfFilter->set_name(pdfName); pdfFilter->add_pattern("*.txt"); pdfFilter->add_mime_type("text/plain"); dialog.add_filter(pdfFilter); const int result = dialog.run(); if (result == Gtk::RESPONSE_OK) { const MaskedHeatMap& maskedHeatMap = static_cast(_plotWidget.Plot()); maskedHeatMap.SaveText(dialog.get_filename()); } } } aoflagger-v3.4.0/rfigui/numinputdialog.h0000644000175000017500000000174114507760372017034 0ustar olesoles#ifndef NUMINPUTDIALOG_H #define NUMINPUTDIALOG_H #include #include #include #include #include #include #include class NumInputDialog : public Gtk::Dialog { public: NumInputDialog(const Glib::ustring& title, const Glib::ustring& valueCaption, double defaultValue) : Dialog(title, true), _label(valueCaption) { _hBox.pack_start(_label); std::ostringstream s; s << defaultValue; _entry.set_text(s.str()); _entry.set_activates_default(true); _hBox.pack_end(_entry); get_content_area()->pack_start(_hBox); _hBox.show_all(); add_button("_Ok", Gtk::RESPONSE_OK); add_button("_Cancel", Gtk::RESPONSE_CANCEL); set_default_response(Gtk::RESPONSE_OK); } double Value() const { return atof(_entry.get_text().c_str()); } private: Gtk::Label _label; Gtk::Entry _entry; Gtk::HBox _hBox; }; #endif // NUMINPUTDIALOG_H aoflagger-v3.4.0/rfigui/plotwindow.cpp0000644000175000017500000000735614507760372016546 0ustar olesoles#include "plotwindow.h" #include "../plot/plotmanager.h" #include "../plot/plotpropertieswindow.h" PlotWindow::PlotWindow(PlotManager& plotManager) : _plotManager(plotManager), _clearButton("_Clear"), _editButton("_Edit"), _plotPropertiesWindow(nullptr) { Gtk::ToolButton(); plotManager.OnUpdate() = std::bind(&PlotWindow::handleUpdate, this); _hBox.pack_start(_plotWidget, Gtk::PACK_EXPAND_WIDGET); _plotListStore = Gtk::ListStore::create(_plotListColumns); _plotListView.set_model(_plotListStore); _plotListView.append_column("Plot title", _plotListColumns._name); _plotListView.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &PlotWindow::onSelectedPlotChange)); _clearButton.set_tooltip_text("Clear the list of plots"); _clearButton.set_icon_name("edit-clear"); _clearButton.signal_clicked().connect( sigc::mem_fun(*this, &PlotWindow::onClearPlotsPressed)); _toolbar.append(_clearButton); _editButton.set_tooltip_text("Edit the properties of the selected plot"); _editButton.set_icon_name("document-properties"); _editButton.signal_clicked().connect( sigc::mem_fun(*this, &PlotWindow::onEditPlottingPropertiesPressed)); _toolbar.append(_editButton); _toolbar.set_icon_size(Gtk::ICON_SIZE_SMALL_TOOLBAR); _toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS); _sideBox.pack_start(_toolbar, Gtk::PACK_SHRINK); _sideBox.pack_start(_plotListView); _hBox.pack_end(_sideBox, false, false, 3); add(_hBox); _hBox.show_all(); } PlotWindow::~PlotWindow() { delete _plotPropertiesWindow; } void PlotWindow::handleUpdate() { updatePlotList(); const std::vector>& plots = _plotManager.Items(); if (!plots.empty()) { XYPlot& lastPlot = **plots.rbegin(); const size_t index = plots.size() - 1; _plotWidget.SetPlot(lastPlot); for (Gtk::TreeNodeChildren::iterator i = _plotListStore->children().begin(); i != _plotListStore->children().end(); ++i) { if ((*i)[_plotListColumns._index] == index) { _plotListView.get_selection()->select(i); break; } } } else { _plotWidget.Clear(); delete _plotPropertiesWindow; _plotPropertiesWindow = nullptr; } show(); raise(); } void PlotWindow::updatePlotList() { const std::vector>& plots = _plotManager.Items(); _plotListView.get_selection()->unselect_all(); _plotListStore->clear(); for (size_t index = 0; index != plots.size(); ++index) { const XYPlot& plot = *plots[index]; const Gtk::TreeModel::Row row = *_plotListStore->append(); row[_plotListColumns._index] = index; row[_plotListColumns._name] = plot.GetTitle(); } onSelectedPlotChange(); } void PlotWindow::onSelectedPlotChange() { const Gtk::TreeModel::iterator iter = _plotListView.get_selection()->get_selected(); if (iter) // If anything is selected { const Gtk::TreeModel::Row row = *iter; const size_t index = row[_plotListColumns._index]; XYPlot& plot = *_plotManager.Items()[index]; _plotWidget.SetPlot(plot); } } void PlotWindow::onClearPlotsPressed() { _plotListView.get_selection()->unselect_all(); _plotManager.Clear(); } void PlotWindow::onEditPlottingPropertiesPressed() { delete _plotPropertiesWindow; const Gtk::TreeModel::iterator iter = _plotListView.get_selection()->get_selected(); if (iter) { XYPlot& plot = *_plotManager.Items()[(*iter)[_plotListColumns._index]]; _plotPropertiesWindow = new PlotPropertiesWindow(plot, "Plot properties"); _plotPropertiesWindow->OnChangesApplied = std::bind(&PlotWindow::onPlotPropertiesChanged, this); _plotPropertiesWindow->show(); _plotPropertiesWindow->raise(); } } void PlotWindow::onPlotPropertiesChanged() { _plotWidget.Update(); } aoflagger-v3.4.0/rfigui/imagepropertieswindow.h0000644000175000017500000000567014507760372020431 0ustar olesoles#ifndef IMAGEPROPERTIESWINDOW_H #define IMAGEPROPERTIESWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../plot/colormap.h" class ImagePropertiesWindow : public Gtk::Window { public: ImagePropertiesWindow(class PlotWidget& plotWidget, const std::string& title); ~ImagePropertiesWindow() {} private: void onApplyClicked(); void onCloseClicked(); void onExportClicked(); void onExportDataClicked(); void onScaleChanged() { _scaleMinEntry.set_sensitive(_specifiedScaleButton.get_active()); _scaleMaxEntry.set_sensitive(_specifiedScaleButton.get_active()); } void initColorMapButtons(); void initScaleWidgets(); void initOptionsWidgets(); void initFilterWidgets(); void initAxisWidgets(); void updateMinMaxEntries(); class PlotWidget& _plotWidget; class MaskedHeatMap* _maskedHeatMap; Gtk::ButtonBox _bottomButtonBox; Gtk::VBox _topVBox; Gtk::HBox _framesHBox; void addColorMap(const Glib::ustring& name, ColorMap::Type map) { Gtk::TreeModel::Row row = (*_colorMapStore->append()); row[_colorMapColumns.name] = name; row[_colorMapColumns.colorMap] = map; } struct ColorMapColumns : public Gtk::TreeModel::ColumnRecord { ColorMapColumns() { add(name); add(colorMap); } Gtk::TreeModelColumn name; Gtk::TreeModelColumn colorMap; }; ColorMapColumns _colorMapColumns; Gtk::Button _applyButton, _exportButton, _exportDataButton, _closeButton; Gtk::Frame _colorMapFrame; Gtk::VBox _colorMapBox; Gtk::ComboBox _colorMapCombo; Glib::RefPtr _colorMapStore; Gtk::Frame _scaleFrame; Gtk::VBox _scaleBox; Gtk::RadioButton _minMaxScaleButton, _winsorizedScaleButton, _specifiedScaleButton; Gtk::Label _scaleMinLabel, _scaleMaxLabel; Gtk::Entry _scaleMinEntry, _scaleMaxEntry; Gtk::VBox _filterAndOptionsBox; Gtk::Frame _optionsFrame; Gtk::VBox _optionsBox; Gtk::RadioButton _normalOptionsButton, _logScaleButton; Gtk::Frame _filterFrame; Gtk::VBox _filterBox; Gtk::RadioButton _bestFilterButton, _nearestFilterButton; Gtk::Frame _axesFrame; Gtk::HBox _axesHBox; Gtk::VBox _axesGeneralBox; Gtk::VBox _axesVisibilityBox; Gtk::CheckButton _showXYAxes, _showColorScale; Gtk::HBox _titleBox, _xAxisBox, _yAxisBox, _zAxisBox; Gtk::CheckButton _showTitleButton, _showXAxisDescriptionButton, _showYAxisDescriptionButton, _showZAxisDescriptionButton; Gtk::CheckButton _manualXAxisDescription, _manualYAxisDescription, _manualZAxisDescription; Gtk::Entry _titleEntry, _xAxisDescriptionEntry, _yAxisDescriptionEntry, _zAxisDescriptionEntry; }; #endif // IMAGEPROPERTIESWINDOW_H aoflagger-v3.4.0/rfigui/opendialog.h0000644000175000017500000000452714507760372016123 0ustar olesoles #ifndef OPEN_DIALOG_H #define OPEN_DIALOG_H #include #include "../imagesets/msoptions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class OpenDialog : public Gtk::Dialog { public: explicit OpenDialog(class RFIGuiWindow& rfiGuiWindow); const std::vector& Selection() const { return _selection; } void SetSelection(const std::vector& selection); MSOptions GetOptions() const; void ActivateOptionsTab() { _notebook.set_current_page(1); } private: void onSelectFile(); void onUnselectFile(); void onFileListSelectionChanged(); void onOpen(); void initDataColumnButtons(size_t& gridRow); void initReadingModeButtons(size_t& gridRow); void initBaselineAveragingButtons(size_t& gridRow); RFIGuiWindow& _rfiGuiWindow; Gtk::Notebook _notebook; Gtk::VBox _fileTab; Gtk::Grid _optionsTab; // File tab elements Gtk::FileChooserWidget _fileChooser; Gtk::HBox _fileButtonBox; Gtk::Button _selectButton; Gtk::Button _unselectButton; Gtk::ScrolledWindow _fileScroller; Gtk::ListViewText _fileList; Gtk::Button* _openButton; std::vector _selection; // Options tab elements Gtk::HBox _intervalBox; Gtk::Label _dataColumnLabel; Gtk::ComboBoxText _dataColumnCombo; Gtk::Grid _otherColumnGrid; Gtk::Label _otherColumnLabel; Gtk::Entry _otherColumnEntry; Gtk::CheckButton _combineSPWsCB; Gtk::CheckButton _concatenateFrequency; Gtk::Separator _columnSeparator; Gtk::Label _readingModeLabel; Gtk::Label _readingModeExplanation; Gtk::ComboBoxText _readingModeCombo; Gtk::Separator _readingSeparator; Gtk::CheckButton _baselineAveragingCB; Gtk::ComboBoxText _baselineAveragingCombo; Gtk::CheckButton _baIncludeAutosCB, _baIncludeFlaggedCB; Gtk::RadioButton _baNoDifference, _baTimeDifference, _baFrequencyDifference; Gtk::Separator _baselineAveragingSeparator; Gtk::CheckButton _intervalCB; Gtk::Entry _intervalStartEntry, _intervalEndEntry; Gtk::Label _intervalExplanation; // Other Gtk::ButtonBox _bottomButtonBox; }; #endif aoflagger-v3.4.0/rfigui/strategyeditor.cpp0000644000175000017500000001220514507760372017376 0ustar olesoles#include "strategyeditor.h" StrategyEditor::StrategyEditor() { _text.override_font(Pango::FontDescription("monospace")); _text.set_wrap_mode(Gtk::WrapMode::WRAP_WORD); add(_text); _tagKeyword = _text.get_buffer()->create_tag(); _tagKeyword->property_weight().set_value(Pango::WEIGHT_BOLD); _tagComment = _text.get_buffer()->create_tag(); _tagComment->property_style().set_value(Pango::STYLE_ITALIC); Gdk::RGBA blue; blue.set_rgba(0.13, 0.0, 0.53); _tagComment->property_foreground_rgba().set_value(blue); _tagString = _text.get_buffer()->create_tag(); Gdk::RGBA gold; gold.set_rgba(0.68, 0.49, 0.0); _tagString->property_foreground_rgba().set_value(gold); _tagFunctionName = _text.get_buffer()->create_tag(); Gdk::RGBA red; red.set_rgba(0.65, 0.1, 0.1); _tagFunctionName->property_foreground_rgba().set_value(red); _tagHighlight = _text.get_buffer()->create_tag(); Gdk::RGBA highlred; highlred.set_rgba(1.0, 0.4, 0.4); _tagHighlight->property_background_rgba().set_value(highlred); _text.get_buffer()->signal_changed().connect([&]() { updateChanges(); }); } bool isAlpha(int c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; } bool isAlphaNumeric(int c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; } void StrategyEditor::parseWord(ParseInfo& p, Gtk::TextBuffer::iterator start, Gtk::TextBuffer::iterator end) { const std::string word(start, end); const bool isKeyword = word == "and" || word == "break" || word == "do" || word == "else" || word == "elseif" || word == "end" || word == "false" || word == "for" || word == "function" || word == "if" || word == "in" || word == "local" || word == "nil" || word == "not" || word == "or" || word == "repeat" || word == "return" || word == "then" || word == "true" || word == "until" || word == "while"; if (isKeyword) { _text.get_buffer()->apply_tag(_tagKeyword, start, end); if (word == "function") p.state = ParseInfo::FunctionStart; } else { if (p.state == ParseInfo::FunctionStart) { _text.get_buffer()->apply_tag(_tagFunctionName, start, end); p.state = ParseInfo::Clear; } } } void StrategyEditor::updateHighlighting() { const Glib::RefPtr buffer = _text.get_buffer(); auto iter = buffer->begin(); buffer->remove_all_tags(iter, buffer->end()); enum { Clear, InWord, InComment, AfterMinus, LongCommentStart, InLongComment, LongCommentEnd, InDQuote, InQuote } mode = Clear; ParseInfo p{ParseInfo::Clear}; Gtk::TextBuffer::iterator wordStart; size_t lineNr = 1; Gtk::TextBuffer::iterator lineStart; while (iter != buffer->end()) { const int c = *iter; if (c == '\n') { if (lineNr == _highlightLine) { _text.get_buffer()->apply_tag(_tagHighlight, lineStart, iter); } lineStart = iter; ++lineStart; ++lineNr; } switch (mode) { case Clear: case AfterMinus: if (isAlpha(c)) { mode = InWord; wordStart = iter; } else if (c == '-') { if (mode == AfterMinus) { mode = InComment; } else { mode = AfterMinus; wordStart = iter; } } else if (c == '"') { mode = InDQuote; wordStart = iter; } else if (c == '\'') { mode = InQuote; wordStart = iter; } break; case InWord: if (!isAlphaNumeric(c)) { parseWord(p, wordStart, iter); mode = Clear; } break; case InComment: if (c == '\n') { _text.get_buffer()->apply_tag(_tagComment, wordStart, iter); mode = Clear; p.state = ParseInfo::Clear; } else if (c == '[') { mode = LongCommentStart; } break; case LongCommentStart: if (c == '[') mode = InLongComment; else mode = InComment; break; case InLongComment: if (c == ']') mode = LongCommentEnd; break; case LongCommentEnd: if (c == ']') { mode = Clear; Gtk::TextBuffer::iterator next = iter; ++next; _text.get_buffer()->apply_tag(_tagComment, wordStart, next); } break; case InDQuote: if (c == '"') { Gtk::TextBuffer::iterator next = iter; ++next; _text.get_buffer()->apply_tag(_tagString, wordStart, next); mode = Clear; p.state = ParseInfo::Clear; } break; case InQuote: if (c == '\'') { Gtk::TextBuffer::iterator next = iter; ++next; _text.get_buffer()->apply_tag(_tagString, wordStart, next); mode = Clear; p.state = ParseInfo::Clear; } break; } ++iter; } } void StrategyEditor::SetText(const std::string& text) { const Glib::RefPtr buffer = _text.get_buffer(); buffer->set_text(text); } std::string StrategyEditor::GetText() const { return std::string(_text.get_buffer()->get_text()); } aoflagger-v3.4.0/rfigui/rfiguiwindow.h0000644000175000017500000001746314507760372016522 0ustar olesoles#ifndef MSWINDOW_H #define MSWINDOW_H #include #include #include #include #include #include #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "../imagesets/imagesetindex.h" #include "../plot/plotwidget.h" #include "../plot/xyplot.h" #include "timefrequencywidget.h" #include "interfaces.h" #include "plotframe.h" #include "strategyeditor.h" #include "../algorithms/enums.h" namespace Gtk { class RadioMenuItem; } namespace algorithms { class ThresholdConfig; } class HistogramCollection; struct MSOptions; class RFIGuiWindow : public Gtk::Window { public: RFIGuiWindow(class RFIGuiController* controller, const std::string& argv0); ~RFIGuiWindow(); void Update() { _timeFrequencyWidget.Update(); } bool HasImage() const { return _timeFrequencyWidget.HasImage(); } Mask2DCPtr Mask() const { return GetOriginalData().GetSingleMask(); } Mask2DCPtr AltMask() const { return GetActiveData().GetSingleMask(); } TimeFrequencyData GetActiveData() const; const TimeFrequencyData& GetOriginalData() const; PlotWidget& GetHeatMapWidget() { return _timeFrequencyWidget.GetHeatMapWidget(); } TimeFrequencyWidget& GetTimeFrequencyWidget() { return _timeFrequencyWidget; } algorithms::ThresholdConfig& HighlightConfig(); void SetHighlighting(bool newValue); TimeFrequencyMetaDataCPtr SelectedMetaData(); void onExecuteStrategyFinished(bool successfull); void onExecuteStrategyError(const std::string& error); void OpenPaths(const std::vector& paths); void OpenMS(const std::vector& filenames, const MSOptions& options); void ShowHistogram(HistogramCollection& histogramCollection); class RFIGuiController& Controller() { return *_controller; } // void UpdateImageSetIndex(); void OpenGotoWindow() { onGoToPressed(); } void SetBaselineInfo(bool isEmpty, bool hasMultipleBaselines, const std::string& name, const std::string& description); void SetImageSetIndex(const imagesets::ImageSetIndex& newImageSetIndex); private: bool onClose(GdkEventAny* event); /// Returns 'false' if the user wants to cancel the operation bool askToSaveChanges(); void onTFWidgetMouseMoved(double x, double y); void onTFScroll(double x, double y, int direction); void onToggleFlags(); void onTogglePolarizations(); void onToggleImage(); void onTFZoomChanged(); void onZoomFit(); void onZoomIn(); void onZoomOut(); void onZoomSelect(); // File menu void onOpen(); void onOpenRecent(size_t index); void updateRecentFiles(); void updateOpenStrategyMenu(); void onSaveBaselineFlags(); void onClose(); void onExportBaseline(); void onQuit() { hide(); } // View menu void onViewData(); void onViewStrategy(); void onViewTimePlot(); // Strategy menu void onExecuteLuaStrategy(); void onStrategyNewEmpty(); void onStrategyNewTemplate(); void onStrategyNewDefault(); void onStrategyOpen(); void onStrategyOpenDefault(const std::string& name); void onStrategySave(); void onStrategySaveAs(); // Browse menu void loadWithProgress(); void onLoadPrevious(); void onLoadNext(); void onSelectImage(); // Data menu void onVisualizedToOriginalPressed(); void onClearOriginalFlagsPressed(); void onClearAltFlagsPressed(); void handleAveraging(bool spectrally); void keepPhasePart( enum TimeFrequencyData::ComplexRepresentation phaseRepresentation); void onKeepRealPressed() { keepPhasePart(TimeFrequencyData::RealPart); } void onKeepImaginaryPressed() { keepPhasePart(TimeFrequencyData::ImaginaryPart); } void onKeepPhasePressed() { keepPhasePart(TimeFrequencyData::PhasePart); } void keepPolarisation(aocommon::PolarizationEnum polarisation); void onKeepStokesIPressed() { keepPolarisation(aocommon::Polarization::StokesI); } void onKeepStokesQPressed() { keepPolarisation(aocommon::Polarization::StokesQ); } void onKeepStokesUPressed() { keepPolarisation(aocommon::Polarization::StokesU); } void onKeepStokesVPressed() { keepPolarisation(aocommon::Polarization::StokesV); } void onKeepRRPressed() { keepPolarisation(aocommon::Polarization::RR); } void onKeepRLPressed() { keepPolarisation(aocommon::Polarization::RL); } void onKeepLRPressed() { keepPolarisation(aocommon::Polarization::LR); } void onKeepLLPressed() { keepPolarisation(aocommon::Polarization::LL); } void onKeepXXPressed() { keepPolarisation(aocommon::Polarization::XX); } void onKeepXYPressed() { keepPolarisation(aocommon::Polarization::XY); } void onKeepYXPressed() { keepPolarisation(aocommon::Polarization::YX); } void onKeepYYPressed() { keepPolarisation(aocommon::Polarization::YY); } void onImagePropertiesPressed(); void onOpenTestSetNoise() { openTestSet(algorithms::RFITestSet::Empty); } void onOpenTestSetA() { openTestSet(algorithms::RFITestSet::FullBandBursts); } void onOpenTestSetB() { openTestSet(algorithms::RFITestSet::HalfBandBursts); } void onOpenTestSetC() { openTestSet(algorithms::RFITestSet::VaryingBursts); } void onOpenTestSetD() { openTestSet(algorithms::RFITestSet::VaryingBursts, algorithms::BackgroundTestSet::ThreeSources); } void onOpenTestSetE() { openTestSet(algorithms::RFITestSet::FullBandBursts, algorithms::BackgroundTestSet::FiveSources); } void onOpenTestSetF() { openTestSet(algorithms::RFITestSet::VaryingBursts, algorithms::BackgroundTestSet::FiveSources); } void onOpenTestSetG() { openTestSet(algorithms::RFITestSet::VaryingBursts, algorithms::BackgroundTestSet::FiveFilteredSources); } void onOpenTestSetH() { openTestSet(algorithms::RFITestSet::VaryingBursts, algorithms::BackgroundTestSet::HighFrequency); } void onAddStaticFringe(); void onAdd1SigmaFringe(); void onSetToOne(); void onSetToI(); void onSetToOnePlusI(); void onAddCorrelatorFault(); void onAddNaNs(); void onShowStats(); void onPlotDistPressed(); void onPlotLogLogDistPressed(); void onPlotMeanSpectrumPressed(); void onPlotSumSpectrumPressed(); void onPlotPowerSpectrumPressed(); void onPlotFrequencyScatterPressed(); void onPlotTimeMeanPressed(); void onPlotTimeScatterPressed(); void onPlotSingularValuesPressed(); void onReloadPressed(); void onGoToPressed(); void onLoadExtremeBaseline(bool longest); void onLoadMedianBaseline(); void onMultiplyData(); void onSegment(); void onCluster(); void onClassify(); void onRemoveSmallSegments(); void onUnrollPhaseButtonPressed(); void onStoreData(); void onRecallData(); void onSubtractDataFromMem(); void showError(const std::string& description); void setSetNameInStatusBar(); void onSimulate(); void onHelpAbout(); void openTestSet(algorithms::RFITestSet rfiSet, algorithms::BackgroundTestSet backgroundSet = algorithms::BackgroundTestSet::Empty); void onControllerStateChange(); void onExecutePythonStrategy(); void updatePolarizations(); void updateTFVisualizationMenu(); size_t getActiveTFVisualization(); class RFIGuiController* _controller; Gtk::Box _mainVBox; TimeFrequencyWidget _timeFrequencyWidget; StrategyEditor _strategyEditor; Gtk::Statusbar _statusbar; std::string _imageSetName, _imageSetIndexDescription; std::unique_ptr _histogramWindow; std::unique_ptr _plotWindow; std::unique_ptr _gotoWindow, _imagePropertiesWindow; std::unique_ptr _progressWindow; std::unique_ptr _menu; TimeFrequencyData _storedData; TimeFrequencyMetaDataCPtr _storedMetaData; std::vector> _tfVisualizationMenuItems; std::thread _taskThread; }; #endif aoflagger-v3.4.0/rfigui/controllers/0000755000175000017500000000000014516225226016161 5ustar olesolesaoflagger-v3.4.0/rfigui/controllers/imagecomparisoncontroller.cpp0000644000175000017500000002437714507760372024171 0ustar olesoles#include "imagecomparisoncontroller.h" #include "../plotimage.h" using aocommon::Polarization; ImageComparisonController::ImageComparisonController() : _showPP(true), _showPQ(false), _showQP(false), _showQQ(true), _visualizedImage(0) { Clear(); } TimeFrequencyData ImageComparisonController::GetActiveDataFullSize() const { TimeFrequencyData data(_dataList[_visualizedImage].data); getActiveMask(data); return data; } TimeFrequencyData ImageComparisonController::GetActiveData() const { TimeFrequencyData data(GetActiveDataFullSize()); if (!_plot.IsZoomedOut()) { data.Trim(round(_plot.XZoomStart() * data.ImageWidth()), round(_plot.YZoomStart() * data.ImageHeight()), round(_plot.XZoomEnd() * data.ImageWidth()), round(_plot.YZoomEnd() * data.ImageHeight())); } return data; } void ImageComparisonController::Clear() { _plot.Clear(); _dataList.clear(); _dataList.emplace_back("No data", TimeFrequencyData()); _visualizedImage = 0; updateVisualizedImage(); _visualizationListChange.emit(); } void ImageComparisonController::SetNewData(const TimeFrequencyData& data, TimeFrequencyMetaDataCPtr metaData) { _plot.Clear(); _dataList.clear(); _dataList.emplace_back("Original data", data); _visualizedImage = 0; updateVisualizedImage(); _plot.SetOriginalMask(data.GetSingleMask()); _plot.SetMetaData(metaData); _plot.ZoomFit(); _visualizationListChange.emit(); } void ImageComparisonController::getFirstAvailablePolarization(bool& pp, bool& pq, bool& qp, bool& qq) const { const TimeFrequencyData& selectedData = _dataList[_visualizedImage].data; if (selectedData.IsEmpty()) { pp = true; pq = false; qp = false; qq = true; } else { bool hasXX = selectedData.HasPolarization(Polarization::XX), hasXY = selectedData.HasPolarization(Polarization::XY), hasYX = selectedData.HasPolarization(Polarization::YX), hasYY = selectedData.HasPolarization(Polarization::YY), hasRR = selectedData.HasPolarization(Polarization::RR), hasRL = selectedData.HasPolarization(Polarization::RL), hasLR = selectedData.HasPolarization(Polarization::LR), hasLL = selectedData.HasPolarization(Polarization::LL), hasI = selectedData.HasPolarization(Polarization::StokesI), hasQ = selectedData.HasPolarization(Polarization::StokesQ), hasU = selectedData.HasPolarization(Polarization::StokesU), hasV = selectedData.HasPolarization(Polarization::StokesV); if (hasXX || hasRR || hasI) { pp = true; pq = false; qp = false; qq = false; } else if (hasYY || hasLL || hasV) { pp = false; pq = false; qp = false; qq = true; } else if (hasXY || hasRL || hasQ) { pp = false; pq = true; qp = false; qq = false; } else if (hasYX || hasLR || hasU) { pp = false; pq = false; qp = true; qq = false; } else { pp = true; pq = false; qp = false; qq = true; } } } void ImageComparisonController::TryVisualizePolarizations(bool& pp, bool& pq, bool& qp, bool& qq) const { const TimeFrequencyData& selectedData = _dataList[_visualizedImage].data; if (selectedData.IsEmpty()) { pp = true; pq = false; qp = false; qq = true; } else { bool hasXX = selectedData.HasPolarization(Polarization::XX), hasXY = selectedData.HasPolarization(Polarization::XY), hasYX = selectedData.HasPolarization(Polarization::YX), hasYY = selectedData.HasPolarization(Polarization::YY), hasRR = selectedData.HasPolarization(Polarization::RR), hasRL = selectedData.HasPolarization(Polarization::RL), hasLR = selectedData.HasPolarization(Polarization::LR), hasLL = selectedData.HasPolarization(Polarization::LL), hasI = selectedData.HasPolarization(Polarization::StokesI), hasQ = selectedData.HasPolarization(Polarization::StokesQ), hasU = selectedData.HasPolarization(Polarization::StokesU), hasV = selectedData.HasPolarization(Polarization::StokesV); if (pp && qq) { pq = false; qp = false; if ((hasXX && !hasYY) || (hasRR && !hasLL) || (hasI && !hasV)) qq = false; else if ((hasYY && !hasXX) || (hasLL && !hasRR) || (hasV && !hasI)) pp = false; else if (!hasXX && !hasYY && !hasRR && !hasLL && !hasI && !hasV) getFirstAvailablePolarization(pp, pq, qp, qq); } else if (pq && qp) { pp = false; qq = false; if ((hasXY && !hasYX) || (hasRL && !hasLR) || hasQ) qp = false; else if ((hasYX && !hasXY) || (hasLR && !hasRL) || hasU) pq = false; else if (!hasXY && !hasYX && !hasRL && !hasLR && !hasU) getFirstAvailablePolarization(pp, pq, qp, qq); } else if (pp) { if (!hasXX && !hasRR && !hasI) getFirstAvailablePolarization(pp, pq, qp, qq); } else if (pq) { if (!hasXY && !hasRL && !hasQ) getFirstAvailablePolarization(pp, pq, qp, qq); } else if (qp) { if (!hasYX && !hasLR && !hasU) getFirstAvailablePolarization(pp, pq, qp, qq); } else if (qq) { if (!hasYY && !hasLL && !hasV) getFirstAvailablePolarization(pp, pq, qp, qq); } } } Mask2DCPtr ImageComparisonController::getSelectedPolarizationMask( const TimeFrequencyData& data) const { if (data.MaskCount() == 0) { return Mask2DCPtr(); } else if (data.MaskCount() == 1) { return data.GetSingleMask(); } else { if (data.MaskCount() == 4) { if (_showPP && _showQQ) { Mask2DPtr mask = Mask2D::MakePtr(*data.GetMask(0)); mask->Join(*data.GetMask(3)); return mask; } else if (_showPQ && _showQP) { Mask2DPtr mask = Mask2D::MakePtr(*data.GetMask(1)); mask->Join(*data.GetMask(2)); return mask; } else if (_showPP) { return data.GetMask(0); } else if (_showPQ) { return data.GetMask(1); } else if (_showQP) { return data.GetMask(2); } else { // if(_showQQ) return data.GetMask(3); } } else { // data->MaskCount() == 2 if (_showPP && _showQQ) { Mask2DPtr mask = Mask2D::MakePtr(*data.GetMask(0)); mask->Join(*data.GetMask(1)); return mask; } else if (_showPP) { return data.GetMask(0); } else { // if(_showQQ) return data.GetMask(1); } } } } void ImageComparisonController::updateVisualizedImageAndMask() { TimeFrequencyData* data; if (_visualizedImage == 0) data = &_dataList.back().data; else data = &_dataList[_visualizedImage].data; if (_dataList.size() > 1) { // getSelectedPolarizationMask may return nullptr, but that is fine _plot.SetAlternativeMask(getSelectedPolarizationMask(*data)); } _plot.SetOriginalMask(getSelectedPolarizationMask(_dataList.front().data)); updateVisualizedImage(); } void ImageComparisonController::updateVisualizedImage() { Image2DCPtr image; const TimeFrequencyData& selectedData = _dataList[_visualizedImage].data; if (!selectedData.IsEmpty()) { if (_showPP && _showQQ) { if ((selectedData.HasPolarization(Polarization::XX) && selectedData.HasPolarization(Polarization::YY)) || (selectedData.HasPolarization(Polarization::RR) && selectedData.HasPolarization(Polarization::LL)) || (selectedData.HasPolarization(Polarization::StokesI))) image = selectedData.Make(Polarization::StokesI).GetSingleImage(); } else if (_showQP && _showPQ) { if (selectedData.HasPolarization(Polarization::XY) && selectedData.HasPolarization(Polarization::YX)) image = selectedData.Make(Polarization::StokesU).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::RL) && selectedData.HasPolarization(Polarization::LR)) image = selectedData.Make(Polarization::StokesQ).GetSingleImage(); } else if (_showPP) { if (selectedData.HasPolarization(Polarization::XX)) image = selectedData.Make(Polarization::XX).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::RR)) image = selectedData.Make(Polarization::RR).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::StokesI)) image = selectedData.Make(Polarization::StokesI).GetSingleImage(); } else if (_showPQ) { if (selectedData.HasPolarization(Polarization::XY)) image = selectedData.Make(Polarization::XY).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::RL)) image = selectedData.Make(Polarization::RL).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::StokesQ)) image = selectedData.Make(Polarization::StokesQ).GetSingleImage(); } else if (_showQP) { if (selectedData.HasPolarization(Polarization::YX)) image = selectedData.Make(Polarization::YX).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::LR)) image = selectedData.Make(Polarization::LR).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::StokesU)) image = selectedData.Make(Polarization::StokesU).GetSingleImage(); } else if (_showQQ) { if (selectedData.HasPolarization(Polarization::YY)) image = selectedData.Make(Polarization::YY).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::LL)) image = selectedData.Make(Polarization::LL).GetSingleImage(); else if (selectedData.HasPolarization(Polarization::StokesV)) image = selectedData.Make(Polarization::StokesV).GetSingleImage(); } } if (image == nullptr) _plot.Clear(); else _plot.SetImage(std::unique_ptr(new PlotImage(std::move(image)))); } void ImageComparisonController::ClearAllButOriginal() { if (_dataList.size() > 1) { _dataList.erase(_dataList.begin() + 1, _dataList.end()); SetVisualization(0); _visualizationListChange.emit(); } } aoflagger-v3.4.0/rfigui/controllers/rfiguicontroller.h0000644000175000017500000001343214507760372021734 0ustar olesoles#ifndef RFIGUI_CONTROLLER_H #define RFIGUI_CONTROLLER_H #include #include "../../structures/timefrequencydata.h" #include "../../structures/timefrequencymetadata.h" #include "../../imagesets/imagesetindex.h" #include "../settings.h" #include "../../algorithms/enums.h" #include "imagecomparisoncontroller.h" #include #include #include namespace imagesets { class BaselineData; } struct MSOptions; class XYPlot; class RFIGuiController { public: RFIGuiController(); ~RFIGuiController(); void AttachWindow(class RFIGuiWindow* rfiGuiWindow) { _rfiGuiWindow = rfiGuiWindow; } bool AreOriginalFlagsShown() const { return _showOriginalFlags; } void SetShowOriginalFlags(bool showFlags) { if (_showOriginalFlags != showFlags) { _showOriginalFlags = showFlags; _signalStateChange(); } } bool AreAlternativeFlagsShown() const { return _showAlternativeFlags; } void SetShowAlternativeFlags(bool showFlags) { if (_showAlternativeFlags != showFlags) { _showAlternativeFlags = showFlags; _signalStateChange(); } } bool IsPPShown() const { return _showPP; } bool IsPQShown() const { return _showPQ; } bool IsQPShown() const { return _showQP; } bool IsQQShown() const { return _showQQ; } void SetShowPP(bool showPP) { if (showPP != _showPP) { if (showPP || _showPQ || _showQP || _showQQ) { _showPP = showPP; if (_showPP) { _showPQ = false; _showQP = false; } } CheckPolarizations(true); } } void SetShowPQ(bool showPQ) { if (showPQ != _showPQ) { if (showPQ || _showPP || _showQP || _showQQ) { _showPQ = showPQ; if (_showPQ) { _showPP = false; _showQQ = false; } } CheckPolarizations(true); } } void SetShowQP(bool showQP) { if (showQP != _showQP) { if (showQP || _showPP || _showPQ || _showQQ) { _showQP = showQP; if (_showQP) { _showPP = false; _showQQ = false; } } CheckPolarizations(true); } } void SetShowQQ(bool showQQ) { if (showQQ != _showQQ) { if (showQQ || _showPP || _showPQ || _showQP) { _showQQ = showQQ; if (_showQQ) { _showPQ = false; _showQP = false; } } CheckPolarizations(true); } } sigc::signal& SignalStateChange() { return _signalStateChange; } sigc::signal& SignalRecentFilesChanged() { return _signalRecentFilesChanged; } void PlotDist(); void PlotLogLogDist(); void PlotMeanSpectrum() { plotMeanSpectrum(false); } void PlotSumSpectrum() { plotMeanSpectrum(true); } void PlotPowerSpectrum(); void PlotFrequencyScatter(); void PlotTimeMean(); void DrawTimeMean(XYPlot& plot); void PlotTimeScatter(); void PlotSingularValues(); void OpenMS(const std::vector& filenames, const MSOptions& options); void OpenTestSet(algorithms::RFITestSet rfiSet, algorithms::BackgroundTestSet backgroundSet); std::vector RecentFiles() const; bool IsImageLoaded() const; TimeFrequencyData ActiveData() const; TimeFrequencyData OriginalData() const; TimeFrequencyMetaDataCPtr SelectedMetaData() const; class PlotManager& PlotManager() { return *_plotManager; } void ExecutePythonStrategy(); void ExecuteLuaStrategy(class ProgressListener& listener); void JoinLuaThread(); void CloseImageSet(); bool HasImageSet() const { return _imageSet != nullptr; } void SetImageSet(std::unique_ptr newImageSet); void SetImageSetIndex(const imagesets::ImageSetIndex& newImageSetIndex); imagesets::ImageSet& GetImageSet() const { return *_imageSet; } const imagesets::ImageSetIndex& GetImageSetIndex() const { return _imageSetIndex; } void LoadCurrentTFDataAsync(class ProgressListener& progress); void LoadCurrentTFDataFinish(bool success); std::mutex& IOMutex() { return _ioMutex; } ImageComparisonController& TFController() { return _tfController; } void Open(const std::vector& filenames); void SaveBaselineFlags(); void CheckPolarizations(bool forceSignal = false); void GetAvailablePolarizations(bool& pp, bool& pq, bool& qp, bool& qq) const; void SaveBaselineAsRfibl(const std::string& filename); void SaveBaselineAsNpy(const std::string& filename); void NewDefaultStrategy(); void NewEmptyStrategy(); void NewTemplateStrategy(); void OpenStrategy(const std::string& filename); bool HasOpenStrategy() const { return !_openStrategyFilename.empty(); } const std::string& StrategyFilename() const { return _openStrategyFilename; } void SaveStrategy(); void SaveStrategyAs(const std::string& filename); std::string GetWorkStrategyText() const; void SetWorkStrategyText(const std::string& text); private: void plotMeanSpectrum(bool weight); void setRecentFile(const std::string& filename); void open(std::unique_ptr imageSet); void OpenMsConcatenated(const std::vector& filenames, const MSOptions& options); bool _showOriginalFlags, _showAlternativeFlags; bool _showPP, _showPQ, _showQP, _showQQ; sigc::signal _signalStateChange; sigc::signal _signalRecentFilesChanged; class RFIGuiWindow* _rfiGuiWindow; class ImageComparisonController _tfController; Settings _settings; std::unique_ptr _plotManager; std::unique_ptr _imageSet; imagesets::ImageSetIndex _imageSetIndex; std::unique_ptr _tempLoadedBaseline; std::mutex _ioMutex; std::thread _processingThread; TimeFrequencyData _scriptTFData; std::unique_ptr _scriptData; std::string _openStrategyFilename; }; #endif aoflagger-v3.4.0/rfigui/controllers/imagecomparisoncontroller.h0000644000175000017500000001267514507760372023634 0ustar olesoles#ifndef IMAGECOMPARISONCONTROLLER_H #define IMAGECOMPARISONCONTROLLER_H #include #include #include #include "../../structures/image2d.h" #include "../../structures/timefrequencydata.h" #include "../../structures/timefrequencymetadata.h" #include "../../structures/segmentedimage.h" #include "../maskedheatmap.h" class ImageComparisonController { public: ImageComparisonController(); void Clear(); void SetNewData(const class TimeFrequencyData& image, TimeFrequencyMetaDataCPtr metaData); /** * The currently visible data. This includes the masks that are activated and * the data is trimmed to the zoomed region. In case none of the masks are * visualized, the returned data has an unset mask. */ TimeFrequencyData GetActiveData() const; /** * Same as @ref GetActiveData(), but full size ("zoomed out"). */ TimeFrequencyData GetActiveDataFullSize() const; /** * The full-size "original" data, including the original mask. */ TimeFrequencyData& OriginalData() { return _dataList.front().data; } const TimeFrequencyData& OriginalData() const { return _dataList.front().data; } void SetAltMaskData(const TimeFrequencyData& data) { if (_visualizedImage == 0) _dataList.back().data = data; else _dataList[_visualizedImage].data = data; updateVisualizedImageAndMask(); } /** * The full-size alternative mask */ TimeFrequencyData AltMaskData() const { if (_visualizedImage == 0) { if (_dataList.size() > 1) { return _dataList.back().data; } else { TimeFrequencyData empty = _dataList.back().data; empty.SetNoMask(); return empty; } } else { return _dataList[_visualizedImage].data; } } size_t AddVisualization(const std::string& label, const TimeFrequencyData& data) { _dataList.emplace_back(label, data); size_t v = _dataList.size() - 1; // If the first image is visualized, adding a new last visualization // affects the visualized flags on top of the first image. if (_visualizedImage == 0) updateVisualizedImageAndMask(); _visualizationListChange.emit(); return v; } template void SetVisualizationData(size_t index, T&& data) { _dataList[index].data = std::forward(data); if (index == 0 || _visualizedImage == index || (_visualizedImage == 0 && index == _dataList.size() - 1)) updateVisualizedImageAndMask(); } /** * Currently visualized data. This is the full set, so "zoomed out". * In contrast to GetActiveData(), these data always include the mask * that is part of the visualization. */ const TimeFrequencyData& VisualizedData() const { return _dataList[_visualizedImage].data; } void SetVisualizedData(const TimeFrequencyData& data) { _dataList[_visualizedImage].data = data; updateVisualizedImageAndMask(); } size_t VisualizationCount() const { return _dataList.size(); } size_t VisualizedIndex() const { return _visualizedImage; } const TimeFrequencyData& GetVisualizationData(size_t index) const { return _dataList[index].data; } const std::string& GetVisualizationLabel(size_t index) { return _dataList[index].label; } void SetVisualization(size_t visualizationIndex) { if (_visualizedImage != visualizationIndex && _visualizedImage < _dataList.size()) { _visualizedImage = visualizationIndex; updateVisualizedImageAndMask(); } } void TryVisualizePolarizations(bool& pp, bool& pq, bool& qp, bool& qq) const; void SetVisualizedPolarization(bool pp, bool pq, bool qp, bool qq) { if (_showPP != pp || _showPQ != pq || _showQP != qp || _showQQ != qq) { _showPP = pp; _showPQ = pq; _showQP = qp; _showQQ = qq; updateVisualizedImageAndMask(); } } void ClearAllButOriginal(); MaskedHeatMap& Plot() { return _plot; } const MaskedHeatMap& Plot() const { return _plot; } sigc::signal& VisualizationListChange() { return _visualizationListChange; } private: void getFirstAvailablePolarization(bool& pp, bool& pq, bool& qp, bool& qq) const; void updateVisualizedImageAndMask(); void updateVisualizedImage(); Mask2DCPtr getSelectedPolarizationMask(const TimeFrequencyData& data) const; void getActiveMask(TimeFrequencyData& data) const { bool orActive = _plot.ShowOriginalMask() && _dataList[0].data.MaskCount() != 0; size_t altMaskIndex = _visualizedImage; if (altMaskIndex == 0) altMaskIndex = _dataList.size() - 1; bool altActive = _plot.ShowAlternativeMask() && altMaskIndex != 0 && _dataList[altMaskIndex].data.MaskCount() != 0; if (orActive && altActive) { data.SetMask(_dataList[0].data); data.JoinMask(_dataList[altMaskIndex].data); } else if (orActive) { data.SetMask(_dataList[0].data); } else if (altActive) { data.SetMask(_dataList[altMaskIndex].data); } else { data.SetMasksToValue(); } } MaskedHeatMap _plot; bool _showPP, _showPQ, _showQP, _showQQ; size_t _visualizedImage; struct DataEntry { DataEntry(const std::string& _label, const TimeFrequencyData& _data) { label = _label; data = _data; } std::string label; TimeFrequencyData data; }; std::vector _dataList; TimeFrequencyMetaDataCPtr _metaData; sigc::signal _visualizationListChange; }; #endif aoflagger-v3.4.0/rfigui/controllers/rfiguicontroller.cpp0000644000175000017500000004756414507760372022304 0ustar olesoles#include "rfiguicontroller.h" #include "../../algorithms/svdmitigater.h" #include "../../algorithms/testsetgenerator.h" #include "../../python/pythonstrategy.h" #include "../../imagesets/h5imageset.h" #include "../../imagesets/imageset.h" #include "../../imagesets/joinedspwset.h" #include "../../imagesets/msimageset.h" #include "../../imagesets/msoptions.h" #include "../../imagesets/multibandmsimageset.h" #include "../../lua/luastrategy.h" #include "../../lua/scriptdata.h" #include "../../lua/telescopefile.h" #include "../../msio/singlebaselinefile.h" #include "../../plot/plotmanager.h" #include "../../quality/histogramcollection.h" #include "../../structures/spatialmatrixmetadata.h" #include "../../util/multiplot.h" #include "../../util/progress/progresslistener.h" #include "../../util/process.h" #include "../../util/rfiplots.h" #include "../rfiguiwindow.h" #include "../../external/npy.hpp" #include "imagecomparisoncontroller.h" #include #include #include #include #include #include #include using algorithms::SVDMitigater; using algorithms::TestSetGenerator; RFIGuiController::RFIGuiController() : _showOriginalFlags(true), _showAlternativeFlags(true), _showPP(true), _showPQ(false), _showQP(false), _showQQ(true), _rfiGuiWindow(nullptr), _tfController() { _plotManager.reset(new class PlotManager()); _settings.Load(); NewDefaultStrategy(); } RFIGuiController::~RFIGuiController() { try { _settings.Save(); } catch (std::exception& e) { Logger::Error << "Failed to write config file: " << e.what() << '\n'; } } bool RFIGuiController::IsImageLoaded() const { return _tfController.Plot().HasImage(); } TimeFrequencyData RFIGuiController::ActiveData() const { return _tfController.GetActiveData(); } TimeFrequencyData RFIGuiController::OriginalData() const { return _tfController.OriginalData(); } TimeFrequencyMetaDataCPtr RFIGuiController::SelectedMetaData() const { return _tfController.Plot().GetSelectedMetaData(); } void RFIGuiController::plotMeanSpectrum(bool weight) { if (IsImageLoaded()) { const std::string title = weight ? "Sum spectrum" : "Mean spectrum"; XYPlot& plot = _plotManager->NewPlot2D(title); const TimeFrequencyData data = ActiveData(); Mask2DCPtr mask = Mask2D::CreateSetMaskPtr(data.ImageWidth(), data.ImageHeight()); XYPointSet& beforeSet = plot.StartLine("Without flagging"); if (weight) RFIPlots::MakeMeanSpectrumPlot(beforeSet, data, mask, SelectedMetaData()); else RFIPlots::MakeMeanSpectrumPlot(beforeSet, data, mask, SelectedMetaData()); mask.reset(new Mask2D(*data.GetSingleMask())); if (!mask->AllFalse()) { XYPointSet& afterSet = plot.StartLine("Flagged"); if (weight) RFIPlots::MakeMeanSpectrumPlot(afterSet, data, mask, SelectedMetaData()); else RFIPlots::MakeMeanSpectrumPlot(afterSet, data, mask, SelectedMetaData()); } _plotManager->Update(); } } void RFIGuiController::PlotDist() { if (IsImageLoaded()) { XYPlot& plot = _plotManager->NewPlot2D("Distribution"); const TimeFrequencyData activeData = ActiveData(); const Image2DCPtr image = activeData.GetSingleImage(); Mask2DPtr mask = Mask2D::CreateSetMaskPtr(image->Width(), image->Height()); XYPointSet& totalSet = plot.StartLine("Total"); RFIPlots::MakeDistPlot(totalSet, image, mask); XYPointSet& uncontaminatedSet = plot.StartLine("Uncontaminated"); mask.reset(new Mask2D(*activeData.GetSingleMask())); RFIPlots::MakeDistPlot(uncontaminatedSet, image, mask); mask->Invert(); XYPointSet& rfiSet = plot.StartLine("RFI"); RFIPlots::MakeDistPlot(rfiSet, image, mask); _plotManager->Update(); } } void RFIGuiController::PlotLogLogDist() { if (IsImageLoaded()) { const TimeFrequencyData activeData = ActiveData(); HistogramCollection histograms(activeData.PolarizationCount()); for (unsigned p = 0; p != activeData.PolarizationCount(); ++p) { const TimeFrequencyData polData(activeData.MakeFromPolarizationIndex(p)); const Image2DCPtr image = polData.GetSingleImage(); const Mask2DCPtr mask = Mask2D::MakePtr(*polData.GetSingleMask()); histograms.Add(0, 1, p, image, mask); } _rfiGuiWindow->ShowHistogram(histograms); } } void RFIGuiController::PlotPowerSpectrum() { if (IsImageLoaded()) { XYPlot& plot = _plotManager->NewPlot2D("Power spectrum"); plot.YAxis().SetLogarithmic(true); const TimeFrequencyData data = ActiveData(); std::array images; if (data.ComplexRepresentation() == TimeFrequencyData::ComplexParts) { images = data.GetSingleComplexImage(); } else { images[0] = data.GetSingleImage(); images[1] = images[0]; } Mask2DPtr mask = Mask2D::CreateSetMaskPtr(images[0]->Width(), images[0]->Height()); XYPointSet& beforeSet = plot.StartLine("Flags not applied"); RFIPlots::MakePowerSpectrumPlot(beforeSet, *images[0], *images[1], *mask, SelectedMetaData().get()); mask = Mask2D::MakePtr(*data.GetSingleMask()); if (!mask->AllFalse()) { XYPointSet& afterSet = plot.StartLine("Flags applied"); RFIPlots::MakePowerSpectrumPlot(afterSet, *images[0], *images[1], *mask, SelectedMetaData().get()); } _plotManager->Update(); } } void RFIGuiController::PlotFrequencyScatter() { if (IsImageLoaded()) { MultiPlot plot(_plotManager->NewPlot2D("Frequency scatter"), 4); RFIPlots::MakeFrequencyScatterPlot(plot, ActiveData(), SelectedMetaData()); plot.Finish(); _plotManager->Update(); } } void RFIGuiController::DrawTimeMean(XYPlot& plot) { plot.SetTitle("Mean over time"); plot.YAxis().SetLogarithmic(true); plot.XAxis().SetType(AxisType::kTime); const TimeFrequencyData activeData = ActiveData(); const Image2DCPtr image = activeData.GetSingleImage(); Mask2DPtr mask = Mask2D::CreateSetMaskPtr(image->Width(), image->Height()); XYPointSet& totalPlot = plot.StartLine("Without flagging"); RFIPlots::MakePowerTimePlot(totalPlot, image, mask, SelectedMetaData()); mask = Mask2D::MakePtr(*activeData.GetSingleMask()); if (!mask->AllFalse()) { XYPointSet& uncontaminatedPlot = plot.StartLine("With flagging"); RFIPlots::MakePowerTimePlot(uncontaminatedPlot, image, mask, SelectedMetaData()); } } void RFIGuiController::PlotTimeMean() { if (IsImageLoaded()) { XYPlot& plot = _plotManager->NewPlot2D("Mean over time"); DrawTimeMean(plot); _plotManager->Update(); } } void RFIGuiController::PlotTimeScatter() { if (IsImageLoaded()) { MultiPlot plot(_plotManager->NewPlot2D("Time scatter"), 4); RFIPlots::MakeTimeScatterPlot(plot, ActiveData(), SelectedMetaData()); plot.Finish(); _plotManager->Update(); } } void RFIGuiController::PlotSingularValues() { if (IsImageLoaded()) { XYPlot& plot = _plotManager->NewPlot2D("Singular values"); SVDMitigater::CreateSingularValueGraph(ActiveData(), plot); _plotManager->Update(); } } void RFIGuiController::open(std::unique_ptr imageSet) { std::vector filenames = imageSet->Files(); if (filenames.size() == 1) Logger::Info << "Opened " << filenames[0] << '\n'; else Logger::Info << "Opening multiple files.\n"; SetImageSet(std::move(imageSet)); if (filenames.size() == 1) setRecentFile(filenames[0]); } void RFIGuiController::Open(const std::vector& filenames) { std::unique_lock lock(_ioMutex); MSOptions options; options.ioMode = DirectReadMode; options.baselineIntegration.enable = false; std::unique_ptr imageSet( imagesets::ImageSet::Create(filenames, options)); imageSet->Initialize(); lock.unlock(); open(std::move(imageSet)); } void RFIGuiController::OpenMsConcatenated( const std::vector& filenames, const MSOptions& options) { constexpr size_t kMaxIoThreads = 16; const size_t n_io_threads = std::min( {kMaxIoThreads, aocommon::system::ProcessorCount(), filenames.size()}); std::unique_ptr image_set = std::make_unique( filenames, options.ioMode, options.intervalStart, options.intervalStart, n_io_threads); image_set->Initialize(); open(std::move(image_set)); } void RFIGuiController::OpenMS(const std::vector& filenames, const MSOptions& options) { if (options.concatenateFrequency) { OpenMsConcatenated(filenames, options); return; } std::unique_ptr imageSet( imagesets::ImageSet::Create(filenames, options)); if (imagesets::H5ImageSet* h5ImageSet = dynamic_cast(imageSet.get()); h5ImageSet != nullptr) { h5ImageSet->SetInterval(options.intervalStart, options.intervalEnd); } else if (imagesets::MSImageSet* msImageSet = dynamic_cast(imageSet.get()); msImageSet != nullptr) { msImageSet->SetDataColumnName(options.dataColumnName); msImageSet->SetInterval(options.intervalStart, options.intervalEnd); msImageSet->SetReadUVW(true); if (options.combineSPWs) { msImageSet->Initialize(); imageSet.release(); std::unique_ptr msImageSetPtr(msImageSet); imageSet.reset(new imagesets::JoinedSPWSet(std::move(msImageSetPtr))); } } imageSet->Initialize(); open(std::move(imageSet)); } void RFIGuiController::SaveBaselineFlags() { _imageSet->AddWriteFlagsTask(_imageSetIndex, _tfController.GetActiveDataFullSize()); _imageSet->PerformWriteFlagsTask(); } void RFIGuiController::setRecentFile(const std::string& filename) { std::string absFilename = std::filesystem::absolute(filename).string(); std::vector files = _settings.RecentFiles(); files.emplace(files.begin(), absFilename); if (files.size() > 10) files.resize(10); for (size_t i = 1; i != files.size(); ++i) { std::error_code ec; if (files[i] == absFilename || std::filesystem::equivalent(files[i], absFilename, ec)) { files.erase(files.begin() + i); break; } } _settings.SetRecentFiles(files); _signalRecentFilesChanged.emit(); } std::vector RFIGuiController::RecentFiles() const { std::vector files = _settings.RecentFiles(); std::vector shownFiles; shownFiles.reserve(files.size()); for (size_t i = 0; i != files.size(); ++i) { if (!files[i].empty()) { // Don't return the current open file as a recent file std::error_code ec; const bool isOpen = (HasImageSet() && (files[i] == _imageSet->Files()[0] || std::filesystem::equivalent(files[i], _imageSet->Files()[0], ec))); if (!isOpen) shownFiles.emplace_back(files[i]); } } return shownFiles; } void RFIGuiController::OpenTestSet( algorithms::RFITestSet rfiSet, algorithms::BackgroundTestSet backgroundSet) { size_t width = 1024, height = 512; TimeFrequencyMetaDataCPtr metaData; if (IsImageLoaded()) { const TimeFrequencyData activeData = ActiveData(); width = activeData.ImageWidth(); height = activeData.ImageHeight(); metaData = SelectedMetaData(); } else { metaData.reset(new TimeFrequencyMetaData()); } CloseImageSet(); const TimeFrequencyData data = TestSetGenerator::MakeTestSet(rfiSet, backgroundSet, width, height); _tfController.SetNewData(data, metaData); const char* name = "Simulated test set"; _tfController.Plot().SetTitleText(name); if (_rfiGuiWindow != nullptr) { _rfiGuiWindow->SetBaselineInfo(true, false, name, name); } } void RFIGuiController::ExecutePythonStrategy() { PythonStrategy pythonStrategy; _tfController.ClearAllButOriginal(); TimeFrequencyData data = OriginalData(); ScriptData scriptData; scriptData.SetCanVisualize(true); pythonStrategy.Execute(data, SelectedMetaData(), scriptData); scriptData.SortVisualizations(); for (size_t i = 0; i != scriptData.VisualizationCount(); ++i) { auto v = scriptData.GetVisualization(i); _tfController.AddVisualization(std::get<0>(v), std::get<1>(v)); } _tfController.AddVisualization("Script result", data); _rfiGuiWindow->GetTimeFrequencyWidget().Update(); } void RFIGuiController::ExecuteLuaStrategy(class ProgressListener& listener) { _tfController.ClearAllButOriginal(); _processingThread = std::thread([&]() { try { _scriptTFData = OriginalData(); const TimeFrequencyMetaDataCPtr metaData = _tfController.Plot().GetFullMetaData(); _scriptData.reset(new ScriptData()); _scriptData->SetCanVisualize(true); _scriptData->SetProgressListener(listener); LuaStrategy luaStrategy; luaStrategy.Initialize(); luaStrategy.LoadFile(_settings.GetStrategyFilename().c_str()); luaStrategy.Execute(_scriptTFData, metaData, *_scriptData, "execute"); listener.OnFinish(); } catch (std::exception& e) { listener.OnException(e); } }); } void RFIGuiController::JoinLuaThread() { _processingThread.join(); _scriptData->SortVisualizations(); for (size_t i = 0; i != _scriptData->VisualizationCount(); ++i) { auto v = _scriptData->GetVisualization(i); _tfController.AddVisualization(std::get<0>(v), std::get<1>(v)); } _scriptData.reset(); _tfController.AddVisualization("Script result", std::move(_scriptTFData)); _rfiGuiWindow->GetTimeFrequencyWidget().Update(); _scriptTFData = TimeFrequencyData(); } void RFIGuiController::SetImageSet( std::unique_ptr newImageSet) { _imageSetIndex = newImageSet->StartIndex(); _imageSet = std::move(newImageSet); } void RFIGuiController::SetImageSetIndex( const imagesets::ImageSetIndex& newImageSetIndex) { _imageSetIndex = newImageSetIndex; } void RFIGuiController::CloseImageSet() { _imageSet.reset(); _tfController.Clear(); if (_rfiGuiWindow != nullptr) _rfiGuiWindow->SetBaselineInfo(true, false, "", "No data loaded"); // Closing a file causes the recent files to change, since // the closed file now becomes a recent file. _signalRecentFilesChanged.emit(); } void RFIGuiController::LoadCurrentTFDataAsync(ProgressListener& progress) { try { if (HasImageSet()) { const std::lock_guard lock(_ioMutex); _imageSet->AddReadRequest(_imageSetIndex); _imageSet->PerformReadRequests(progress); _tempLoadedBaseline = _imageSet->GetNextRequested(); } } catch (std::exception& exception) { _tempLoadedBaseline.reset(); progress.OnException(exception); } } void RFIGuiController::LoadCurrentTFDataFinish(bool success) { if (success) { _tfController.SetNewData(std::move(_tempLoadedBaseline->Data()), _tempLoadedBaseline->MetaData()); _tempLoadedBaseline.reset(); // We store these seperate, as they might access the measurement set. This // is not only faster (the names are used in the onMouse.. events) but also // less dangerous, since the set can be simultaneously accessed by another // thread. (thus the io mutex should be locked before calling below // statements). std::string name, description; std::unique_lock lock(_ioMutex); name = GetImageSet().Name(); description = GetImageSet().Description(GetImageSetIndex()); lock.unlock(); _tfController.Plot().SetTitleText(description); if (_rfiGuiWindow != nullptr) { // Disable forward/back buttons when only one baseline is available imagesets::ImageSetIndex firstIndex = _imageSet->StartIndex(); firstIndex.Next(); const bool multipleBaselines = !firstIndex.HasWrapped(); _rfiGuiWindow->SetBaselineInfo(false, multipleBaselines, name, description); } } else { CloseImageSet(); } } void RFIGuiController::CheckPolarizations(bool forceSignal) { const bool pp = _showPP, pq = _showPQ, qp = _showQP, qq = _showQQ; if (!pp && !pq && !qp && !qq) { _showPP = true; _showQQ = true; } _tfController.TryVisualizePolarizations(_showPP, _showPQ, _showQP, _showQQ); if (forceSignal || _showPP != pp || _showPQ != pq || _showQP != qp || _showQQ != qq) _signalStateChange(); } void RFIGuiController::GetAvailablePolarizations(bool& pp, bool& pq, bool& qp, bool& qq) const { bool b[4]; for (size_t i = 0; i != 4; ++i) { // Set b to false except for b[i] for (size_t j = 0; j != 4; ++j) b[j] = (j == i); _tfController.TryVisualizePolarizations(b[0], b[1], b[2], b[3]); switch (i) { case 0: pp = b[0]; break; case 1: pq = b[1]; break; case 2: qp = b[2]; break; case 3: qq = b[3]; break; } } } void RFIGuiController::SaveBaselineAsRfibl(const std::string& filename) { SingleBaselineFile file; file.data = _tfController.OriginalData(); file.metaData = *_tfController.Plot().GetFullMetaData(); file.telescopeName = _imageSet->TelescopeName(); std::ofstream stream(filename); file.Write(stream); } void RFIGuiController::SaveBaselineAsNpy(const std::string& filename) { const TimeFrequencyData& tf_data = _tfController.OriginalData(); std::vector> data = ToComplexVector(tf_data); const std::array shape = { tf_data.PolarizationCount(), tf_data.ImageHeight(), tf_data.ImageWidth()}; npy::SaveArrayAsNumpy(filename, false, shape.size(), shape.data(), data); } void RFIGuiController::NewDefaultStrategy() { _settings.InitializeWorkStrategy(); _openStrategyFilename.clear(); } void RFIGuiController::NewEmptyStrategy() { const std::ofstream file(_settings.GetStrategyFilename()); if (!file) throw std::runtime_error("Error writing new strategy to work file"); _openStrategyFilename.clear(); } void RFIGuiController::NewTemplateStrategy() { std::ofstream file(_settings.GetStrategyFilename()); file << LuaStrategy::GetTemplateScript(); if (!file) throw std::runtime_error("Error writing new strategy to work file"); _openStrategyFilename.clear(); } void RFIGuiController::OpenStrategy(const std::string& filename) { std::error_code ec; if (std::filesystem::equivalent(_settings.GetStrategyFilename(), filename, ec)) throw std::runtime_error("Can't open working Lua strategy"); std::filesystem::copy_file(filename, _settings.GetStrategyFilename(), std::filesystem::copy_options::overwrite_existing); _openStrategyFilename = filename; } void RFIGuiController::SaveStrategy() { std::filesystem::copy_file(_settings.GetStrategyFilename(), _openStrategyFilename, std::filesystem::copy_options::overwrite_existing); } void RFIGuiController::SaveStrategyAs(const std::string& filename) { std::filesystem::copy_file(_settings.GetStrategyFilename(), filename, std::filesystem::copy_options::overwrite_existing); _openStrategyFilename = filename; } std::string RFIGuiController::GetWorkStrategyText() const { const std::ifstream file(_settings.GetStrategyFilename()); if (!file) throw std::runtime_error("Error reading work strategy from file"); std::ostringstream text; text << file.rdbuf(); return text.str(); } void RFIGuiController::SetWorkStrategyText(const std::string& text) { std::ofstream file(_settings.GetStrategyFilename()); if (!file) throw std::runtime_error("Error writing work strategy to file"); file << text; } aoflagger-v3.4.0/rfigui/settings.h0000644000175000017500000001015414507760372015633 0ustar olesoles#ifndef SETTINGS_H #define SETTINGS_H #include #include #include #include #include class SettingValue { public: virtual ~SettingValue() {} virtual std::string ValueToString() const = 0; virtual void SetFromString(const std::string& valueStr) = 0; virtual std::unique_ptr Create() const = 0; }; class StringSetting final : public SettingValue { public: StringSetting() {} StringSetting(const std::string& value) { _value = value; } std::string& Value() { return _value; } const std::string& Value() const { return _value; } std::string ValueToString() const override { return _value; } void SetFromString(const std::string& valueStr) override { _value = valueStr; } std::unique_ptr Create() const override { return std::unique_ptr(new StringSetting(_value)); } private: std::string _value; }; class SettingItem { public: explicit SettingItem(std::unique_ptr defaultValue) : _defaultValue(std::move(defaultValue)) {} bool HasValue() const { return _value != nullptr; } SettingValue& Value() { return *_value; } void SetValue(std::unique_ptr value) { _value = std::move(value); } const SettingValue& DefaultValue() const { return *_defaultValue; } const SettingValue& ValueOrDefault() const { return _value == nullptr ? *_defaultValue : *_value; } void MakeDefault() { _value.reset(); } private: std::unique_ptr _value, _defaultValue; }; class Settings { public: Settings(); static std::string GetConfigDir(); std::string GetStrategyFilename() const; void Load(); void Save() const; void InitializeWorkStrategy(); std::vector RecentFiles() const { return getStrArr("recent-files", 10); } void SetRecentFiles(const std::vector& recentFiles) { return setStrArr("recent-files", recentFiles); } std::vector RecentStrategies() const { return getStrArr("recent-strategies", 10); } void SetRecentStrategies(const std::vector& recentStrategies) { return setStrArr("recent-strategies", recentStrategies); } private: static std::string getConfigFilename(); void initStr(const std::string& key, const std::string& defaultStr) { _settings.emplace( key, std::unique_ptr(new StringSetting(defaultStr))); } void initStrArray(const std::string& key, const std::vector& defaultVal) { for (size_t i = 0; i != defaultVal.size(); ++i) _settings.emplace( key + '[' + std::to_string(i) + ']', std::unique_ptr(new StringSetting(defaultVal[i]))); } void set(const std::string& key, const std::string& value) { auto iter = _settings.find(key); if (iter == _settings.end()) throw std::runtime_error("Unknown setting in settings file: " + key); if (!iter->second.HasValue()) iter->second.SetValue(iter->second.DefaultValue().Create()); iter->second.Value().SetFromString(value); } std::string getStr(const std::string& key) const { return static_cast( _settings.find(key)->second.ValueOrDefault()) .Value(); } void setStr(const std::string& key, const std::string& value) { SettingItem& item = _settings.find(key)->second; if (static_cast(item.DefaultValue()).Value() == value) { item.MakeDefault(); } else { if (!item.HasValue()) item.SetValue(item.DefaultValue().Create()); static_cast(item.Value()).Value() = value; } } std::vector getStrArr(const std::string& key, size_t n) const { std::vector arr(n); for (size_t i = 0; i != n; ++i) arr[i] = getStr(key + '[' + std::to_string(i) + ']'); return arr; } void setStrArr(const std::string& key, const std::vector& values) { for (size_t i = 0; i != values.size(); ++i) setStr(key + '[' + std::to_string(i) + ']', values[i]); } std::map _settings; }; #endif aoflagger-v3.4.0/rfigui/progresswindow.h0000644000175000017500000000306614507760372017073 0ustar olesoles#ifndef PROGRESSWINDOW_H #define PROGRESSWINDOW_H #include "../util/progress/progresslistener.h" #include #include #include #include #include #include #include #include class ProgressWindow : public Gtk::Window, public ProgressListener { public: ProgressWindow(); ~ProgressWindow(); virtual void OnStartTask(const std::string& description) final override; virtual void OnProgress(size_t progress, size_t maxProgress) final override; virtual void OnFinish() final override; virtual void OnException(std::exception& thrownException) final override; sigc::signal& SignalFinished() { return _signalFinished; } sigc::signal& SignalError() { return _signalError; } private: void updateProgress(); Glib::Dispatcher _progressChangeSignal; bool _blockProgressSignal; std::mutex _mutex; sigc::signal _signalFinished; sigc::signal _signalError; Gtk::Label _currentTaskTitleLabel, _currentTaskLabel, _timeElapsedTitleLabel, _timeElapsedLabel, _timeEstimatedTitleLabel, _timeEstimatedLabel; Gtk::Grid _grid; Gtk::ProgressBar _progressBar; boost::posix_time::ptime _startTime, _lastUpdate; bool _started; bool _exceptionQueued; std::string _exceptionType; std::string _exceptionDescription; std::string _taskDescription; size_t _progress, _maxProgress; bool _finished; }; #endif aoflagger-v3.4.0/README0000644000175000017500000000265214507760372013221 0ustar olesoles-- Read-me file for the AOFlagger distribution -- For the latest version and information about installing, go to https://aoflagger.readthedocs.io/ . The quick summary to compile and install, from the aoflagger root directory: mkdir build cd build/ cmake ../ make (or make -j ) sudo make install This will normally work when you have installed all libraries in their default locations. If you have not done so, you might need to tell cmake where the libraries are. The easiest way to do this is by adding search paths to cmake, e.g.: cmake ../ -DCMAKE_PREFIX_PATH=/opt/cep/casacore/ This will include /opt/cep/casacore to the search path. Multiple paths can be specified by separating them with a colon ':'. -- License -- This file is part of the AOFlagger package. Copyright 2008-2022 A. R. Offringa The AOFlagger package is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AOFlagger is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the AOFlagger package. If not, see . aoflagger-v3.4.0/algorithms/0000755000175000017500000000000014516225226014477 5ustar olesolesaoflagger-v3.4.0/algorithms/thresholdtools.cpp0000644000175000017500000005707714507760372020306 0ustar olesoles#include #include #include #include #include #include "../util/rng.h" #include "thresholdtools.h" namespace algorithms { void ThresholdTools::MeanAndStdDev(const Image2D* image, const Mask2D* mask, num_t& mean, num_t& stddev) { // Calculate mean mean = 0.0; size_t count = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (!mask->Value(x, y) && std::isfinite(image->Value(x, y))) { const num_t value = image->Value(x, y); mean += value; count++; } } } mean /= (num_t)count; // Calculate variance stddev = 0.0; count = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (!mask->Value(x, y) && std::isfinite(image->Value(x, y))) { const num_t value = image->Value(x, y); stddev += (value - mean) * (value - mean); count++; } } } stddev = sqrtn(stddev / (num_t)count); } void ThresholdTools::WinsorizedMeanAndStdDev(const Image2D* image, num_t& mean, num_t& stddev) { const size_t size = image->Width() * image->Height(); num_t* data = new num_t[size]; image->CopyData(data); std::sort(data, data + size, numLessThanOperator); const size_t lowIndex = (size_t)floor(0.1 * size); const size_t highIndex = (size_t)ceil(0.9 * size) - 1; const num_t lowValue = data[lowIndex]; const num_t highValue = data[highIndex]; delete[] data; // Calculate mean mean = 0.0; size_t count = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (std::isfinite(image->Value(x, y))) { const num_t value = image->Value(x, y); if (value < lowValue) mean += lowValue; else if (value > highValue) mean += highValue; else mean += value; count++; } } } if (count > 0) mean /= (num_t)count; // Calculate variance stddev = 0.0; count = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (std::isfinite(image->Value(x, y))) { const num_t value = image->Value(x, y); if (value < lowValue) stddev += (lowValue - mean) * (lowValue - mean); else if (value > highValue) stddev += (highValue - mean) * (highValue - mean); else stddev += (value - mean) * (value - mean); count++; } } } if (count > 0) stddev = sqrtn(1.54 * stddev / (num_t)count); else stddev = 0.0; } template void ThresholdTools::TrimmedMeanAndStdDev(const std::vector& input, T& mean, T& stddev) { if (input.size() == 1) { mean = input[0]; stddev = 0.0; return; } else if (input.size() == 0) { mean = 0; stddev = 0.0; return; } std::vector data(input); std::sort(data.begin(), data.end(), numLessThanOperator); const size_t lowIndex = (size_t)floor(0.25 * data.size()); const size_t highIndex = (size_t)ceil(0.75 * data.size()) - 1; T lowValue = data[lowIndex]; T highValue = data[highIndex]; // Calculate mean mean = 0.0; size_t count = 0; for (typename std::vector::const_iterator i = data.begin(); i != data.end(); ++i) { if (std::isfinite(*i) && *i > lowValue && *i < highValue) { mean += *i; ++count; } } if (count > 0) mean /= (T)count; // Calculate variance stddev = 0.0; count = 0; for (typename std::vector::const_iterator i = data.begin(); i != data.end(); ++i) { if (std::isfinite(*i) && *i >= lowValue && *i <= highValue) { stddev += (*i - mean) * (*i - mean); ++count; } } if (count > 0) stddev = sqrt(3.3 * stddev / (T)count); else stddev = 0.0; } template void ThresholdTools::TrimmedMeanAndStdDev( const std::vector& input, num_t& mean, num_t& stddev); template void ThresholdTools::TrimmedMeanAndStdDev( const std::vector& input, double& mean, double& stddev); template void ThresholdTools::WinsorizedMeanAndStdDev(const std::vector& input, T& mean, T& stddev) { if (input.empty()) { mean = 0.0; stddev = 0.0; } else { std::vector data(input); std::sort(data.begin(), data.end(), numLessThanOperator); const size_t lowIndex = (size_t)floor(0.1 * data.size()); const size_t highIndex = (size_t)ceil(0.9 * data.size()) - 1; T lowValue = data[lowIndex]; T highValue = data[highIndex]; // Calculate mean mean = 0.0; size_t count = 0; for (typename std::vector::const_iterator i = data.begin(); i != data.end(); ++i) { if (std::isfinite(*i)) { if (*i < lowValue) mean += lowValue; else if (*i > highValue) mean += highValue; else mean += *i; count++; } } if (count > 0) mean /= (T)count; // Calculate variance stddev = 0.0; count = 0; for (typename std::vector::const_iterator i = data.begin(); i != data.end(); ++i) { if (std::isfinite(*i)) { if (*i < lowValue) stddev += (lowValue - mean) * (lowValue - mean); else if (*i > highValue) stddev += (highValue - mean) * (highValue - mean); else stddev += (*i - mean) * (*i - mean); count++; } } if (count > 0) stddev = sqrt(1.54 * stddev / (T)count); else stddev = 0.0; } } template void ThresholdTools::WinsorizedMeanAndStdDev( const std::vector& input, num_t& mean, num_t& stddev); template void ThresholdTools::WinsorizedMeanAndStdDev( const std::vector& input, double& mean, double& stddev); void ThresholdTools::WinsorizedMeanAndStdDev(const Image2D* image, const Mask2D* mask, num_t& mean, num_t& stddev) { num_t* data = new num_t[image->Width() * image->Height()]; size_t unflaggedCount = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const num_t val = image->Value(x, y); if (!mask->Value(x, y) && std::isfinite(val)) { data[unflaggedCount] = image->Value(x, y); ++unflaggedCount; } } } const size_t lowIndex = (size_t)floor(0.1 * unflaggedCount); size_t highIndex = (size_t)ceil(0.9 * unflaggedCount); if (highIndex > 0) --highIndex; std::nth_element(data, data + lowIndex, data + unflaggedCount, numLessThanOperator); const num_t lowValue = data[lowIndex]; std::nth_element(data, data + highIndex, data + unflaggedCount, numLessThanOperator); const num_t highValue = data[highIndex]; // Calculate mean mean = 0.0; for (size_t i = 0; i < unflaggedCount; ++i) { const num_t value = data[i]; if (value < lowValue) mean += lowValue; else if (value > highValue) mean += highValue; else mean += value; } if (unflaggedCount > 0) mean /= (num_t)unflaggedCount; // Calculate variance stddev = 0.0; for (size_t i = 0; i < unflaggedCount; ++i) { const num_t value = data[i]; if (value < lowValue) stddev += (lowValue - mean) * (lowValue - mean); else if (value > highValue) stddev += (highValue - mean) * (highValue - mean); else stddev += (value - mean) * (value - mean); } delete[] data; if (unflaggedCount > 0) stddev = sqrtn(1.54 * stddev / (num_t)unflaggedCount); else stddev = 0.0; } void ThresholdTools::WinsorizedMeanAndStdDev(const Image2D* image, const Mask2D* maskA, const Mask2D* maskB, num_t& mean, num_t& stddev) { const std::unique_ptr data( new num_t[image->Width() * image->Height()]); size_t unflaggedCount = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const num_t val = image->Value(x, y); if (!maskA->Value(x, y) && !maskB->Value(x, y) && std::isfinite(val)) { data[unflaggedCount] = image->Value(x, y); ++unflaggedCount; } } } const size_t lowIndex = (size_t)floor(0.1 * unflaggedCount); size_t highIndex = (size_t)ceil(0.9 * unflaggedCount); if (highIndex > 0) --highIndex; std::nth_element(data.get(), data.get() + lowIndex, data.get() + unflaggedCount, numLessThanOperator); const num_t lowValue = data[lowIndex]; std::nth_element(data.get(), data.get() + highIndex, data.get() + unflaggedCount, numLessThanOperator); const num_t highValue = data[highIndex]; // Calculate mean mean = 0.0; for (size_t i = 0; i < unflaggedCount; ++i) { const num_t value = data[i]; if (value < lowValue) mean += lowValue; else if (value > highValue) mean += highValue; else mean += value; } if (unflaggedCount > 0) mean /= (num_t)unflaggedCount; // Calculate variance stddev = 0.0; for (size_t i = 0; i < unflaggedCount; ++i) { const num_t value = data[i]; if (value < lowValue) stddev += (lowValue - mean) * (lowValue - mean); else if (value > highValue) stddev += (highValue - mean) * (highValue - mean); else stddev += (value - mean) * (value - mean); } if (unflaggedCount > 0) stddev = sqrtn(1.54 * stddev / (num_t)unflaggedCount); else stddev = 0.0; } template double ThresholdTools::WinsorizedRMS( const std::vector>& input) { if (input.empty()) { return 0.0; } else { std::vector> data(input); std::sort(data.begin(), data.end(), complexLessThanOperator); const size_t lowIndex = (size_t)floor(0.1 * data.size()); const size_t highIndex = (size_t)ceil(0.9 * data.size()) - 1; const std::complex lowValue = data[lowIndex]; const std::complex highValue = data[highIndex]; // Calculate RMS double rms = 0.0; size_t count = 0; for (const std::complex& val : data) { if (std::isfinite(val.real()) && std::isfinite(val.imag())) { if (complexLessThanOperator(val, lowValue)) rms += (lowValue * std::conj(lowValue)).real(); else if (complexLessThanOperator(highValue, val)) rms += (highValue * std::conj(highValue)).real(); else rms += (val * std::conj(val)).real(); count++; } } if (count > 0) return sqrt(1.54 * rms / (T)count); else return 0.0; } } template double ThresholdTools::WinsorizedRMS( const std::vector>& input); template double ThresholdTools::WinsorizedRMS( const std::vector>& input); num_t ThresholdTools::MinValue(const Image2D* image, const Mask2D* mask) { num_t minValue = std::numeric_limits::max(); for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (!mask->Value(x, y) && std::isfinite(image->Value(x, y)) && image->Value(x, y) < minValue) minValue = image->Value(x, y); } } return minValue; } num_t ThresholdTools::MaxValue(const Image2D* image, const Mask2D* mask) { num_t maxValue = boost::numeric::bounds::lowest(); for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (!mask->Value(x, y) && std::isfinite(image->Value(x, y)) && image->Value(x, y) > maxValue) maxValue = image->Value(x, y); } } return maxValue; } void ThresholdTools::SetFlaggedValuesToZero(Image2D* dest, const Mask2D* mask) { for (size_t y = 0; y < dest->Height(); ++y) { for (size_t x = 0; x < dest->Width(); ++x) { if (mask->Value(x, y)) dest->SetValue(x, y, 0.0); } } } void ThresholdTools::CountMaskLengths(const Mask2D* mask, int* lengths, size_t lengthsSize) { for (size_t i = 0; i < lengthsSize; ++i) lengths[i] = 0; int *horizontal, *vertical; horizontal = new int[mask->Width() * mask->Height()]; vertical = new int[mask->Width() * mask->Height()]; size_t y = 0, index = 0; // Count horizontally lengths while (y < mask->Height()) { size_t x = 0; while (x < mask->Width()) { if (mask->Value(x, y)) { const size_t xStart = x; do { ++x; ++index; } while (x < mask->Width() && mask->Value(x, y)); for (size_t i = 0; i < x - xStart; ++i) horizontal[index - (x - xStart) + i] = x - xStart; } else { horizontal[index] = 0; ++x; ++index; } } ++y; } // Count vertically lengths size_t x = 0; while (x < mask->Width()) { size_t y = 0; while (y < mask->Height()) { if (mask->Value(x, y)) { const size_t yStart = y; while (y < mask->Height() && mask->Value(x, y)) { ++y; } for (size_t i = yStart; i < y; ++i) vertical[i * mask->Width() + x] = y - yStart; } else { vertical[y * mask->Width() + x] = 0; ++y; } } ++x; } // Count the horizontal distribution index = 0; for (size_t y = 0; y < mask->Height(); ++y) { size_t x = 0; while (x < mask->Width()) { if (horizontal[index] != 0) { const int count = horizontal[index]; bool dominant = false; for (int i = 0; i < count; ++i) { if (count >= vertical[index + i]) { dominant = true; break; } } if (dominant && (size_t)count - 1 < lengthsSize) ++lengths[count - 1]; x += count; index += count; } else { ++index; ++x; } } } // Count the vertical distribution for (size_t x = 0; x < mask->Width(); ++x) { size_t y = 0; while (y < mask->Height()) { if (vertical[y * mask->Width() + x] != 0) { const int count = vertical[y * mask->Width() + x]; bool dominant = false; for (int i = 0; i < count; ++i) { if (count >= horizontal[(y + i) * mask->Width() + x]) { dominant = true; break; } } if (dominant && (size_t)count - 1 < lengthsSize) ++lengths[count - 1]; y += count; } else { ++y; } } } delete[] vertical; delete[] horizontal; } num_t ThresholdTools::Mode(const Image2D* image, const Mask2D* mask) { num_t mode = 0.0; size_t count = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const num_t value = image->Value(x, y); if (!mask->Value(x, y) && std::isfinite(value)) { mode += value * value; count++; } } } return sqrtn(mode / (2.0 * (num_t)count)); } numl_t ThresholdTools::Sum(const Image2D* image, const Mask2D* mask) { numl_t sum = 0.0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (!mask->Value(x, y)) sum += image->Value(x, y); } } return sum; } numl_t ThresholdTools::RMS(const Image2D* image, const Mask2D* mask) { numl_t mode = 0.0; size_t count = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const num_t value = image->Value(x, y); if (!mask->Value(x, y) && std::isfinite(value)) { mode += (numl_t)value * (numl_t)value; count++; } } } return sqrtnl(mode / (numl_t)count); } num_t ThresholdTools::WinsorizedMode(const Image2D* image, const Mask2D* mask) { num_t* data = new num_t[image->Width() * image->Height()]; size_t unflaggedCount = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const num_t val = image->Value(x, y); if (!mask->Value(x, y) && std::isfinite(val)) { data[unflaggedCount] = val; ++unflaggedCount; } } } const size_t highIndex = (size_t)floor(0.9 * unflaggedCount); std::nth_element(data, data + highIndex, data + unflaggedCount); const num_t highValue = data[highIndex]; num_t mode = 0.0; for (size_t i = 0; i < unflaggedCount; ++i) { const num_t value = data[i]; if (value > highValue) mode += highValue * highValue; else mode += value * value; } delete[] data; // The correction factor 1.0541 was found by running simulations // It corresponds with the correction factor needed when winsorizing 10% of // the data, meaning that the highest 10% is set to the value exactly at the // 90%/10% limit. if (unflaggedCount > 0) return sqrtn(mode / (2.0 * (num_t)unflaggedCount)) * 1.0541; else return 0.0; } num_t ThresholdTools::WinsorizedMode(const Image2D* image, const Mask2D* maskA, const Mask2D* maskB) { const std::unique_ptr data( new num_t[image->Width() * image->Height()]); size_t unflaggedCount = 0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const num_t val = image->Value(x, y); if (!maskA->Value(x, y) && !maskB->Value(x, y) && std::isfinite(val)) { data[unflaggedCount] = val; ++unflaggedCount; } } } const size_t highIndex = (size_t)floor(0.9 * unflaggedCount); std::nth_element(data.get(), data.get() + highIndex, data.get() + unflaggedCount); const num_t highValue = data[highIndex]; num_t mode = 0.0; for (size_t i = 0; i < unflaggedCount; ++i) { const num_t value = data[i]; if (value > highValue) mode += highValue * highValue; else mode += value * value; } if (unflaggedCount > 0) return sqrtn(mode / (2.0 * (num_t)unflaggedCount)) * 1.0541; else return 0.0; } num_t ThresholdTools::WinsorizedMode(const Image2D* image) { const size_t size = image->Width() * image->Height(); num_t* data = new num_t[size]; image->CopyData(data); std::sort(data, data + size, numLessThanOperator); const size_t highIndex = (size_t)ceil(0.9 * size) - 1; const num_t highValue = data[highIndex]; delete[] data; num_t mode = 0.0; for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { const num_t value = image->Value(x, y); if (value > highValue || -value > highValue) mode += highValue * highValue; else mode += value * value; } } // The correction factor 1.0541 was found by running simulations // It corresponds with the correction factor needed when winsorizing 10% of // the data, meaning that the highest 10% is set to the value exactly at the // 90%/10% limit. if (size > 0) return sqrtn(mode / (2.0L * (num_t)size)) * 1.0541L; else return 0.0; } void ThresholdTools::FilterConnectedSamples(Mask2D* mask, size_t minConnectedSampleArea, bool eightConnected) { for (size_t y = 0; y < mask->Height(); ++y) { for (size_t x = 0; x < mask->Width(); ++x) if (mask->Value(x, y)) FilterConnectedSample(mask, x, y, minConnectedSampleArea, eightConnected); } } struct ConnectedAreaCoord { ConnectedAreaCoord(size_t _x, size_t _y) throw() { x = _x; y = _y; } size_t x, y; }; void ThresholdTools::FilterConnectedSample(Mask2D* mask, size_t x, size_t y, size_t minConnectedSampleArea, bool eightConnected) { std::deque tosearch, changed; tosearch.push_back(ConnectedAreaCoord(x, y)); size_t count = 0; do { const ConnectedAreaCoord c = tosearch.front(); tosearch.pop_front(); if (mask->Value(c.x, c.y)) { mask->SetValue(c.x, c.y, false); changed.push_back(ConnectedAreaCoord(c.x, c.y)); if (c.x > 0) tosearch.push_back(ConnectedAreaCoord(c.x - 1, c.y)); if (c.x < mask->Width() - 1) tosearch.push_back(ConnectedAreaCoord(c.x + 1, c.y)); if (c.y > 0) tosearch.push_back(ConnectedAreaCoord(c.x, c.y - 1)); if (c.y < mask->Height() - 1) tosearch.push_back(ConnectedAreaCoord(c.x, c.y + 1)); if (eightConnected) { if (c.x > 0 && c.y > 0) tosearch.push_back(ConnectedAreaCoord(c.x - 1, c.y - 1)); if (c.x < mask->Width() - 1 && c.y < mask->Height() - 1) tosearch.push_back(ConnectedAreaCoord(c.x + 1, c.y + 1)); if (c.x < mask->Width() - 1 && c.y > 0) tosearch.push_back(ConnectedAreaCoord(c.x + 1, c.y - 1)); if (c.x > 0 && c.y < mask->Height() - 1) tosearch.push_back(ConnectedAreaCoord(c.x - 1, c.y + 1)); } ++count; } } while (tosearch.size() != 0 && count < minConnectedSampleArea); if (count >= minConnectedSampleArea) { while (changed.size() != 0) { const ConnectedAreaCoord c = changed.front(); changed.pop_front(); mask->SetValue(c.x, c.y, true); } } } void ThresholdTools::UnrollPhase(Image2D* image) { for (size_t y = 0; y < image->Height(); ++y) { num_t prev = image->Value(0, y); for (size_t x = 1; x < image->Width(); ++x) { num_t val = image->Value(x, y); while (val - prev > M_PIn) val -= 2.0L * M_PIn; while (prev - val > M_PIn) val += 2.0L * M_PIn; image->SetValue(x, y, val); prev = val; } } } Image2DPtr ThresholdTools::ShrinkHorizontally(size_t factor, const Image2D* input, const Mask2D* mask) { const size_t oldWidth = input->Width(); const size_t newWidth = (oldWidth + factor - 1) / factor; Image2DPtr newImage = Image2D::CreateUnsetImagePtr(newWidth, input->Height()); for (size_t x = 0; x < newWidth; ++x) { size_t avgSize = factor; if (avgSize + x * factor > oldWidth) avgSize = oldWidth - x * factor; for (size_t y = 0; y < input->Height(); ++y) { size_t count = 0; num_t sum = 0.0; for (size_t binX = 0; binX < avgSize; ++binX) { const size_t curX = x * factor + binX; if (!mask->Value(curX, y)) { sum += input->Value(curX, y); ++count; } } if (count == 0) { sum = 0.0; for (size_t binX = 0; binX < avgSize; ++binX) { const size_t curX = x * factor + binX; sum += input->Value(curX, y); ++count; } } newImage->SetValue(x, y, sum / (num_t)count); } } return newImage; } Image2DPtr ThresholdTools::ShrinkVertically(size_t factor, const Image2D* input, const Mask2D* mask) { const size_t oldHeight = input->Height(); const size_t newHeight = (oldHeight + factor - 1) / factor; Image2DPtr newImage = Image2D::CreateUnsetImagePtr(input->Width(), newHeight); for (size_t y = 0; y != newHeight; ++y) { size_t avgSize = factor; if (avgSize + y * factor > oldHeight) avgSize = oldHeight - y * factor; for (size_t x = 0; x != input->Width(); ++x) { size_t count = 0; num_t sum = 0.0; for (size_t binY = 0; binY != avgSize; ++binY) { const size_t curY = y * factor + binY; if (!mask->Value(x, curY)) { sum += input->Value(x, curY); ++count; } } if (count == 0) { sum = 0.0; for (size_t binY = 0; binY != avgSize; ++binY) { const size_t curY = y * factor + binY; sum += input->Value(x, curY); ++count; } } newImage->SetValue(x, y, sum / (num_t)count); } } return newImage; } } // namespace algorithms aoflagger-v3.4.0/algorithms/enums.h0000644000175000017500000000251114507760372016004 0ustar olesoles#ifndef ALGORITHMS_ENUMS_H #define ALGORITHMS_ENUMS_H namespace algorithms { enum class RFITestSet { Empty, SpectralLines, GaussianSpectralLines, IntermittentSpectralLines, FullBandBursts, HalfBandBursts, VaryingBursts, GaussianBursts, SinusoidalBursts, SlewedGaussians, FluctuatingBursts, StrongPowerLaw, MediumPowerLaw, WeakPowerLaw, PolarizedSpike }; constexpr inline RFITestSet RFITestSetFirst() { return RFITestSet::Empty; } constexpr inline RFITestSet RFITestSetLast() { return RFITestSet::PolarizedSpike; } RFITestSet inline operator++(RFITestSet& x) { return x = (RFITestSet)(std::underlying_type::type(x) + 1); } enum class BackgroundTestSet { Empty, LowFrequency, HighFrequency, ThreeSources, FiveSources, FiveFilteredSources, StaticSidelobeSource, StrongVariableSidelobeSource, FaintVariableSidelobeSource, Checker }; constexpr inline BackgroundTestSet BackgroundTestSetFirst() { return BackgroundTestSet::Empty; } constexpr inline BackgroundTestSet BackgroundTestSetLast() { return BackgroundTestSet::Checker; } BackgroundTestSet inline operator++(BackgroundTestSet& x) { return x = (BackgroundTestSet)(std::underlying_type::type( x) + 1); } } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/polarizationstatistics.h0000644000175000017500000000446014507760372021510 0ustar olesoles#ifndef POLARIZATIONSTATISTICS_H #define POLARIZATIONSTATISTICS_H #include #include #include #include #include "../structures/mask2d.h" #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "../util/logger.h" namespace algorithms { class PolarizationStatistics { public: PolarizationStatistics() {} ~PolarizationStatistics() {} void Add(const class TimeFrequencyData& data) { unsigned polarizationCount = data.PolarizationCount(); if (_flaggedCounts.size() == 0) { _polarizations = data.Polarizations(); for (unsigned i = 0; i < polarizationCount; ++i) { _flaggedCounts.push_back(0); _totalCounts.push_back(0); _names.push_back( aocommon::Polarization::TypeToFullString(_polarizations[i])); } } else if (_polarizations != data.Polarizations()) { throw std::runtime_error( "Adding differently polarized data to statistics"); } for (unsigned i = 0; i < polarizationCount; ++i) { Mask2DCPtr mask = data.MakeFromPolarizationIndex(i).GetSingleMask(); _flaggedCounts[i] += mask->GetCount(); _totalCounts[i] += mask->Width() * mask->Height(); } } bool HasData() { return !_flaggedCounts.empty(); } void Report() { if (HasData()) { Logger::Info << "Polarization statistics: "; for (unsigned i = 0; i < _flaggedCounts.size(); ++i) { numl_t percentage = (numl_t)_flaggedCounts[i] * 100.0 / (numl_t)_totalCounts[i]; if (i != 0) Logger::Info << ", "; Logger::Info << _names[i] << ": " << formatPercentage(percentage) << '%'; } Logger::Info << '\n'; } else { Logger::Info << "No polarization statistics were collected.\n"; } } private: std::string formatPercentage(numl_t percentage) { std::ostringstream s; if (percentage >= 1.0) s << round(percentage * 10.0) / 10.0; else if (percentage >= 0.1) s << round(percentage * 100.0) / 100.0; else s << round(percentage * 1000.0) / 1000.0; return s.str(); } std::vector _flaggedCounts, _totalCounts; std::vector _names; std::vector _polarizations; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/baselineselector.h0000644000175000017500000000422414507760372020203 0ustar olesoles#ifndef BASELINE_SELECTOR_H #define BASELINE_SELECTOR_H #include #include #include #include #include "../structures/timefrequencymetadata.h" #include "../structures/mask2d.h" class DefaultStatistics; namespace algorithms { class BaselineSelector { public: struct SingleBaselineInfo { SingleBaselineInfo() : marked(false) {} bool operator<(const SingleBaselineInfo& rhs) const { return length < rhs.length; } int antenna1, antenna2; std::string antenna1Name, antenna2Name; int band; unsigned sequenceId; double length; unsigned long rfiCount, totalCount; bool marked; }; BaselineSelector() : _threshold(8.0), _absThreshold(0.4), _smoothingSigma(0.6), _makePlot(false), _useLog(true) {} typedef std::vector BaselineVector; void Search( std::vector& markedBaselines); void ImplyStations( const std::vector& markedBaselines, double maxRatio, std::set& badStations) const; void Add(Mask2DCPtr mask, TimeFrequencyMetaDataCPtr metaData); void Add(class DefaultStatistics& baselineStat, class AntennaInfo& antenna1, class AntennaInfo& antenna2); std::mutex& Mutex() { return _mutex; } double Threshold() const { return _threshold; } double AbsThreshold() const { return _absThreshold; } void SetThreshold(double threshold) { _threshold = threshold; } void SetAbsThreshold(double absThreshold) { _absThreshold = absThreshold; } void SetSmoothingSigma(double smoothingSigma) { _smoothingSigma = smoothingSigma; } void SetUseLog(bool useLog) { _useLog = useLog; } size_t BaselineCount() const { return _baselines.size(); } private: std::mutex _mutex; BaselineVector _baselines; double _threshold, _absThreshold; double _smoothingSigma; bool _makePlot; bool _useLog; double smoothedValue(double length) const; double smoothedValue( const BaselineSelector::SingleBaselineInfo& baseline) const { return smoothedValue(baseline.length); } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/highpassfilter.cpp0000644000175000017500000002316514507760372020234 0ustar olesoles#include "highpassfilter.h" #include "../util/rng.h" #include #include #ifdef __SSE__ #define USE_INTRINSICS #endif #ifdef USE_INTRINSICS #include #endif namespace algorithms { HighPassFilter::~HighPassFilter() { delete[] _hKernel; delete[] _vKernel; } void HighPassFilter::applyLowPassSimple(const Image2DPtr& image) { // Guassian convolution can be separated in two 1D convolution // because of properties of the 2D Gaussian function. const Image2DPtr temp = Image2D::CreateZeroImagePtr(image->Width(), image->Height()); const size_t hKernelMid = _hWindowSize / 2; for (size_t i = 0; i < _hWindowSize; ++i) { const num_t kernelValue = _hKernel[i]; const size_t xStart = (i >= hKernelMid) ? 0 : (hKernelMid - i), xEnd = (i <= hKernelMid) ? image->Width() : (image->Width() + hKernelMid > i ? (image->Width() - i + hKernelMid) : 0); for (unsigned y = 0; y < image->Height(); ++y) { for (unsigned x = xStart; x < xEnd; ++x) temp->AddValue(x, y, image->Value(x + i - hKernelMid, y) * kernelValue); } } image->SetAll(0.0); const size_t vKernelMid = _vWindowSize / 2; for (size_t i = 0; i < _vWindowSize; ++i) { const num_t kernelValue = _vKernel[i]; const size_t yStart = (i >= vKernelMid) ? 0 : (vKernelMid - i), yEnd = (i <= vKernelMid) ? image->Height() : ((image->Height() + vKernelMid > i) ? (image->Height() - i + vKernelMid) : 0); for (unsigned y = yStart; y < yEnd; ++y) { for (unsigned x = 0; x < image->Width(); ++x) image->AddValue(x, y, temp->Value(x, y + i - vKernelMid) * kernelValue); } } } void HighPassFilter::applyLowPassSSE(const Image2DPtr& image) { #ifdef USE_INTRINSICS const Image2DPtr temp = Image2D::CreateZeroImagePtr(image->Width(), image->Height()); const unsigned hKernelMid = _hWindowSize / 2; for (unsigned i = 0; i < _hWindowSize; ++i) { const num_t k = _hKernel[i]; const __m128 k4 = _mm_set_ps(k, k, k, k); unsigned /* xStart is the first column to start writing to. Note that it might be * larger than the width. */ xStart = (i >= hKernelMid) ? 0 : (hKernelMid - i), xEnd = (i <= hKernelMid) ? image->Width() : (image->Width() + hKernelMid > i ? (image->Width() - i + hKernelMid) : 0); for (unsigned y = 0; y < image->Height(); ++y) { float* tempPtr = temp->ValuePtr(xStart, y); const float* imagePtr = image->ValuePtr(xStart + i - hKernelMid, y); unsigned x = xStart; for (; x + 4 < xEnd; x += 4) { const __m128 imageVal = _mm_loadu_ps(imagePtr), tempVal = _mm_loadu_ps(tempPtr); // *tempPtr += k * (*imagePtr); _mm_storeu_ps(tempPtr, _mm_add_ps(tempVal, _mm_mul_ps(imageVal, k4))); tempPtr += 4; imagePtr += 4; } for (; x < xEnd; ++x) { *tempPtr += k * (*imagePtr); ++tempPtr; ++imagePtr; } } } image->SetAll(0.0); const unsigned vKernelMid = _vWindowSize / 2; for (unsigned i = 0; i < _vWindowSize; ++i) { const num_t k = _vKernel[i]; const __m128 k4 = _mm_set_ps(k, k, k, k); const unsigned yStart = (i >= vKernelMid) ? 0 : (vKernelMid - i), yEnd = (i <= vKernelMid) ? image->Height() : ((image->Height() + vKernelMid > i) ? (image->Height() - i + vKernelMid) : 0); for (unsigned y = yStart; y < yEnd; ++y) { const float* tempPtr = temp->ValuePtr(0, y + i - vKernelMid); float* imagePtr = image->ValuePtr(0, y); unsigned x = 0; for (; x + 4 < image->Width(); x += 4) { const __m128 imageVal = _mm_load_ps(imagePtr), tempVal = _mm_load_ps(tempPtr); // *imagePtr += k * (*tempPtr); _mm_store_ps(imagePtr, _mm_add_ps(imageVal, _mm_mul_ps(tempVal, k4))); tempPtr += 4; imagePtr += 4; } for (; x < image->Width(); ++x) { *imagePtr += k * (*tempPtr); ++tempPtr; ++imagePtr; } } } #else throw std::runtime_error("SSE function called without SSE available"); #endif } Image2DPtr HighPassFilter::ApplyHighPass(const Image2DCPtr& image, const Mask2DCPtr& mask) { Image2DPtr outputImage = ApplyLowPass(image, mask); outputImage->SubtractAsRHS(image); return outputImage; } Image2DPtr HighPassFilter::ApplyLowPass(const Image2DCPtr& image, const Mask2DCPtr& mask) { initializeKernel(); Image2DPtr outputImage = Image2D::CreateUnsetImagePtr(image->Width(), image->Height()), weights = Image2D::CreateUnsetImagePtr(image->Width(), image->Height()); setFlaggedValuesToZeroAndMakeWeights(image, outputImage, mask, weights); applyLowPass(outputImage); applyLowPass(weights); elementWiseDivide(outputImage, weights); weights.reset(); return outputImage; } void HighPassFilter::initializeKernel() { if (_hKernel == nullptr) { _hKernel = new num_t[_hWindowSize]; const int midPointX = _hWindowSize / 2; for (int x = 0; x < (int)_hWindowSize; ++x) _hKernel[x] = RNG::EvaluateUnnormalizedGaussian(x - midPointX, _hKernelSigmaSq); } if (_vKernel == nullptr) { _vKernel = new num_t[_vWindowSize]; const int midPointY = _vWindowSize / 2; for (int y = 0; y < (int)_vWindowSize; ++y) _vKernel[y] = RNG::EvaluateUnnormalizedGaussian(y - midPointY, _vKernelSigmaSq); } } void HighPassFilter::setFlaggedValuesToZeroAndMakeWeightsSimple( const Image2DCPtr& inputImage, const Image2DPtr& outputImage, const Mask2DCPtr& inputMask, const Image2DPtr& weightsOutput) { const size_t width = inputImage->Width(); for (size_t y = 0; y < inputImage->Height(); ++y) { for (size_t x = 0; x < width; ++x) { if (inputMask->Value(x, y) || !std::isfinite(inputImage->Value(x, y))) { outputImage->SetValue(x, y, 0.0); weightsOutput->SetValue(x, y, 0.0); } else { outputImage->SetValue(x, y, inputImage->Value(x, y)); weightsOutput->SetValue(x, y, 1.0); } } } } void HighPassFilter::setFlaggedValuesToZeroAndMakeWeightsSSE( const Image2DCPtr& inputImage, const Image2DPtr& outputImage, const Mask2DCPtr& inputMask, const Image2DPtr& weightsOutput) { #ifdef USE_INTRINSICS const size_t width = inputImage->Width(); const __m128i zero4i = _mm_set_epi32(0, 0, 0, 0); const __m128 zero4 = _mm_set_ps(0.0, 0.0, 0.0, 0.0); const __m128 one4 = _mm_set_ps(1.0, 1.0, 1.0, 1.0); for (size_t y = 0; y < inputImage->Height(); ++y) { const bool* rowPtr = inputMask->ValuePtr(0, y); const float* inputPtr = inputImage->ValuePtr(0, y); float* outputPtr = outputImage->ValuePtr(0, y); float* weightsPtr = weightsOutput->ValuePtr(0, y); const float* end = inputPtr + width; while (inputPtr < end) { // Assign each integer to one bool in the mask // Convert false to 0xFFFFFFFF and true to 0 const __m128 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(rowPtr[3] || !std::isfinite(inputPtr[3]), rowPtr[2] || !std::isfinite(inputPtr[2]), rowPtr[1] || !std::isfinite(inputPtr[1]), rowPtr[0] || !std::isfinite(inputPtr[0])), zero4i)); _mm_store_ps(weightsPtr, _mm_or_ps(_mm_and_ps(conditionMask, one4), _mm_andnot_ps(conditionMask, zero4))); _mm_store_ps(outputPtr, _mm_or_ps(_mm_and_ps(conditionMask, _mm_load_ps(inputPtr)), _mm_andnot_ps(conditionMask, zero4))); rowPtr += 4; outputPtr += 4; inputPtr += 4; weightsPtr += 4; } } #else throw std::runtime_error("SSE function called without SSE available"); #endif } void HighPassFilter::elementWiseDivideSimple(const Image2DPtr& leftHand, const Image2DCPtr& rightHand) { for (unsigned y = 0; y < leftHand->Height(); ++y) { for (unsigned x = 0; x < leftHand->Width(); ++x) { if (rightHand->Value(x, y) == 0.0) leftHand->SetValue(x, y, 0.0); else leftHand->SetValue(x, y, leftHand->Value(x, y) / rightHand->Value(x, y)); } } } void HighPassFilter::elementWiseDivideSSE(const Image2DPtr& leftHand, const Image2DCPtr& rightHand) { #ifdef USE_INTRINSICS const __m128 zero4 = _mm_set_ps(0.0, 0.0, 0.0, 0.0); for (unsigned y = 0; y < leftHand->Height(); ++y) { float* leftHandPtr = leftHand->ValuePtr(0, y); const float* rightHandPtr = rightHand->ValuePtr(0, y); float* end = leftHandPtr + leftHand->Width(); while (leftHandPtr < end) { __m128 l = _mm_load_ps(leftHandPtr), r = _mm_load_ps(rightHandPtr); const __m128 conditionMask = _mm_cmpeq_ps(r, zero4); _mm_store_ps(leftHandPtr, _mm_or_ps(_mm_and_ps(conditionMask, zero4), _mm_andnot_ps(conditionMask, _mm_div_ps(l, r)))); leftHandPtr += 4; rightHandPtr += 4; } } #else throw std::runtime_error("SSE function called without SSE available"); #endif } } // namespace algorithms aoflagger-v3.4.0/algorithms/combinatorialthresholder.cpp0000644000175000017500000000357314507760372022310 0ustar olesoles#include "../structures/image2d.h" #include "combinatorialthresholder.h" #include "thresholdtools.h" namespace algorithms { void CombinatorialThresholder::HorizontalVarThreshold(const Image2D* input, Mask2D* mask, size_t length, num_t threshold) { const size_t width = input->Width() - length + 1; for (size_t y = 0; y < input->Height(); ++y) { for (size_t x = 0; x < width; ++x) { bool flag = true; for (size_t i = 0; i < length; ++i) { if (input->Value(x + i, y) < threshold && input->Value(x + i, y) > -threshold) { flag = false; break; } } if (flag) { for (size_t i = 0; i < length; ++i) mask->SetValue(x + i, y, true); } } } } void CombinatorialThresholder::VerticalVarThreshold(const Image2D* input, Mask2D* mask, size_t length, num_t threshold) { const size_t height = input->Height() - length + 1; for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < input->Width(); ++x) { bool flag = true; for (size_t i = 0; i < length; ++i) { if (input->Value(x, y + i) <= threshold && input->Value(x, y + i) >= -threshold) { flag = false; break; } } if (flag) { for (size_t i = 0; i < length; ++i) mask->SetValue(x, y + i, true); } } } } void CombinatorialThresholder::VarThreshold(const Image2D* input, Mask2D* mask, size_t length, num_t threshold) { HorizontalVarThreshold(input, mask, length, threshold); VerticalVarThreshold(input, mask, length, threshold); } } // namespace algorithms aoflagger-v3.4.0/algorithms/thresholdconfig.h0000644000175000017500000000425614507760372020047 0ustar olesoles#ifndef THRESHOLDCONFIG_H #define THRESHOLDCONFIG_H #include #include "../structures/image2d.h" #include "../structures/mask2d.h" namespace algorithms { class ThresholdConfig { public: enum Distribution { Gaussian, Rayleigh }; ThresholdConfig(); void InitializeLengthsDefault(unsigned count = 0); void InitializeLengthsSingleSample(); void InitializeThresholdsFromFirstThreshold(num_t firstThreshold, Distribution noiseDistribution); void Execute(const Image2D* image, Mask2D* mask, bool additive, num_t timeSensitivity, num_t frequencySensitivity) const; void ExecuteWithMissing(const Image2D* image, Mask2D* mask, const Mask2D* missing, bool additive, num_t timeSensitivity, num_t frequencySensitivity) const; num_t GetHorizontalThreshold(unsigned index) const { return _horizontalOperations[index].threshold; } num_t GetVerticalThreshold(unsigned index) const { return _verticalOperations[index].threshold; } void SetHorizontalThreshold(unsigned index, num_t threshold) { _horizontalOperations[index].threshold = threshold; } void SetVerticalThreshold(unsigned index, num_t threshold) { _verticalOperations[index].threshold = threshold; } size_t GetHorizontalLength(unsigned index) const { return _horizontalOperations[index].length; } size_t GetVerticalLength(unsigned index) const { return _verticalOperations[index].length; } size_t GetHorizontalOperations() const { return _horizontalOperations.size(); } size_t GetVerticalOperations() const { return _horizontalOperations.size(); } void RemoveHorizontalOperations() { _horizontalOperations.clear(); } void RemoveVerticalOperations() { _verticalOperations.clear(); } private: struct ThresholdOperation { explicit ThresholdOperation(size_t length_) : length(length_), threshold(0) {} size_t length; num_t threshold; }; std::vector _horizontalOperations; std::vector _verticalOperations; Distribution _distribution; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/sumthresholdmissing.cpp0000644000175000017500000001556714507760372021342 0ustar olesoles#include "sumthresholdmissing.h" #include "../structures/xyswappedmask2d.h" #include #include #include "sumthreshold.h" namespace algorithms { template void SumThresholdMissing::horizontal(const ImageLike& input, MaskLike& mask, const CMaskLike& missing, MaskLike& scratch, size_t length, num_t threshold) { scratch = mask; const size_t width = mask.Width(), height = mask.Height(); if (length <= width) { for (size_t y = 0; y < height; ++y) { num_t sum = 0.0; // Find first non-missing value for the start of the summation interval // xLeft points to the first element of the interval, which is marked as // non-missing. size_t xLeft = 0; while (xLeft != width && missing.Value(xLeft, y)) ++xLeft; // xRight points to the last non-missing element of the interval size_t xRight = xLeft, countAdded = 0, countTotal = 0; while (countTotal + 1 < length && xRight != width) { if (!missing.Value(xRight, y)) { if (!mask.Value(xRight, y)) { sum += input.Value(xRight, y); ++countAdded; } ++countTotal; } ++xRight; } while (xRight != width) { // Add a sample at the right if (!mask.Value(xRight, y)) { sum += input.Value(xRight, y); ++countAdded; } // Threshold if (countAdded > 0 && std::fabs(sum / countAdded) > threshold) { scratch.SetHorizontalValues(xLeft, y, true, xRight - xLeft + 1); } // subtract one sample at the left if (!mask.Value(xLeft, y)) { sum -= input.Value(xLeft, y); --countAdded; } do { ++xRight; } while (xRight != width && missing.Value(xRight, y)); do { ++xLeft; // it could happen that xLeft gets to width when the length is one... // for other lengths the first test is not necessary. } while (xLeft != width && missing.Value(xLeft, y)); } } } mask = std::move(scratch); } template void SumThresholdMissing::horizontal(const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold); struct RowData { num_t sum = 0.0f; size_t yStart = 0; size_t nNotFlagged = 0; size_t nNotMissing = 0; }; void SumThresholdMissing::InitializeVertical(VerticalCache& cache, const Image2D& input, const Mask2D& missing) { cache.positions.assign(input.Width(), 0); cache.validImage = Image2D::MakeSetImage(input.Width(), input.Height(), 0.0f); cache.validMask = Mask2D::MakeSetMask(input.Width(), input.Height()); for (size_t y = 0; y != input.Height(); ++y) { for (size_t x = 0; x != input.Width(); ++x) { if (!missing.Value(x, y)) { size_t& pos = cache.positions[x]; cache.validImage.SetValue(x, pos, input.Value(x, y)); ++pos; } } } cache.scratch = SumThreshold::VerticalScratch(input.Width(), input.Height()); } void SumThresholdMissing::VerticalStacked(VerticalCache& cache, const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold) { cache.positions.assign(cache.positions.size(), 0); for (size_t y = 0; y != input.Height(); ++y) { for (size_t x = 0; x != input.Width(); ++x) { if (!missing.Value(x, y)) { size_t& pos = cache.positions[x]; cache.validMask.SetValue(x, pos, mask.Value(x, y)); ++pos; } } } SumThreshold::VerticalLarge(&cache.validImage, &cache.validMask, &scratch, &cache.scratch, length, threshold); cache.positions.assign(cache.positions.size(), 0); for (size_t y = 0; y != input.Height(); ++y) { for (size_t x = 0; x != input.Width(); ++x) { size_t& pos = cache.positions[x]; if (!missing.Value(x, y)) { if (cache.validMask.Value(x, pos)) mask.SetValue(x, y, true); ++pos; } } } } void SumThresholdMissing::VerticalConsecutive(const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold) { scratch = mask; const size_t width = mask.Width(), height = mask.Height(); std::vector rows(width); if (length <= height) { for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { RowData& row = rows[x]; // Add sample if necessary if (!missing.Value(x, y)) { if (!mask.Value(x, y)) { row.sum += input.Value(x, y); ++row.nNotFlagged; } ++row.nNotMissing; if (row.nNotMissing == length) { // There is a full sequence after having added one more sample: // perform threshold and subtract a sample that runs out // of the window // Threshold if (row.nNotFlagged != 0 && std::fabs(row.sum / row.nNotFlagged) > threshold) { scratch.SetVerticalValues(x, row.yStart, true, y - row.yStart + 1); } // Subtract the oldest sample do { if (!missing.Value(x, row.yStart)) { if (!mask.Value(x, row.yStart)) { row.sum -= input.Value(x, row.yStart); --row.nNotFlagged; } --row.nNotMissing; } ++row.yStart; } while (row.nNotMissing == length); } } } } } mask = std::move(scratch); } void SumThresholdMissing::VerticalReference(const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold) { const XYSwappedImage2D swappedInput(input); XYSwappedMask2D swappedMask(mask); const XYSwappedMask2D swappedMissing(missing); XYSwappedMask2D swappedScratch(scratch); horizontal(swappedInput, swappedMask, swappedMissing, swappedScratch, length, threshold); } } // namespace algorithms aoflagger-v3.4.0/algorithms/morphologicalflagger.h0000644000175000017500000000172114507760372021046 0ustar olesoles#ifndef MORPHOLOGICAL_FLAGGER_H #define MORPHOLOGICAL_FLAGGER_H #include #include "../structures/mask2d.h" namespace algorithms { class MorphologicalFlagger { public: static inline bool SquareContainsFlag(const Mask2D* mask, size_t xLeft, size_t yTop, size_t xRight, size_t yBottom); static void DilateFlags(Mask2D* mask, size_t timeSize, size_t frequencySize) { DilateFlagsHorizontally(mask, timeSize); DilateFlagsVertically(mask, frequencySize); } static void DilateFlagsHorizontally(Mask2D* mask, size_t timeSize); static void DilateFlagsVertically(Mask2D* mask, size_t frequencySize); static void LineRemover(Mask2D* mask, size_t maxTimeContamination, size_t maxFreqContamination); private: static void FlagTime(Mask2D* mask, size_t x); static void FlagFrequency(Mask2D* mask, size_t y); }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/testsetgenerator.h0000644000175000017500000001402314507760372020260 0ustar olesoles#ifndef MITIGATIONTESTER_H #define MITIGATIONTESTER_H #include #include #include #include #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../util/rng.h" #include "enums.h" namespace algorithms { class TestSetGenerator { public: enum NoiseType { Gaussian, GaussianProduct, GaussianPartialProduct, Rayleigh }; enum BroadbandShape { UniformShape, GaussianShape, SinusoidalShape, BurstShape }; static double shapeLevel(enum BroadbandShape shape, double x) { switch (shape) { default: case UniformShape: return 1.0; case GaussianShape: return exp(-x * x * 3.0 * 3.0); case SinusoidalShape: return (1.0 + cos(x * M_PI * 2.0 * 1.5)) * 0.5; case BurstShape: return RNG::Gaussian() * 0.6; } } static Image2D MakeRayleighData(unsigned width, unsigned height); static Image2D MakeGaussianData(unsigned width, unsigned height); static Image2D MakeNoise(unsigned width, unsigned height, int gaussian) { if (gaussian == 1) return MakeGaussianData(width, height); else if (gaussian == 0) return MakeRayleighData(width, height); else return Image2D::MakeZeroImage(width, height); } static void AddBroadbandLine(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration) { AddBroadbandLine(data, rfi, lineStrength, startTime, duration, 1.0); } static void AddBroadbandLine(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration, double frequencyRatio) { AddBroadbandLine(data, rfi, lineStrength, startTime, duration, frequencyRatio, 0.5L - frequencyRatio / 2.0L); } static void AddSpectralLine(Image2D& data, Mask2D& rfi, double lineStrength, size_t startChannel, size_t nChannels, double timeRatio, double timeOffsetRatio, enum BroadbandShape shape); static void AddIntermittentSpectralLine(Image2D& data, Mask2D& rfi, double lineStrength, size_t channel, double probability, std::mt19937& mt); static void AddBroadbandLine(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration, double frequencyRatio, double frequencyOffsetRatio); static void AddBroadbandLinePos(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration, unsigned frequencyStart, double frequencyEnd, enum BroadbandShape shape); static void AddSlewedBroadbandLinePos(Image2D& data, Mask2D& rfi, double lineStrength, double slewrate, size_t startTime, size_t duration, unsigned frequencyStart, double frequencyEnd, enum BroadbandShape shape); static void AddRfiPos(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration, unsigned frequencyPos); static std::string GetDescription(BackgroundTestSet backgroundSet); static std::string GetDescription(RFITestSet rfiSet); static TimeFrequencyData MakeTestSet(RFITestSet rfiSet, BackgroundTestSet backgroundSet, size_t width, size_t height); static void MakeBackground(BackgroundTestSet backgroundSet, TimeFrequencyData& image); static void MakeTestSet(RFITestSet testSet, TimeFrequencyData& data); private: static void AddSpectralLinesToTestSet(Image2D& image, Mask2D& rfi, double strength, enum BroadbandShape shape); static void AddIntermittentSpectralLinesToTestSet(Image2D& image, Mask2D& rfi, double strength); static void AddGaussianBroadbandToTestSet(Image2D& image, Mask2D& rfi) { AddBroadbandToTestSet(image, rfi, 1.0, 1.0, GaussianShape); } static void AddSinusoidalBroadbandToTestSet(Image2D& image, Mask2D& rfi) { AddBroadbandToTestSet(image, rfi, 1.0, 1.0, SinusoidalShape); } static void AddBurstBroadbandToTestSet(Image2D& image, Mask2D& rfi) { AddBroadbandToTestSet(image, rfi, 1.0, 1.0, BurstShape); } static void AddSlewedGaussianBroadbandToTestSet(Image2D& image, Mask2D& rfi) { AddSlewedBroadbandToTestSet(image, rfi, 1.0); } static void AddBroadbandToTestSet(Image2D& image, Mask2D& rfi, double length, double strength = 1.0, enum BroadbandShape shape = UniformShape); static void AddSlewedBroadbandToTestSet( Image2D& image, Mask2D& rfi, double length, double strength = 1.0, double slewrate = 0.02, enum BroadbandShape shape = GaussianShape); static void AddVarBroadbandToTestSet(Image2D& image, Mask2D& rfi); static void SetModelData(Image2D& image, unsigned sources, size_t width, size_t height); static void SubtractBackground(Image2D& image); static Image2D sampleRFIDistribution(unsigned width, unsigned height, double ig_over_rsq); static double Rand(enum NoiseType type) { switch (type) { case Gaussian: return RNG::Gaussian(); case GaussianProduct: return RNG::GaussianProduct(); case GaussianPartialProduct: return RNG::GaussianPartialProduct(); case Rayleigh: return RNG::Rayleigh(); } throw std::exception(); } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/siroperator.cpp0000644000175000017500000001044714507760372017570 0ustar olesoles#include "siroperator.h" namespace algorithms { template void SIROperator::operateHorizontallyMissing(MaskLikeA& mask, const MaskLikeB& missing, num_t eta) { const unsigned width = mask.Width(), maxWSize = width + 1; std::unique_ptr values(new num_t[width]), w(new num_t[maxWSize]); std::unique_ptr minIndices(new unsigned[maxWSize]), maxIndices(new unsigned[maxWSize]); for (unsigned row = 0; row < mask.Height(); ++row) { unsigned nAvailable = 0; for (unsigned i = 0; i < width; ++i) { if (!missing.Value(i, row)) { if (mask.Value(i, row)) values[nAvailable] = eta; else values[nAvailable] = eta - 1.0; ++nAvailable; } } if (nAvailable != 0) { const unsigned wSize = nAvailable + 1; w[0] = 0.0; unsigned currentMinIndex = 0; minIndices[0] = 0; for (unsigned i = 1; i != wSize; ++i) { w[i] = w[i - 1] + values[i - 1]; if (w[i] < w[currentMinIndex]) { currentMinIndex = i; } minIndices[i] = currentMinIndex; } // Calculate the maximum suffixes unsigned currentMaxIndex = wSize - 1; for (unsigned i = nAvailable - 1; i != 0; --i) { maxIndices[i] = currentMaxIndex; if (w[i] > w[currentMaxIndex]) { currentMaxIndex = i; } } maxIndices[0] = currentMaxIndex; // See if max sequence exceeds limit. nAvailable = 0; for (unsigned i = 0; i != width; ++i) { if (!missing.Value(i, row)) { const num_t maxW = w[maxIndices[nAvailable]] - w[minIndices[nAvailable]]; mask.SetValue(i, row, (maxW >= 0.0)); ++nAvailable; } } } } } template void SIROperator::operateHorizontallyMissing(Mask2D& mask, const Mask2D& missing, num_t eta); template void SIROperator::operateHorizontallyMissing( XYSwappedMask2D& mask, const XYSwappedMask2D& missing, num_t eta); template void SIROperator::operateHorizontallyMissing(MaskLikeA& mask, const MaskLikeB& missing, num_t eta, num_t penalty) { const size_t width = mask.Width(); const size_t maxWSize = width + 1; const std::unique_ptr values(new num_t[width]); const std::unique_ptr w(new num_t[maxWSize]); const std::unique_ptr minIndices(new size_t[maxWSize]); const std::unique_ptr maxIndices(new size_t[maxWSize]); const num_t penaltyValue = (eta - 1.0) * penalty; for (size_t row = 0; row < mask.Height(); ++row) { for (size_t i = 0; i != width; ++i) { if (missing.Value(i, row)) values[i] = penaltyValue; else if (mask.Value(i, row)) values[i] = eta; else values[i] = eta - 1.0; } w[0] = 0.0; size_t currentMinIndex = 0; minIndices[0] = 0; for (size_t i = 1; i != width + 1; ++i) { w[i] = w[i - 1] + values[i - 1]; if (w[i] < w[currentMinIndex]) { currentMinIndex = i; } minIndices[i] = currentMinIndex; } // Calculate the maximum suffixes size_t currentMaxIndex = width; for (size_t i = width - 1; i != 0; --i) { maxIndices[i] = currentMaxIndex; if (w[i] > w[currentMaxIndex]) { currentMaxIndex = i; } } maxIndices[0] = currentMaxIndex; // See if max sequence exceeds limit. for (size_t i = 0; i != width; ++i) { if (!missing.Value(i, row)) { const num_t maxW = w[maxIndices[i]] - w[minIndices[i]]; mask.SetValue(i, row, maxW >= 0.0); } } } } template void SIROperator::operateHorizontallyMissing(Mask2D& mask, const Mask2D& missing, num_t eta, num_t penalty); template void SIROperator::operateHorizontallyMissing( XYSwappedMask2D& mask, const XYSwappedMask2D& missing, num_t eta, num_t penalty); } // namespace algorithms aoflagger-v3.4.0/algorithms/polfitmethod.h0000644000175000017500000000430114507760372017352 0ustar olesoles#ifndef PolFitMethod_H #define PolFitMethod_H // This file is ORPHAN: it is not used or referenced, because it implements // a method which is not used, and I wanted to remove the GSL dependence. #include #include #include #include #include #include #include namespace algorithms { class PolFitMethod : public SurfaceFitMethod { public: enum Method { None, LeastSquare, LeastAbs }; PolFitMethod(); ~PolFitMethod(); virtual void Initialize(const TimeFrequencyData& input); virtual unsigned TaskCount(); virtual void PerformFit(unsigned taskNumber); virtual TimeFrequencyData Background() { return *_background; } virtual enum TimeFrequencyData::PhaseRepresentation PhaseRepresentation() const { return TimeFrequencyData::AmplitudePart; } private: long double Evaluate(unsigned x, unsigned y, long double* coefficients); static int SquareError(const gsl_vector* coefs, void* data, gsl_vector* f); static int SquareErrorDiff(const gsl_vector* x, void* data, gsl_matrix* J); static int SquareErrorComb(const gsl_vector* x, void* data, gsl_vector* f, gsl_matrix* J) { SquareError(x, data, f); SquareErrorDiff(x, data, J); return GSL_SUCCESS; } static int LinError(const gsl_vector* coefs, void* data, gsl_vector* f); static int LinErrorDiff(const gsl_vector* x, void* data, gsl_matrix* J); static int LinErrorComb(const gsl_vector* x, void* data, gsl_vector* f, gsl_matrix* J) { LinError(x, data, f); LinErrorDiff(x, data, J); return GSL_SUCCESS; } long double CalculateBackgroundValue(unsigned x, unsigned y); long double FitBackground(unsigned x, unsigned y, ThreadLocal& local); Image2DCPtr _original; class TimeFrequencyData* _background; Image2DPtr _background2D; Mask2DCPtr _mask; unsigned _hSquareSize, _vSquareSize; long double _precision; long double* _previousCoefficients; long double _hKernelSize, _vKernelSize; enum Method _method; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/polfitmethod.cpp0000644000175000017500000002430314507760372017711 0ustar olesoles#include PolFitMethod::PolFitMethod() : _background(0), _previousCoefficients(0) {} PolFitMethod::~PolFitMethod() { if (_background != 0) delete _background; } void PolFitMethod::Initialize(const TimeFrequencyData& input) { _original = input.GetSingleImage(); _background2D = Image2D::CreateEmptyImagePtr(_original->Width(), _original->Height()); if (_background != 0) delete _background; _background = new TimeFrequencyData(input.PhaseRepresentation(), input.Polarisation(), _background2D); _mask = input.GetSingleMask(); if (_hSquareSize * 2 > _original->Width()) _hSquareSize = _original->Width() / 2; if (_vSquareSize * 2 > _original->Height()) _vSquareSize = _original->Height() / 2; } unsigned PolFitMethod::TaskCount() { return _original->Height(); } void PolFitMethod::PerformFit(unsigned taskNumber) { if (_mask == 0) throw BadUsageException("Mask has not been set!"); unsigned y = taskNumber; for (unsigned x = 0; x < _original->Width(); ++x) _background2D->SetValue(x, y, CalculateBackgroundValue(x, y)); } long double PolFitMethod::CalculateBackgroundValue(unsigned x, unsigned y) { ThreadLocal local; local.image = this; local.currentX = x; local.currentY = y; if (local.currentY >= _vSquareSize) local.startY = local.currentY - _vSquareSize; else local.startY = 0; local.endY = local.currentY + _vSquareSize; if (local.endY >= _original->Height()) local.endY = _original->Height() - 1; if (local.currentX >= _hSquareSize) local.startX = local.currentX - _hSquareSize; else local.startX = 0; local.endX = local.currentX + _hSquareSize; if (local.endX >= _original->Width()) local.endX = _original->Width() - 1; local.emptyWindows = 0; switch (_method) { case None: return 0.0; case LeastSquare: case LeastAbs: case FastGaussianWeightedAverage: return FitBackground(x, y, local); default: throw ConfigurationException( "The PolFitMethod was not initialized before a fit was executed."); } } int PolFitMethod::SquareError(const gsl_vector* coefs, void* data, gsl_vector* f) { // f(x,y) = ( a * x^2 + b * xy + c * y^2 + d x + e y + l - image[x,y] )^2 ThreadLocal& local = *(ThreadLocal*)data; double a = gsl_vector_get(coefs, 0); double b = gsl_vector_get(coefs, 1); double c = gsl_vector_get(coefs, 2); double d = gsl_vector_get(coefs, 3); double e = gsl_vector_get(coefs, 4); double l = gsl_vector_get(coefs, 5); unsigned index = 0; for (unsigned y = local.startY; y <= local.endY; ++y) { double yf = y; for (unsigned x = local.startX; x <= local.endX; ++x) { if (!local.image->_mask->Value(x, y)) { double xf = x; double g_xy = a * xf * xf + b * xf * yf + c * yf * yf + d * xf + e * yf + l - local.image->_original->Value(x, y); gsl_vector_set(f, index, (g_xy * g_xy)); } else { gsl_vector_set(f, index, 0.0); } index++; } } return GSL_SUCCESS; } int PolFitMethod::SquareErrorDiff(const gsl_vector* coefs, void* data, gsl_matrix* J) { ThreadLocal& local = *(ThreadLocal*)data; double a = gsl_vector_get(coefs, 0); double b = gsl_vector_get(coefs, 1); double c = gsl_vector_get(coefs, 2); double d = gsl_vector_get(coefs, 3); double e = gsl_vector_get(coefs, 4); double f = gsl_vector_get(coefs, 5); unsigned index = 0; for (unsigned y = local.startY; y <= local.endY; ++y) { double yf = y; for (unsigned x = local.startX; x <= local.endX; ++x) { if (!local.image->_mask->Value(x, y)) { // f(x,y) = ( a * x^2 + b * xy + c * y^2 + d x + e y + f - image[x,y] // )^2 f(x,y) = g^2(x,y) df(x,y)/dz = 2 * g(x,y) * dg(x,y)/dz We now // need to calculate df(x,y)/da, df(x,y)/db, ..... for each x and y double xf = x; double g_xy = 2.0 * (a * xf * xf + b * xf * yf + c * yf * yf + d * xf + e * yf + f - local.image->_original->Value(x, y)); gsl_matrix_set(J, index, 0, g_xy * xf * xf); // df/da gsl_matrix_set(J, index, 1, g_xy * xf * yf); // df/db gsl_matrix_set(J, index, 2, g_xy * yf * yf); // df/dc gsl_matrix_set(J, index, 3, g_xy * xf); // df/dd gsl_matrix_set(J, index, 4, g_xy * yf); // df/de gsl_matrix_set(J, index, 5, g_xy); // df/df } else { for (unsigned ci = 0; ci < 6; ++ci) gsl_matrix_set(J, index, ci, 0.0); } index++; } } return GSL_SUCCESS; } int PolFitMethod::LinError(const gsl_vector* coefs, void* data, gsl_vector* f) { // f(x,y) = | a * x^2 + b * xy + c * y^2 + d x + e y + l - image[x,y] | ThreadLocal& local = *(ThreadLocal*)data; double a = gsl_vector_get(coefs, 0); double b = gsl_vector_get(coefs, 1); double c = gsl_vector_get(coefs, 2); double d = gsl_vector_get(coefs, 3); double e = gsl_vector_get(coefs, 4); double l = gsl_vector_get(coefs, 5); unsigned index = 0; for (unsigned y = local.startY; y <= local.endY; ++y) { double yf = y; for (unsigned x = local.startX; x <= local.endX; ++x) { if (!local.image->_mask->Value(x, y)) { double xf = x; double g_xy = a * xf * xf + b * xf * yf + c * yf * yf + d * xf + e * yf + l - local.image->_original->Value(x, y); gsl_vector_set(f, index, fabs(g_xy)); } else { gsl_vector_set(f, index, 0.0); } index++; } } return GSL_SUCCESS; } int PolFitMethod::LinErrorDiff(const gsl_vector* coefs, void* data, gsl_matrix* J) { ThreadLocal& local = *(ThreadLocal*)data; double a = gsl_vector_get(coefs, 0); double b = gsl_vector_get(coefs, 1); double c = gsl_vector_get(coefs, 2); double d = gsl_vector_get(coefs, 3); double e = gsl_vector_get(coefs, 4); double f = gsl_vector_get(coefs, 5); unsigned index = 0; for (unsigned y = local.startY; y <= local.endY; ++y) { double yf = y; for (unsigned x = local.startX; x <= local.endX; ++x) { if (!local.image->_mask->Value(x, y)) { // f(x,y) = | a * x^2 + b * xy + c * y^2 + d x + e y + f - image[x,y] // | f(x,y) = | g(x,y) | df(x,y)/dz = dg(x,y)/dz * g(x,y) / | g(x,y) | // We now need to calculate df(x,y)/da, df(x,y)/db, ..... for each x and // y double xf = x; double g_xy = a * xf * xf + b * xf * yf + c * yf * yf + d * xf + e * yf + f - local.image->_original->Value(x, y); double h_xy = g_xy / fabs(g_xy); gsl_matrix_set(J, index, 0, h_xy * xf * xf); // df/da gsl_matrix_set(J, index, 1, h_xy * xf * yf); // df/db gsl_matrix_set(J, index, 2, h_xy * yf * yf); // df/dc gsl_matrix_set(J, index, 3, h_xy * xf); // df/dd gsl_matrix_set(J, index, 4, h_xy * yf); // df/de gsl_matrix_set(J, index, 5, h_xy); // df/df } else { for (unsigned ci = 0; ci < 6; ++ci) gsl_matrix_set(J, index, ci, 0.0); } index++; } } return GSL_SUCCESS; } long double PolFitMethod::FitBackground(unsigned x, unsigned y, ThreadLocal& local) { std::vector coefficients(6); boost::mutex::scoped_lock lock(_mutex); if (_previousCoefficients) { for (unsigned i = 0; i < 6; ++i) coefficients[i] = _previousCoefficients[i]; } else { for (unsigned i = 0; i < 6; ++i) coefficients[i] = 1e-4 * (i * i * i); } lock.unlock(); // Chose to use the Levenberg-Marquardt solver with scaling const gsl_multifit_fdfsolver_type* T = gsl_multifit_fdfsolver_lmsder; // Construct solver unsigned functionCount = (local.endY - local.startY + 1) * (local.endX - local.startX + 1); unsigned coefficientCount = 6; gsl_multifit_fdfsolver* solver = gsl_multifit_fdfsolver_alloc(T, functionCount, coefficientCount); if (solver == 0) throw BadUsageException("No solver."); // Initialize function information structure gsl_multifit_function_fdf functionInfo; switch (_method) { case LeastSquare: default: functionInfo.f = &SquareError; functionInfo.df = &SquareErrorDiff; functionInfo.fdf = &SquareErrorComb; break; case LeastAbs: functionInfo.f = &LinError; functionInfo.df = &LinErrorDiff; functionInfo.fdf = &LinErrorComb; break; } functionInfo.n = functionCount; functionInfo.p = coefficientCount; functionInfo.params = &local; // Initialize initial value of parameters // gsl_vector vec; double vec_init[coefficientCount]; for (unsigned i = 0; i < coefficientCount; ++i) vec_init[i] = coefficients[i]; gsl_vector_view vec_view = gsl_vector_view_array(vec_init, coefficientCount); int status = gsl_multifit_fdfsolver_set(solver, &functionInfo, &vec_view.vector); if (status && status != GSL_CONTINUE) { std::cout << "Error: status = " << gsl_strerror(status) << std::endl; } // Start iterating int iter = 0; do { iter++; status = gsl_multifit_fdfsolver_iterate(solver); // PrintState(iter, solver); if (status && status != GSL_CONTINUE) { // std::cout << "Error: status = " << gsl_strerror (status) << std::endl; break; } status = gsl_multifit_test_delta(solver->dx, solver->x, _precision, _precision); } while (status == GSL_CONTINUE && iter < 250); // Save coefficients for (unsigned i = 0; i < coefficientCount; ++i) coefficients[i] = gsl_vector_get(solver->x, i); lock.lock(); if (_previousCoefficients == 0) _previousCoefficients = new long double[6]; for (unsigned i = 0; i < coefficientCount; ++i) _previousCoefficients[i] = coefficients[i]; lock.unlock(); // Clean up gsl_multifit_fdfsolver_free(solver); long double evaluation = Evaluate(x, y, coefficients); return evaluation; } long double PolFitMethod::Evaluate(unsigned x, unsigned y, long double* coefficients) { // f(x,y) = a * x^2 + b * xy + c * y^2 + d x + e y + f double xf = x, yf = y; return coefficients[0] * xf * xf + coefficients[1] * xf * yf + coefficients[2] * yf * yf + coefficients[3] * xf + coefficients[4] * yf + coefficients[5]; } aoflagger-v3.4.0/algorithms/baselineselector.cpp0000644000175000017500000002057214507760372020542 0ustar olesoles#include "baselineselector.h" #include "../util/logger.h" #include "../util/plot.h" #include "../quality/defaultstatistics.h" #include "thresholdtools.h" #include #include #include namespace algorithms { void BaselineSelector::Add(Mask2DCPtr mask, TimeFrequencyMetaDataCPtr metaData) { BaselineSelector::SingleBaselineInfo baseline; baseline.length = metaData->Baseline().Distance(); if (baseline.length > 0) { baseline.antenna1 = metaData->Antenna1().id; baseline.antenna2 = metaData->Antenna2().id; baseline.antenna1Name = metaData->Antenna1().name; baseline.antenna2Name = metaData->Antenna2().name; baseline.band = metaData->Band().windowIndex; baseline.sequenceId = metaData->SequenceId(); baseline.rfiCount = mask->GetCount(); baseline.totalCount = mask->Width() * mask->Height(); _baselines.push_back(baseline); } } void BaselineSelector::Add(DefaultStatistics& baselineStat, AntennaInfo& antenna1, AntennaInfo& antenna2) { if (antenna1.id != antenna2.id) { BaselineSelector::SingleBaselineInfo baseline; baseline.length = Baseline(antenna1, antenna2).Distance(); baseline.antenna1 = antenna1.id; baseline.antenna2 = antenna2.id; baseline.antenna1Name = antenna1.name; baseline.antenna2Name = antenna2.name; baseline.band = 0; baseline.sequenceId = 0; const DefaultStatistics singleStat = baselineStat.ToSinglePolarization(); baseline.rfiCount = singleStat.rfiCount[0]; baseline.totalCount = singleStat.count[0] + singleStat.rfiCount[0]; _baselines.push_back(baseline); } } void BaselineSelector::Search( std::vector& markedBaselines) { // Perform a first quick threshold to remove baselines which deviate a lot // (e.g. 100% flagged baselines). Sometimes, there are a lot of them, causing // instability if this would not be done. for (int i = _baselines.size() - 1; i >= 0; --i) { const double currentValue = (double)_baselines[i].rfiCount / (double)_baselines[i].totalCount; if (currentValue > _absThreshold || (_baselines[i].rfiCount == 0 && _baselines[i].totalCount >= 2500)) { if (_useLog) Logger::Info << "Baseline " << _baselines[i].antenna1Name << " x " << _baselines[i].antenna2Name << " looks bad: " << round(currentValue * 10000.0) / 100.0 << "% rfi (zero or above " << (_absThreshold * 100.0) << "% abs threshold)\n"; _baselines[i].marked = true; markedBaselines.push_back(_baselines[i]); _baselines.erase(_baselines.begin() + i); } } bool foundMoreBaselines; do { std::sort(_baselines.begin(), _baselines.end()); std::unique_ptr plot; if (_makePlot) { plot.reset(new Plot("baselineSelection.pdf")); plot->SetXAxisText("Baseline length (meters)"); plot->SetYAxisText("Percentage RFI"); } const size_t unmarkedBaselineCount = _baselines.size(); std::vector values(unmarkedBaselineCount); // Calculate the smoothed values if (_makePlot) plot->StartLine("Smoothed values"); size_t valueIndex = 0; for (BaselineVector::const_iterator i = _baselines.begin(); i != _baselines.end(); ++i) { const double smoothedVal = smoothedValue(*i); if (_makePlot) plot->PushDataPoint(i->length, 100.0 * smoothedVal); values[valueIndex] = smoothedVal - (double)i->rfiCount / (double)i->totalCount; ++valueIndex; } // Calculate the std dev double mean, stddev; std::vector valuesCopy; for (size_t i = 0; i < unmarkedBaselineCount; ++i) valuesCopy.push_back(values[i]); ThresholdTools::TrimmedMeanAndStdDev(valuesCopy, mean, stddev); if (_makePlot && _useLog) Logger::Debug << "Estimated std dev for thresholding, in percentage of RFI: " << round(10000.0 * stddev) / 100.0 << "%\n"; // unselect already marked baselines for (int i = markedBaselines.size() - 1; i >= 0; --i) { const BaselineSelector::SingleBaselineInfo baseline = markedBaselines[i]; const double currentValue = (double)baseline.rfiCount / (double)baseline.totalCount; const double baselineValue = smoothedValue(baseline.length) - currentValue; if (baselineValue >= mean - _threshold * stddev && baselineValue <= mean + _threshold * stddev && currentValue < _absThreshold && (baseline.rfiCount != 0 || baseline.totalCount < 2500)) { markedBaselines.erase(markedBaselines.begin() + i); _baselines.push_back(baseline); if (_useLog) Logger::Info << "Baseline " << baseline.antenna1Name << " x " << baseline.antenna2Name << " is now within baseline curve\n"; } } // (re)select baselines to be thrown away foundMoreBaselines = false; if (_makePlot) plot->StartScatter("Threshold"); double maxPlotY = 0.0; for (int i = unmarkedBaselineCount - 1; i >= 0; --i) { const double currentValue = (double)_baselines[i].rfiCount / (double)_baselines[i].totalCount; if (_makePlot) { const double plotY = 100.0 * (values[i] + currentValue + mean + _threshold * stddev); plot->PushDataPoint(_baselines[i].length, plotY); plot->PushDataPoint( _baselines[i].length, 100.0 * (values[i] + currentValue + mean - _threshold * stddev)); if (plotY > maxPlotY) maxPlotY = plotY; } if (values[i] < mean - _threshold * stddev || values[i] > mean + _threshold * stddev || currentValue > _absThreshold || (_baselines[i].rfiCount == 0 && _baselines[i].totalCount >= 2500)) { if (_useLog) Logger::Info << "Baseline " << _baselines[i].antenna1Name << " x " << _baselines[i].antenna2Name << " looks bad: " << round(currentValue * 10000.0) / 100.0 << "% rfi, " << round(10.0 * fabs((values[i] - mean) / stddev)) / 10.0 << "*sigma away from est baseline curve\n"; if (!_baselines[i].marked) { foundMoreBaselines = true; _baselines[i].marked = true; } markedBaselines.push_back(_baselines[i]); _baselines.erase(_baselines.begin() + i); } } if (_makePlot) { plot->SetYRange(0.0, maxPlotY * 1.5); plot->StartScatter("Accepted baselines"); for (BaselineVector::const_iterator i = _baselines.begin(); i != _baselines.end(); ++i) { plot->PushDataPoint( i->length, 100.0 * (double)i->rfiCount / (double)i->totalCount); } plot->StartScatter("Rejected baselines"); for (BaselineVector::const_iterator i = markedBaselines.begin(); i != markedBaselines.end(); ++i) { plot->PushDataPoint( i->length, 100.0 * (double)i->rfiCount / (double)i->totalCount); } plot->Close(); } } while (foundMoreBaselines); } void BaselineSelector::ImplyStations( const std::vector& markedBaselines, double maxRatio, std::set& badStations) const { std::map stations; for (std::vector::const_iterator i = markedBaselines.begin(); i != markedBaselines.end(); ++i) { stations[i->antenna1]++; stations[i->antenna2]++; } for (std::map::const_iterator i = stations.begin(); i != stations.end(); ++i) { const double ratio = (double)i->second / (double)stations.size(); if (ratio > maxRatio) { badStations.insert(i->first); } } } double BaselineSelector::smoothedValue(double length) const { const double logLength = log(length); double sum = 0.0; double weight = 0.0; for (BaselineSelector::BaselineVector::const_iterator i = _baselines.begin(); i != _baselines.end(); ++i) { const double otherLogLength = log(i->length); const double otherValue = (double)i->rfiCount / (double)i->totalCount; const double x = otherLogLength - logLength; const double curWeight = exp(-x * x / (2.0 * _smoothingSigma * _smoothingSigma)); sum += curWeight * otherValue; weight += curWeight; } return sum / weight; } } // namespace algorithms aoflagger-v3.4.0/algorithms/sumthreshold.h0000644000175000017500000001250414507760372017401 0ustar olesoles#ifndef SUMTHRESHOLD_H #define SUMTHRESHOLD_H #include #include #include #include "../structures/image2d.h" #include "../structures/mask2d.h" namespace algorithms { class SumThreshold { public: struct VerticalScratch { VerticalScratch(); VerticalScratch(size_t width, size_t height); std::unique_ptr lastFlaggedPos; std::unique_ptr sum; std::unique_ptr count; }; template static void Horizontal(const Image2D* input, Mask2D* mask, num_t threshold); template static void Vertical(const Image2D* input, Mask2D* mask, num_t threshold); template static void HorizontalLarge(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); /* We always want to compile SSE for 64-bit Intel. Note that code will only be executed if the CPU where the binary is run supports SSE. However, code can only be compiled successfully if either __SSE__ is defined or if we're on 64-bit Intel (since we're not cross-compiling) */ #if defined(__SSE__) || defined(__x86_64__) template __attribute__((target("sse"))) static void VerticalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); __attribute__((target("sse"))) static void VerticalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold); template __attribute__((target("sse"))) static void HorizontalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); __attribute__((target("sse"))) static void HorizontalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold); #endif // defined(__SSE__) || defined(__x86_64__) /* We always want to compile AVX2 for 64-bit Intel. Note that code will only be executed if the CPU where the binary is run supports AVX2. However, code can only be compiled successfully if either __AVX2__ is defined or if we're on 64-bit Intel (since we're not cross-compiling) */ #if defined(__AVX2__) || defined(__x86_64__) template __attribute__((target("avx2"))) static void VerticalLargeAVX( const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); __attribute__((target("avx2"))) static void VerticalLargeAVX( const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold); __attribute__((target("avx2"))) static void HorizontalAVXDumas( const Image2D* input, Mask2D* mask, size_t length, num_t threshold); __attribute__((target("avx2"))) static void VerticalAVXDumas( const Image2D* input, Mask2D* mask, VerticalScratch* scratch, size_t length, num_t threshold); template __attribute__((target("avx2"))) static void HorizontalAVXDumas( const Image2D* input, Mask2D* mask, num_t threshold); template __attribute__((target("avx2"))) static void VerticalAVXDumas( const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); #endif // defined(__AVX2__) || defined(__x86_64__) template static void VerticalLarge(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template static void Large(const Image2D* input, Mask2D* mask, num_t hThreshold, num_t vThreshold) { HorizontalLarge(input, mask, hThreshold); VerticalLarge(input, mask, vThreshold); } static void VerticalLarge(const Image2D* input, Mask2D* mask, Mask2D* scratch, VerticalScratch* vScratch, size_t length, num_t threshold) { #if defined(__AVX2__) || defined(__x86_64__) if (__builtin_cpu_supports("avx2")) { VerticalAVXDumas(input, mask, vScratch, length, threshold); return; } #endif #if defined(__SSE__) || defined(__x86_64__) if (__builtin_cpu_supports("sse")) { VerticalLargeSSE(input, mask, scratch, length, threshold); return; } #endif VerticalLargeReference(input, mask, scratch, length, threshold); } static void VerticalLargeReference(const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold); static void HorizontalLargeReference(const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold); static void HorizontalLarge(const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold) { #if defined(__AVX2__) || defined(__x86_64__) if (__builtin_cpu_supports("avx2")) { if (length >= 64) HorizontalAVXDumas(input, mask, length, threshold); else HorizontalLargeSSE(input, mask, scratch, length, threshold); return; } #endif #if defined(__SSE__) || defined(__x86_64__) if (__builtin_cpu_supports("sse")) { HorizontalLargeSSE(input, mask, scratch, length, threshold); return; } #endif HorizontalLargeReference(input, mask, scratch, length, threshold); } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/antennaselector.cpp0000644000175000017500000000305514507760372020401 0ustar olesoles#include "antennaselector.h" #include #include "../quality/statisticscollection.h" #include "../quality/statisticsderivator.h" using std::size_t; namespace algorithms { std::vector AntennaSelector::Run( const StatisticsCollection& statisticsCollection) { const std::map antStatistics = statisticsCollection.GetAntennaStatistics(); std::vector stddevs; std::set badAntennas; for (size_t p = 0; p != 4; ++p) { double meanStddev = 0.0; stddevs.clear(); for (const std::pair& antenna : antStatistics) { const double stddev = StatisticsDerivator::GetStatisticAmplitude( QualityTablesFormatter::StandardDeviationStatistic, antenna.second, p); stddevs.emplace_back(stddev); meanStddev += stddev; } double stddevOfStddev = 0.0; meanStddev /= stddevs.size(); for (const double& s : stddevs) { stddevOfStddev += (s - meanStddev) * (s - meanStddev); } stddevOfStddev = sqrt(stddevOfStddev / stddevs.size()); size_t index = 0; const double limit = _threshold * stddevOfStddev; for (const std::pair& antenna : antStatistics) { if (std::fabs(stddevs[index] - meanStddev) > limit || stddevs[index] == 0.0) { if (antenna.second.count[p] != 0) badAntennas.insert(antenna.first); } ++index; } } return std::vector(badAntennas.begin(), badAntennas.end()); } } // namespace algorithms aoflagger-v3.4.0/algorithms/baselinetimeplaneimager.h0000644000175000017500000000126214507760372021525 0ustar olesoles#ifndef BASELINETIMEPLANEIMAGER_H #define BASELINETIMEPLANEIMAGER_H #include #include "../structures/image2d.h" namespace algorithms { template class BaselineTimePlaneImager { public: void Image(NumType uTimesLambda, NumType vTimesLambda, NumType wTimesLambda, NumType lowestFrequency, NumType frequencyStep, size_t channelCount, const std::complex* data, Image2D& output); private: template static T frequencyToWavelength(const T frequency) { return speedOfLight() / frequency; } static long double speedOfLight() { return 299792458.0L; } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/sinusfitter.cpp0000644000175000017500000000371014507760372017571 0ustar olesoles#include "sinusfitter.h" #include namespace algorithms { SinusFitter::SinusFitter() {} SinusFitter::~SinusFitter() {} void SinusFitter::FindPhaseAndAmplitude(num_t& phase, num_t& amplitude, const num_t* dataX, const num_t* dataT, const size_t dataSize, const num_t frequency) const throw() { // calculate 1/N * \sum_t x(t) e^{-i * frequency * t} num_t sumR = 0.0L, sumI = 0.0L; for (unsigned i = 0; i < dataSize; ++i) { const num_t t = dataT[i]; const num_t x = dataX[i]; sumR += x * cosn(-t * frequency); sumI += x * sinn(-t * frequency); } sumR /= (num_t)dataSize; sumI /= (num_t)dataSize; phase = Phase(sumR, sumI); amplitude = 2.0L * sqrtn(sumR * sumR + sumI * sumI); } void SinusFitter::FindPhaseAndAmplitudeComplex( num_t& phase, num_t& amplitude, const num_t* dataR, const num_t* dataI, const num_t* dataT, const size_t dataSize, const num_t frequency) const throw() { // calculate 1/N * \sum_t x(t) e^{-i * frequency * t} num_t sumR = 0.0L, sumI = 0.0L; for (unsigned i = 0; i < dataSize; ++i) { const num_t t = dataT[i]; const num_t xR = dataR[i]; const num_t xI = dataI[i]; sumR += xR * cosn(-t * frequency); sumR += xI * sinn(-t * frequency); sumI += xR * sinn(-t * frequency); sumI -= xI * cosn(-t * frequency); } sumR /= (num_t)dataSize; sumI /= (num_t)dataSize; phase = Phase(sumR, sumI); amplitude = sqrtn(sumR * sumR + sumI * sumI); } num_t SinusFitter::FindMean(const num_t phase, const num_t amplitude, const num_t* dataX, const num_t* dataT, const size_t dataSize, const num_t frequency) { num_t sum = 0.0L; for (unsigned i = 0; i < dataSize; ++i) { sum += dataX[i] - Value(phase, amplitude, dataT[i], frequency, 0.0L); } return sum / dataSize; } } // namespace algorithms aoflagger-v3.4.0/algorithms/resampling.h0000644000175000017500000001344614507760372017027 0ustar olesoles#ifndef AOFLAGGER_ALGORITHMS_RESAMPLING_H #define AOFLAGGER_ALGORITHMS_RESAMPLING_H #include #include #include #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "thresholdtools.h" namespace algorithms { void downsample_masked(TimeFrequencyData& tfData, TimeFrequencyMetaData* metaData, size_t horizontalFactor, size_t verticalFactor) { // Decrease in horizontal direction size_t polCount = tfData.PolarizationCount(); for (size_t i = 0; i < polCount; ++i) { TimeFrequencyData polData(tfData.MakeFromPolarizationIndex(i)); const Mask2DCPtr mask = polData.GetSingleMask(); for (unsigned j = 0; j < polData.ImageCount(); ++j) { const Image2DCPtr image = polData.GetImage(j); polData.SetImage(j, ThresholdTools::ShrinkHorizontally( horizontalFactor, image.get(), mask.get())); } tfData.SetPolarizationData(i, std::move(polData)); } size_t maskCount = tfData.MaskCount(); for (size_t i = 0; i < maskCount; ++i) { Mask2DCPtr mask = tfData.GetMask(i); Mask2DPtr newMask( new Mask2D(mask->ShrinkHorizontallyForAveraging(horizontalFactor))); tfData.SetMask(i, std::move(newMask)); } // Decrease in vertical direction for (size_t i = 0; i < polCount; ++i) { TimeFrequencyData polData(tfData.MakeFromPolarizationIndex(i)); const Mask2DCPtr mask = polData.GetSingleMask(); for (unsigned j = 0; j < polData.ImageCount(); ++j) { const Image2DCPtr image = polData.GetImage(j); polData.SetImage(j, ThresholdTools::ShrinkVertically( verticalFactor, image.get(), mask.get())); } tfData.SetPolarizationData(i, std::move(polData)); } for (size_t i = 0; i < maskCount; ++i) { Mask2DCPtr mask = tfData.GetMask(i); Mask2DPtr newMask( new Mask2D(mask->ShrinkVerticallyForAveraging(verticalFactor))); tfData.SetMask(i, std::move(newMask)); } if (metaData) { if (metaData->HasBand() && verticalFactor != 1) { BandInfo newBand = metaData->Band(); size_t newNChannels = tfData.ImageHeight(); newBand.channels.resize(newNChannels); for (size_t i = 0; i != newNChannels; ++i) { const size_t startChannel = i * verticalFactor; const size_t endChannel = std::min((i + 1) * verticalFactor, metaData->Band().channels.size()); double f = 0; for (size_t j = startChannel; j != endChannel; ++j) { f += metaData->Band().channels[j].frequencyHz; } newBand.channels[i].frequencyHz = f / (endChannel - startChannel); } metaData->SetBand(newBand); } if (metaData->HasObservationTimes() && horizontalFactor != 1) { size_t newNTimes = tfData.ImageWidth(); std::vector times(newNTimes); for (size_t i = 0; i != newNTimes; ++i) { const size_t startTime = i * horizontalFactor; const size_t endTime = std::min((i + 1) * horizontalFactor, metaData->ObservationTimes().size()); double t = 0; for (size_t j = startTime; j != endTime; ++j) { t += metaData->ObservationTimes()[j]; } times[i] = t / (endTime - startTime); } metaData->SetObservationTimes(times); } } } void upsample_image(TimeFrequencyData timeFrequencyData, TimeFrequencyData& destination, size_t horizontalFactor, size_t verticalFactor) { const size_t imageCount = timeFrequencyData.ImageCount(), newWidth = destination.ImageWidth(), newHeight = destination.ImageHeight(); if (destination.ImageCount() != imageCount) throw std::runtime_error( "Error in upsample() call: source and image have different number of " "images"); if (horizontalFactor > 1) { for (size_t i = 0; i < imageCount; ++i) { Image2DPtr newImage( new Image2D(timeFrequencyData.GetImage(i)->EnlargeHorizontally( horizontalFactor, newWidth))); timeFrequencyData.SetImage(i, newImage); } } for (size_t i = 0; i < imageCount; ++i) { if (verticalFactor > 1) { Image2DPtr newImage( new Image2D(timeFrequencyData.GetImage(i)->EnlargeVertically( verticalFactor, newHeight))); destination.SetImage(i, newImage); } else { destination.SetImage(i, timeFrequencyData.GetImage(i)); } } } void upsample_mask(TimeFrequencyData timeFrequencyData, TimeFrequencyData& destination, size_t horizontalFactor, size_t verticalFactor) { const size_t maskCount = timeFrequencyData.MaskCount(), newWidth = destination.ImageWidth(), newHeight = destination.ImageHeight(), oldHeight = timeFrequencyData.ImageHeight(); if (destination.MaskCount() != maskCount) throw std::runtime_error( "Error in upsample() call: source and image have different number of " "masks"); if (horizontalFactor > 1) { for (size_t i = 0; i != maskCount; ++i) { Mask2DPtr newMask = Mask2D::CreateUnsetMaskPtr(newWidth, oldHeight); newMask->EnlargeHorizontallyAndSet(*timeFrequencyData.GetMask(i), horizontalFactor); timeFrequencyData.SetMask(i, newMask); } } for (size_t i = 0; i != maskCount; ++i) { if (verticalFactor > 1) { Mask2DPtr newMask = Mask2D::CreateUnsetMaskPtr(newWidth, newHeight); newMask->EnlargeVerticallyAndSet(*timeFrequencyData.GetMask(i), verticalFactor); destination.SetMask(i, newMask); } else { destination.SetMask(i, timeFrequencyData.GetMask(i)); } } } } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/normalizebandpass.h0000644000175000017500000001174014507760372020375 0ustar olesoles#ifndef NORMALIZE_PASSBAND_H #define NORMALIZE_PASSBAND_H #include "../algorithms/thresholdtools.h" #include #include #include #ifdef __SSE__ #define USE_INTRINSICS #endif #ifdef USE_INTRINSICS #include #endif namespace algorithms { class NormalizeBandpass { public: static void NormalizeStepwise(TimeFrequencyData& data, size_t steps) { const size_t height = data.ImageHeight(); aocommon::UVector stddev(steps); for (size_t step = 0; step != steps; ++step) { const size_t startY = step * height / steps, endY = (step + 1) * height / steps; std::vector dataVector((1 + endY - startY) * data.ImageWidth() * data.ImageCount()); std::vector::iterator vecIter = dataVector.begin(); const Mask2DCPtr mask = data.GetSingleMask(); for (size_t i = 0; i != data.ImageCount(); ++i) { const Image2D& image = *data.GetImage(i); for (size_t y = startY; y != endY; ++y) { const num_t* inputPtr = image.ValuePtr(0, y); const bool* maskPtr = mask->ValuePtr(0, y); for (size_t x = 0; x != image.Width(); ++x) { if (!*maskPtr && std::isfinite(*inputPtr)) { *vecIter = *inputPtr; ++vecIter; } ++inputPtr; ++maskPtr; } } } dataVector.resize(vecIter - dataVector.begin()); num_t mean; ThresholdTools::WinsorizedMeanAndStdDev(dataVector, mean, stddev[step]); } for (size_t i = 0; i != data.ImageCount(); ++i) { const Image2D& image = *data.GetImage(i); Image2DPtr destImage = Image2D::CreateUnsetImagePtr(image.Width(), image.Height()); for (size_t step = 0; step != steps; ++step) { const size_t startY = step * height / steps, endY = (step + 1) * height / steps; float correctionFactor; if (stddev[step] == 0.0) correctionFactor = 0.0; else correctionFactor = 1.0 / stddev[step]; #ifdef USE_INTRINSICS const __m128 corrFact4 = _mm_set_ps(correctionFactor, correctionFactor, correctionFactor, correctionFactor); #endif for (size_t y = startY; y != endY; ++y) { const float* inputPtr = image.ValuePtr(0, y); float* destPtr = destImage->ValuePtr(0, y); #ifdef USE_INTRINSICS for (size_t x = 0; x < image.Width(); x += 4) { _mm_store_ps(destPtr, _mm_mul_ps(corrFact4, _mm_load_ps(inputPtr))); inputPtr += 4; destPtr += 4; } #else for (size_t x = 0; x < image.Width(); x++) { *destPtr = correctionFactor * *inputPtr; inputPtr++; destPtr++; } #endif } } data.SetImage(i, std::move(destImage)); } } static void NormalizeSmooth(TimeFrequencyData& data) { TimeFrequencyData real = data.Make(TimeFrequencyData::RealPart), imag = data.Make(TimeFrequencyData::ImaginaryPart); const size_t height = data.ImageHeight(); aocommon::UVector rms(height); std::vector> dataVector; for (size_t y = 0; y != height; ++y) { dataVector.resize(data.ImageWidth() * data.ImageCount()); auto vecIter = dataVector.begin(); const Mask2DCPtr mask = data.GetSingleMask(); for (size_t i = 0; i != real.ImageCount(); ++i) { const Image2D& realImage = *real.GetImage(i); const Image2D& imagImage = *imag.GetImage(i); const num_t* realPtr = realImage.ValuePtr(0, y); const num_t* imagPtr = imagImage.ValuePtr(0, y); const bool* maskPtr = mask->ValuePtr(0, y); for (size_t x = 0; x != realImage.Width(); ++x) { if (!*maskPtr && std::isfinite(*realPtr) && std::isfinite(*imagPtr)) { *vecIter = std::complex(*realPtr, *imagPtr); ++vecIter; } ++realPtr; ++imagPtr; ++maskPtr; } } dataVector.resize(vecIter - dataVector.begin()); rms[y] = ThresholdTools::WinsorizedRMS(dataVector); } for (size_t i = 0; i != data.ImageCount(); ++i) { const Image2D& image = *data.GetImage(i); Image2DPtr destImage = Image2D::CreateUnsetImagePtr(image.Width(), image.Height()); for (size_t y = 0; y != height; ++y) { num_t correctionFactor; if (rms[y] == 0.0) correctionFactor = 0.0; else correctionFactor = 1.0 / rms[y]; const num_t* inputPtr = image.ValuePtr(0, y); num_t* destPtr = destImage->ValuePtr(0, y); for (size_t x = 0; x < image.Width(); x++) { *destPtr = correctionFactor * *inputPtr; ++inputPtr; ++destPtr; } } data.SetImage(i, std::move(destImage)); } } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/fringetestcreater.cpp0000644000175000017500000000247014507760372020734 0ustar olesoles#include "fringetestcreater.h" #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "../imaging/uvimager.h" namespace algorithms { void FringeTestCreater::AddStaticFringe(class TimeFrequencyData& ftData, TimeFrequencyMetaDataCPtr metaData, long double strength) { Image2DCPtr real = ftData.GetRealPart(), imaginary = ftData.GetImaginaryPart(); Image2DPtr newReal = Image2D::CreateUnsetImagePtr(real->Width(), real->Height()), newImaginary = Image2D::CreateUnsetImagePtr(real->Width(), real->Height()); for (size_t channelIndex = 0; channelIndex < ftData.ImageHeight(); ++channelIndex) { for (size_t t = 0; t < ftData.ImageWidth(); ++t) { const num_t fringeRotation = 2.0 * M_PIn * UVImager::GetFringeCount(0, t, channelIndex, metaData); newReal->SetValue( t, channelIndex, strength * cosn(fringeRotation) + real->Value(t, channelIndex)); newImaginary->SetValue( t, channelIndex, strength * sinn(fringeRotation) + imaginary->Value(t, channelIndex)); } } ftData.Set(ftData.Polarizations()[0], newReal, newImaginary); } } // namespace algorithms aoflagger-v3.4.0/algorithms/timefrequencystatistics.h0000644000175000017500000000070114507760372021647 0ustar olesoles#ifndef TIMEFREQUENCYSTATISTICS_H #define TIMEFREQUENCYSTATISTICS_H #include #include "../structures/timefrequencydata.h" namespace algorithms { class TimeFrequencyStatistics { public: explicit TimeFrequencyStatistics(const TimeFrequencyData& data); num_t GetFlaggedRatio(); static std::string FormatRatio(num_t ratio); private: TimeFrequencyData _data; }; } // namespace algorithms #endif // TIMEFREQUENCYSTATISTICS_H aoflagger-v3.4.0/algorithms/siroperator.h0000644000175000017500000002412014507760372017226 0ustar olesoles#ifndef SIROPERATOR_H #define SIROPERATOR_H #include #include "../structures/mask2d.h" #include "../structures/types.h" #include "../structures/xyswappedmask2d.h" namespace algorithms { /** * This class contains functions that implement an algorithm to dilate * a flag mask: the "scale-invariant rank (SIR) operator". * The amount of dilation is relative to the size of the flagged * areas in the input, hence it is scale invariant. This behaviour is very * effective for application after amplitude based RFI detection and is a step * in the default LOFAR flagging pipeline. * * The rule for this scale invariant dilation is as follows: * Consider the sequence w(y) of size N, where w(y) = 0 if sample y is flagged * and w(y) = 1 otherwise. If there exists a subsequence within w that includes * y and that has a flagged ratio of η or more, y will be flagged. * * Thus: * if Y1 and Y2 exists, such that \\sum_{y=Y1}^{Y2-1} w(y) < η (Y2 - Y1), flag * y. * * The algorithm will be applied both in time and in frequency direction, thus * w(y) can contain a slice through the time-frequency image in either * directions. * * The algorithm is described in Offringa, van de Gronde and Roerdink 2012 * (A&A). * * @author A.R. Offringa */ class SIROperator { public: /** * This is the proof of concept, reference version of the O(N) algorithm. It * is fast, but OperateHorizontally() and OperateVertically() have been * optimized for operating on a mask directly, which is the common mode of * operation. * * It contains extra comments to explain the algorithm within the code. * * @param [in,out] flags The input array of flags to be dilated that will be * overwritten by the dilatation of itself. * @param [in] flagsSize Size of the @c flags array. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have (see class description for the * definition). */ static void Operate(bool* flags, const unsigned flagsSize, num_t eta) { // The test for a sample to become flagged can be rewritten as // \\sum_{y=Y1}^{Y2-1} ( η - w(y) ) >= 0. // With w(y) = flags[y] : 0 // !flags[y] : 1 // Make an array in which flagged samples are η and unflagged samples are // η-1, such that we can test for \\sum_{y=Y1}^{Y2-1} values[y] >= 0 std::unique_ptr values(new num_t[flagsSize]); for (unsigned i = 0; i < flagsSize; ++i) { if (flags[i]) values[i] = eta; else values[i] = eta - 1.0; } // For each x, we will now search for the largest sum of sequantial values // that contains x. If this sum is larger then 0, this value is part of a // sequence that exceeds the test. // Define W(x) = \\sum_{y=0}^{x-1} values[y], such that the largest sequence // containing x starts at the element after W(y) is minimal in the range 0 // <= y <= x, and ends when W(y) is maximal in the range x < y < N. // Calculate these W's and minimum prefixes const unsigned wSize = flagsSize + 1; std::unique_ptr w(new num_t[wSize]); w[0] = 0.0; unsigned currentMinIndex = 0; std::unique_ptr minIndices(new unsigned[wSize]); minIndices[0] = 0; for (unsigned i = 1; i != wSize; ++i) { w[i] = w[i - 1] + values[i - 1]; if (w[i] < w[currentMinIndex]) { currentMinIndex = i; } minIndices[i] = currentMinIndex; } // Calculate the maximum suffixes unsigned currentMaxIndex = wSize - 1; std::unique_ptr maxIndices(new unsigned[wSize]); for (unsigned i = flagsSize - 1; i != 0; --i) { // We directly assign maxIndices[i] to the max index over // all indices *higher* than i, since maxIndices[i] is // not allowed to be i (maxIndices[i] = max i: x < i < N). maxIndices[i] = currentMaxIndex; if (w[i] > w[currentMaxIndex]) { currentMaxIndex = i; } } maxIndices[0] = currentMaxIndex; // See if max sequence exceeds limit. for (unsigned i = 0; i != flagsSize; ++i) { const num_t maxW = w[maxIndices[i]] - w[minIndices[i]]; flags[i] = (maxW >= 0.0); } } /** * Performs a horizontal dilation directly on a mask. Algorithm is equal to * Operate(). * * @param [in,out] mask The input flag mask to be dilated. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have. */ static void OperateHorizontally(Mask2D& mask, num_t eta) { operateHorizontally(mask, eta); } /** * Performs a horizontal dilation directly on a mask, with missing value. * Missing values are values for which it is not know they should have * been flagged. An example is when the correlator has flagged * samples: these should be excluded from RFI detection, but they might * or might not contain RFI. The way this is implemented is by concatenating * all non-missing samples in a row, and performing the algorithm on that. * * @param [in,out] mask The input flag mask to be dilated. * @param [in] missing Flag mask that identifies missing values. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have. */ static void OperateHorizontallyMissing(Mask2D& mask, const Mask2D& missing, num_t eta) { operateHorizontallyMissing(mask, missing, eta); } /** * Like @ref OperateHorizontallyMissing(), but with a penalty for missing * values. * * @param [in,out] mask The input flag mask to be dilated. * @param [in] missing Flag mask that identifies missing values. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have. * @param [in] penalty Penalty given to missing samples. */ static void OperateHorizontallyMissing(Mask2D& mask, const Mask2D& missing, num_t eta, num_t penalty) { operateHorizontallyMissing(mask, missing, eta, penalty); } /** * Performs a vertical dilation directly on a mask. Algorithm is equal to * Operate(). * * @param [in,out] mask The input flag mask to be dilated. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have. */ static void OperateVertically(Mask2D& mask, num_t eta) { XYSwappedMask2D swappedMask(mask); operateHorizontally>(swappedMask, eta); } /** * Performs a vertical dilation directly on a mask, with missing value. * Identical to @ref OperateHorizontallyMissing(), but then vertically. * * @param [in,out] mask The input flag mask to be dilated. * @param [in] missing Flag mask that identifies missing values. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have. */ static void OperateVerticallyMissing(Mask2D& mask, const Mask2D& missing, num_t eta) { XYSwappedMask2D swappedMask(mask); XYSwappedMask2D swappedMissing(missing); operateHorizontallyMissing(swappedMask, swappedMissing, eta); } static void OperateVerticallyMissing(Mask2D& mask, const Mask2D& missing, num_t eta, num_t penalty) { XYSwappedMask2D swappedMask(mask); XYSwappedMask2D swappedMissing(missing); operateHorizontallyMissing(swappedMask, swappedMissing, eta, penalty); } private: SIROperator() = delete; /** * Performs a horizontal dilation directly on a mask. Algorithm is equal to * Operate(). This is the implementation. * * @param [in,out] mask The input flag mask to be dilated. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have. */ template static void operateHorizontally(MaskLike& mask, num_t eta) { const unsigned width = mask.Width(), wSize = width + 1; std::unique_ptr values(new num_t[width]), w(new num_t[wSize]); std::unique_ptr minIndices(new unsigned[wSize]), maxIndices(new unsigned[wSize]); for (unsigned row = 0; row < mask.Height(); ++row) { for (unsigned i = 0; i < width; ++i) { if (mask.Value(i, row)) values[i] = eta; else values[i] = eta - 1.0; } w[0] = 0.0; unsigned currentMinIndex = 0; minIndices[0] = 0; for (unsigned i = 1; i != wSize; ++i) { w[i] = w[i - 1] + values[i - 1]; if (w[i] < w[currentMinIndex]) { currentMinIndex = i; } minIndices[i] = currentMinIndex; } // Calculate the maximum suffixes unsigned currentMaxIndex = wSize - 1; for (unsigned i = width - 1; i != 0; --i) { maxIndices[i] = currentMaxIndex; if (w[i] > w[currentMaxIndex]) { currentMaxIndex = i; } } maxIndices[0] = currentMaxIndex; // See if max sequence exceeds limit. for (unsigned i = 0; i != width; ++i) { const num_t maxW = w[maxIndices[i]] - w[minIndices[i]]; mask.SetValue(i, row, (maxW >= 0.0)); } } } /** * Performs a horizontal dilation directly on a mask with missing values. * This is the implementation. * * @param [in,out] mask The input flag mask to be dilated. * @param [in] missing Flag mask that identifies missing values. * @param [in] eta The η parameter that specifies the minimum number of good * data that any subsequence should have. */ template static void operateHorizontallyMissing(MaskLikeA& mask, const MaskLikeB& missing, num_t eta); template static void operateHorizontallyMissing(MaskLikeA& mask, const MaskLikeB& missing, num_t eta, num_t penalty); }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/morphology.h0000644000175000017500000000566614507760372017072 0ustar olesoles#ifndef MORPHOLOGY_H #define MORPHOLOGY_H #include #include #include "../structures/mask2d.h" #include "../structures/segmentedimage.h" namespace algorithms { class Morphology { public: Morphology() : _hLineEnlarging(1), _vLineEnlarging(1), _hDensityEnlargeRatio(0.5), _vDensityEnlargeRatio(0.5) {} ~Morphology() {} void SegmentByMaxLength(const Mask2D* mask, SegmentedImagePtr output); void SegmentByLengthRatio(const Mask2D* mask, SegmentedImagePtr output); void Cluster(SegmentedImagePtr segmentedImage); void RemoveSmallSegments(SegmentedImagePtr segmentedImage, size_t thresholdLevel); void Classify(SegmentedImagePtr segmentedImage); static size_t BROADBAND_SEGMENT, LINE_SEGMENT, BLOB_SEGMENT; private: struct SegmentInfo { SegmentInfo() : segment(0), top(0), left(0), bottom(0), right(0), count(0), width(0), height(0), xTotal(0), yTotal(0), mark(false) {} size_t segment; size_t top, left, bottom, right; size_t count; size_t width, height; size_t xTotal, yTotal; bool mark; void AddPoint(size_t x, size_t y) { if (x < left) left = x; if (x >= right) right = x + 1; if (y < top) top = y; if (y >= bottom) bottom = y + 1; xTotal += x; yTotal += y; ++count; } int HorizontalDistance(const SegmentInfo& other) const { if (other.left > right) return (int)other.left - (int)right; else if (left > other.right) return (int)left - (int)other.right; else return 0; } int VerticalDistance(const SegmentInfo& other) const { if (other.top > bottom) return (int)other.top - (int)bottom; else if (top > other.bottom) return (int)top - (int)other.bottom; else return 0; } bool Contains(size_t x, size_t y) const { return (x >= left && x < right && y >= top && y < bottom); } }; void calculateOpenings(const Mask2D* mask, int** values); void calculateOpenings(const Mask2D* mask, Mask2DPtr* values, int** hCounts, int** vCounts); void calculateVerticalCounts(const Mask2D* mask, int** values); void calculateHorizontalCounts(const Mask2D* mask, int** values); void floodFill(const Mask2D* mask, SegmentedImagePtr output, const int* const* lengthWidthValues, size_t x, size_t y, size_t value); void floodFill(const Mask2D* mask, SegmentedImagePtr output, Mask2DPtr* matrices, size_t x, size_t y, size_t z, size_t value, int** hCounts, int** vCounts); std::map createSegmentMap( SegmentedImageCPtr segmentedImage) const; size_t _hLineEnlarging; size_t _vLineEnlarging; double _hDensityEnlargeRatio, _vDensityEnlargeRatio; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/svdmitigater.h0000644000175000017500000000351014507760372017357 0ustar olesoles#ifndef SVDMITIGATER_H #define SVDMITIGATER_H #include #include "../structures/image2d.h" #include "../structures/timefrequencydata.h" // Needs to be included LAST #include "../util/f2c.h" class XYPlot; namespace algorithms { class SVDMitigater final { public: SVDMitigater(); ~SVDMitigater(); void Initialize(const TimeFrequencyData& data) { Clear(); _data = data; _iteration = 0; } void PerformFit() { _iteration++; RemoveSingularValues(_removeCount); } void PerformFit(unsigned) { PerformFit(); } void RemoveSingularValues(unsigned singularValueCount) { if (!IsDecomposed()) Decompose(); for (unsigned i = 0; i < singularValueCount; ++i) SetSingularValue(i, 0.0); Compose(); } TimeFrequencyData Background() const { return *_background; } enum TimeFrequencyData::ComplexRepresentation ComplexRepresentation() const { return TimeFrequencyData::ComplexParts; } bool IsDecomposed() const throw() { return _singularValues != nullptr; } double SingularValue(unsigned index) const throw() { return _singularValues[index]; } void SetRemoveCount(unsigned removeCount) throw() { _removeCount = removeCount; } void SetVerbose(bool verbose) throw() { _verbose = verbose; } static void CreateSingularValueGraph(const TimeFrequencyData& data, class XYPlot& plot); private: void Clear(); void Decompose(); void Compose(); void SetSingularValue(unsigned index, double newValue) throw() { _singularValues[index] = newValue; } TimeFrequencyData _data; TimeFrequencyData* _background; double* _singularValues; doublecomplex* _leftSingularVectors; doublecomplex* _rightSingularVectors; long int _m, _n; unsigned _iteration; unsigned _removeCount; bool _verbose; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/noisestatistics.h0000644000175000017500000000743614507760372020120 0ustar olesoles#ifndef NOISESTATISTICS_H #define NOISESTATISTICS_H #include #include #include #include #include "../structures/types.h" namespace algorithms { class NoiseStatistics { public: typedef numl_t stat_t; typedef std::vector Array; NoiseStatistics() : _sum(0.0), _sum2(0.0), _sum3(0.0), _sum4(0.0), _count(0) {} explicit NoiseStatistics(const Array& samples) : _sum(0.0), _sum2(0.0), _sum3(0.0), _sum4(0.0), _count(0) { Add(samples); } void Set(const Array& samples) { _sum = 0.0; _sum2 = 0.0; _sum3 = 0.0; _sum4 = 0.0; _count = 0; Add(samples); } void Add(const Array& samples) { // Calculate sum & mean for (Array::const_iterator i = samples.begin(); i != samples.end(); ++i) { const stat_t v = *i; _sum += v; _sum2 += (v * v); _sum3 += (v * v * v); _sum4 += (v * v * v * v); } _count += samples.size(); } void Add(const NoiseStatistics& statistics) { _count += statistics._count; _sum += statistics._sum; _sum2 += statistics._sum2; _sum3 += statistics._sum3; _sum4 += statistics._sum4; } unsigned long Count() const { return _count; } void SetCount(unsigned long count) { _count = count; } stat_t Sum() const { return _sum; } void SetSum(stat_t sum) { _sum = sum; } stat_t Sum2() const { return _sum2; } void SetSum2(stat_t sum2) { _sum2 = sum2; } stat_t Sum3() const { return _sum3; } stat_t Sum4() const { return _sum4; } stat_t Mean() const { if (_count == 0) return 0.0; else return _sum / (numl_t)_count; } stat_t StdDevEstimator() const { return std::sqrt(VarianceEstimator()); } stat_t VarianceEstimator() const { if (_count <= 1) { return 0.0; } else { const stat_t n = _count; const stat_t sumMeanSquared = (_sum * _sum) / n; return (_sum2 + sumMeanSquared - (_sum * 2.0 * _sum / n)) / (n - 1.0); } } stat_t SecondMoment() const { if (_count == 0) { return 0.0; } else { const stat_t n = _count; const stat_t sumMeanSquared = (_sum * _sum) / n; return (_sum2 + sumMeanSquared - (_sum * 2.0 * _sum / n)) / n; } } stat_t FourthMoment() const { if (_count == 0) { return 0.0; } else { const stat_t n = _count, mean = _sum / n, mean2 = mean * mean; return (_sum4 - 4.0 * (_sum3 * mean + _sum * mean2 * mean) + 6.0 * _sum2 * mean2) / n + mean2 * mean2; } } stat_t VarianceOfVarianceEstimator() const { const long double n = _count; if (n <= 1) { return 0.0; } else { const long double moment2 = SecondMoment(); return (FourthMoment() - moment2 * moment2 * (n - 3.0) / (n - 1.0)) / n; } } static unsigned WriteColumnCount() { return 8; } static unsigned VarianceColumn() { return 6; } static void WriteHeaders(const std::string& headerPrefix, std::ostream& stream) { stream << headerPrefix << "Count\t" << headerPrefix << "Sum\t" << headerPrefix << "Sum2\t" << headerPrefix << "Sum3\t" << headerPrefix << "Sum4\t" << headerPrefix << "Mean\t" << headerPrefix << "Variance\t" << headerPrefix << "VarianceOfVariance"; } void WriteValues(std::ostream& stream) const { stream << _count << '\t' << _sum << '\t' << _sum2 << '\t' << _sum3 << '\t' << _sum4 << '\t' << Mean() << '\t' << VarianceEstimator() << '\t' << VarianceOfVarianceEstimator(); } void ReadValues(std::istream& stream) { stat_t tmp; stream >> _count >> _sum >> _sum2 >> _sum3 >> _sum4 >> tmp >> tmp >> tmp; } private: stat_t _sum; stat_t _sum2; stat_t _sum3; stat_t _sum4; unsigned long _count; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/applybandpass.h0000644000175000017500000000536614507760372017531 0ustar olesoles#ifndef APPLY_BANDPASS_H #define APPLY_BANDPASS_H #include "../structures/timefrequencydata.h" #include "bandpassfile.h" #include #include namespace algorithms { class ApplyBandpass { public: static void Apply(TimeFrequencyData& data, BandpassFile& file, const std::string& antenna1, const std::string& antenna2) { for (size_t i = 0; i != data.PolarizationCount(); ++i) { TimeFrequencyData polData = data.MakeFromPolarizationIndex(i); char pol1, pol2; switch (polData.GetPolarization(0)) { case aocommon::Polarization::XX: pol1 = 'X'; pol2 = 'X'; break; case aocommon::Polarization::XY: pol1 = 'X'; pol2 = 'Y'; break; case aocommon::Polarization::YX: pol1 = 'Y'; pol2 = 'X'; break; case aocommon::Polarization::YY: pol1 = 'Y'; pol2 = 'Y'; break; case aocommon::Polarization::LL: pol1 = 'L'; pol2 = 'L'; break; case aocommon::Polarization::LR: pol1 = 'L'; pol2 = 'R'; break; case aocommon::Polarization::RL: pol1 = 'R'; pol2 = 'L'; break; case aocommon::Polarization::RR: pol1 = 'R'; pol2 = 'R'; break; default: throw std::runtime_error("Can't apply a bandpass for polarization " + aocommon::Polarization::TypeToShortString( polData.GetPolarization(0))); } for (size_t imageIndex = 0; imageIndex != polData.ImageCount(); ++imageIndex) { Image2DCPtr uncorrected = polData.GetImage(imageIndex); Image2DPtr newImage = apply(uncorrected, file, antenna1, antenna2, pol1, pol2); polData.SetImage(imageIndex, std::move(newImage)); } data.SetPolarizationData(i, std::move(polData)); } } private: static Image2DPtr apply(Image2DCPtr& uncorrected, BandpassFile& file, const std::string& antenna1, const std::string& antenna2, char pol1, char pol2) { Image2DPtr corrected = Image2D::MakePtr(uncorrected->Width(), uncorrected->Height()); for (size_t ch = 0; ch != uncorrected->Height(); ++ch) { float val = 1.0 / (file.GetValue(antenna1, pol1, ch) * file.GetValue(antenna2, pol2, ch)); const num_t* ptrUncor = uncorrected->ValuePtr(0, ch); num_t* ptrCor = corrected->ValuePtr(0, ch); for (size_t x = 0; x != uncorrected->Width(); ++x) { ptrCor[x] = ptrUncor[x] * val; } } return corrected; } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/thresholdtools.h0000644000175000017500000001164314507760372017740 0ustar olesoles#ifndef THRESHOLDTOOLS_H #define THRESHOLDTOOLS_H #include #include #include #include "../structures/image2d.h" #include "../structures/mask2d.h" namespace algorithms { class ThresholdTools { public: static void MeanAndStdDev(const Image2D* image, const Mask2D* mask, num_t& mean, num_t& stddev); static numl_t Sum(const Image2D* image, const Mask2D* mask); static numl_t RMS(const Image2D* image, const Mask2D* mask); static num_t Mode(const Image2D* input, const Mask2D* mask); static num_t WinsorizedMode(const Image2D* image, const Mask2D* mask); static num_t WinsorizedMode(const Image2D* image, const Mask2D* maskA, const Mask2D* maskB); static num_t WinsorizedMode(const Image2D* image); template static void TrimmedMeanAndStdDev(const std::vector& input, T& mean, T& stddev); template static void WinsorizedMeanAndStdDev(const std::vector& input, T& mean, T& stddev); static void WinsorizedMeanAndStdDev(const Image2D* image, const Mask2D* mask, num_t& mean, num_t& stddev); static void WinsorizedMeanAndStdDev(const Image2D* image, const Mask2D* maskA, const Mask2D* maskB, num_t& mean, num_t& stddev); static void WinsorizedMeanAndStdDev(const Image2D* image, num_t& mean, num_t& stddev); template static double WinsorizedRMS(const std::vector>& input); static num_t MinValue(const Image2D* image, const Mask2D* mask); static num_t MaxValue(const Image2D* image, const Mask2D* mask); static void SetFlaggedValuesToZero(Image2D* dest, const Mask2D* mask); static void CountMaskLengths(const Mask2D* mask, int* lengths, size_t lengthsSize); static void FilterConnectedSamples(Mask2D* mask, size_t minConnectedSampleArea, bool eightConnected = true); static void FilterConnectedSample(Mask2D* mask, size_t x, size_t y, size_t minConnectedSampleArea, bool eightConnected = true); static void UnrollPhase(Image2D* image); static Image2DPtr ShrinkHorizontally(size_t factor, const Image2D* input, const Mask2D* mask); static Image2DPtr ShrinkVertically(size_t factor, const Image2D* input, const Mask2D* mask); static Image2DPtr FrequencyRectangularConvolution(const Image2D* source, size_t convolutionSize) { Image2DPtr image(new Image2D(*source)); const size_t upperWindowHalf = (convolutionSize + 1) / 2; for (size_t x = 0; x < image->Width(); ++x) { num_t sum = 0.0; for (size_t y = 0; y < upperWindowHalf; ++y) sum += image->Value(x, y); for (size_t y = upperWindowHalf; y < convolutionSize; ++y) { image->SetValue(x, y - upperWindowHalf, sum / (num_t)y); sum += image->Value(x, y); } size_t count = convolutionSize; for (size_t y = convolutionSize; y != image->Height(); ++y) { image->SetValue(x, y - upperWindowHalf, sum / (num_t)count); sum += image->Value(x, y) - image->Value(x, y - convolutionSize); } for (size_t y = image->Height(); y != image->Height() + upperWindowHalf; ++y) { image->SetValue(x, y - upperWindowHalf, sum / (num_t)count); sum -= image->Value(x, y - convolutionSize); --count; } } return image; } static Mask2DPtr Threshold(const Image2D* image, num_t threshold) { Mask2DPtr mask = Mask2D::CreateUnsetMaskPtr(image->Width(), image->Height()); for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { mask->SetValue(x, y, image->Value(x, y) >= threshold); } } return mask; } private: ThresholdTools() {} // We need this less than operator, because the normal operator // does not enforce a strictly ordered set, because a static bool complexLessThanOperator(const std::complex& a, const std::complex& b) { if (std::isfinite(a.real()) && std::isfinite(a.imag())) { if (std::isfinite(b.real()) && std::isfinite(b.imag())) return (a * std::conj(a)).real() < (b * std::conj(b)).real(); else return true; } return false; } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/morphologicalflagger.cpp0000644000175000017500000000722214507760372021403 0ustar olesoles#include "morphologicalflagger.h" #include namespace algorithms { bool MorphologicalFlagger::SquareContainsFlag(const Mask2D* mask, size_t xLeft, size_t yTop, size_t xRight, size_t yBottom) { for (size_t y = yTop; y <= yBottom; ++y) { for (size_t x = xLeft; x <= xRight; ++x) { if (mask->Value(x, y)) return true; } } return false; } void MorphologicalFlagger::DilateFlagsHorizontally(Mask2D* mask, size_t timeSize) { if (timeSize != 0) { Mask2D destination(Mask2D::MakeUnsetMask(mask->Width(), mask->Height())); if (timeSize > mask->Width()) timeSize = mask->Width(); const int intSize = (int)timeSize; for (size_t y = 0; y < mask->Height(); ++y) { int dist = intSize + 1; for (size_t x = 0; x < timeSize; ++x) { if (mask->Value(x, y)) dist = -intSize; dist++; } for (size_t x = 0; x < mask->Width() - timeSize; ++x) { if (mask->Value(x + timeSize, y)) dist = -intSize; if (dist <= intSize) { destination.SetValue(x, y, true); dist++; } else { destination.SetValue(x, y, false); } } for (size_t x = mask->Width() - timeSize; x < mask->Width(); ++x) { if (dist <= intSize) { destination.SetValue(x, y, true); dist++; } else { destination.SetValue(x, y, false); } } } *mask = std::move(destination); } } void MorphologicalFlagger::DilateFlagsVertically(Mask2D* mask, size_t frequencySize) { if (frequencySize != 0) { Mask2D destination(Mask2D::MakeUnsetMask(mask->Width(), mask->Height())); if (frequencySize > mask->Height()) frequencySize = mask->Height(); const int intSize = (int)frequencySize; for (size_t x = 0; x < mask->Width(); ++x) { int dist = intSize + 1; for (size_t y = 0; y < frequencySize; ++y) { if (mask->Value(x, y)) dist = -intSize; dist++; } for (size_t y = 0; y < mask->Height() - frequencySize; ++y) { if (mask->Value(x, y + frequencySize)) dist = -intSize; if (dist <= intSize) { destination.SetValue(x, y, true); dist++; } else { destination.SetValue(x, y, false); } } for (size_t y = mask->Height() - frequencySize; y < mask->Height(); ++y) { if (dist <= intSize) { destination.SetValue(x, y, true); dist++; } else { destination.SetValue(x, y, false); } } } *mask = std::move(destination); } } void MorphologicalFlagger::LineRemover(Mask2D* mask, size_t maxTimeContamination, size_t maxFreqContamination) { for (size_t x = 0; x < mask->Width(); ++x) { size_t count = 0; for (size_t y = 0; y < mask->Height(); ++y) { if (mask->Value(x, y)) ++count; } if (count > maxFreqContamination) FlagTime(mask, x); } for (size_t y = 0; y < mask->Height(); ++y) { size_t count = 0; for (size_t x = 0; x < mask->Width(); ++x) { if (mask->Value(x, y)) ++count; } if (count > maxTimeContamination) FlagFrequency(mask, y); } } void MorphologicalFlagger::FlagTime(Mask2D* mask, size_t x) { for (size_t y = 0; y < mask->Height(); ++y) { mask->SetValue(x, y, true); } } void MorphologicalFlagger::FlagFrequency(Mask2D* mask, size_t y) { for (size_t x = 0; x < mask->Width(); ++x) { mask->SetValue(x, y, true); } } } // namespace algorithms aoflagger-v3.4.0/algorithms/bandpassfile.h0000644000175000017500000000356114507760372017316 0ustar olesoles#ifndef BANDPASS_FILE_H #define BANDPASS_FILE_H #include #include #include #include #include "../util/logger.h" class BandpassFile { public: explicit BandpassFile(const std::string& filename) { std::ifstream file(filename); if (!file) throw std::runtime_error("Can not find bandpass file: '" + filename + '\''); std::string antenna, pol; size_t channel; double value; while (file) { file >> antenna >> pol >> channel >> value; if (file.good()) { char polChar = pol[0]; _values.emplace(BandpassIndex{antenna, polChar, channel}, value); // Logger::Info << antenna << " , " << polChar << " , " << channel << // '\n'; } } Logger::Info << "Read " << _values.size() << " passband values from file " << filename << ".\n"; } double GetValue(const std::string& antenna, char polarization, size_t channel) const { auto iter = _values.find(BandpassIndex{antenna, polarization, channel}); if (iter == _values.end()) { throw std::runtime_error("Passband file is missing values for " + antenna + " pol " + polarization + " ch " + std::to_string(channel)); } return iter->second; } private: struct BandpassIndex { std::string antenna; char polarization; size_t channel; bool operator<(const BandpassIndex& rhs) const { if (channel < rhs.channel) { return true; } else if (channel == rhs.channel) { if (polarization < rhs.polarization) return true; else if (polarization == rhs.polarization && antenna < rhs.antenna) return true; } return false; } }; /** antenna, polarization, */ std::map _values; }; #endif aoflagger-v3.4.0/algorithms/fringetestcreater.h0000644000175000017500000000070114507760372020374 0ustar olesoles#ifndef FRINGETESTCREATER_H #define FRINGETESTCREATER_H #include "../structures/timefrequencymetadata.h" namespace algorithms { class FringeTestCreater { public: static void AddStaticFringe(class TimeFrequencyData& ftData, TimeFrequencyMetaDataCPtr metaData, long double strength); private: FringeTestCreater() {} ~FringeTestCreater() {} }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/medianwindow.h0000644000175000017500000000374714507760372017356 0ustar olesoles#ifndef MEDIANWINDOW_H #define MEDIANWINDOW_H #include #include #include #include "../structures/samplerow.h" namespace algorithms { template class MedianWindow { public: static void SubtractMedian(SampleRow& sampleRow, unsigned windowSize) { if (windowSize > sampleRow.Size() * 2) windowSize = sampleRow.Size() * 2; SampleRow copy(sampleRow); MedianWindow window; unsigned rightPtr, leftPtr = 0; for (rightPtr = 0; rightPtr < ((windowSize - 1) / 2); ++rightPtr) { if (!copy.ValueIsMissing(rightPtr)) window.Add(copy.Value(rightPtr)); } for (unsigned i = 0; i < sampleRow.Size(); ++i) { if (rightPtr < sampleRow.Size()) { if (!copy.ValueIsMissing(rightPtr)) window.Add(copy.Value(rightPtr)); ++rightPtr; } if (rightPtr > windowSize) { if (!copy.ValueIsMissing(leftPtr)) window.Remove(copy.Value(leftPtr)); ++leftPtr; } sampleRow.SetValue(i, copy.Value(i) - window.Median()); } } private: std::vector data_; void Add(NumType sample) { // Add after the last value, to reduce the number of elements to shift. data_.insert(std::upper_bound(data_.begin(), data_.end(), sample), sample); } void Remove(NumType sample) { // Remove the last occurance, to reduce the number of elements to shift. data_.erase(std::upper_bound(data_.begin(), data_.end(), sample) - 1); } NumType Median() const { if (data_.size() == 0) return std::numeric_limits::quiet_NaN(); if (data_.size() % 2 == 0) { unsigned m = data_.size() / 2 - 1; typename std::vector::const_iterator i = data_.begin(); i += m; NumType lMid = *i; ++i; NumType rMid = *i; return (lMid + rMid) / 2.0; } else { unsigned m = data_.size() / 2; typename std::vector::const_iterator i = data_.begin(); i += m; return *i; } } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/convolutions.h0000644000175000017500000001762414507760372017432 0ustar olesoles#ifndef CONVOLUTIONS_H #define CONVOLUTIONS_H #include "../structures/types.h" #include "../util/rng.h" #include namespace algorithms { class Convolutions { public: /** * This function will convolve data with the specified kernel. It will * place the element at position (kernelSize/2) of the kernel in the * centre, i.e. data[0] := sum over i in kS : data[i - kS + _kS/2_] * * kernel[i]. Therefore, it makes most sense to specify an odd kernelSize if * the kernel consists of a peak / symmetric function. * * This function assumes the function represented by @c data is zero outside * its domain [0..dataSize}. * * This function does not reverse one of the input functions, therefore this * function is not adhering to the strict definition of a convolution. * * This function does not use an FFT to calculate the convolution, and is * therefore O(dataSize x kernelSize). * * @param data The data to be convolved (will also be the output) * @param dataSize Number of samples in data * @param kernel The kernel to be convolved, central sample = kernelSize/2 * @param kernelSize Number of samples in the kernel, probably desired to be * odd if the kernel is symmetric. */ static void OneDimensionalConvolutionBorderZero(num_t* data, unsigned dataSize, const num_t* kernel, unsigned kernelSize) { num_t* tmp = new num_t[dataSize]; for (unsigned i = 0; i < dataSize; ++i) { unsigned kStart, kEnd; const int offset = i - kernelSize / 2; // Make sure that kStart >= 0 if (offset < 0) kStart = -offset; else kStart = 0; // Make sure that kEnd + offset <= dataSize if (offset + kernelSize > dataSize) kEnd = dataSize - offset; else kEnd = kernelSize; num_t sum = 0.0; for (unsigned k = kStart; k < kEnd; ++k) sum += data[k + offset] * kernel[k]; tmp[i] = sum; } for (unsigned i = 0; i < dataSize; ++i) data[i] = tmp[i]; delete[] tmp; } /** * This function will convolve data with the specified kernel. It will * place the element at position (kernelSize/2) of the kernel in the * centre, i.e. data[0] := sum over i in kS : data[i - kS + _kS/2_] * * kernel[i]. Therefore, it makes most sense to specify an odd kernelSize if * the kernel consists of a peak / symmetric function. * * This function assumes the function represented by @c data is not zero * outside its domain [0..dataSize}, but is "unknown". It assumes that the * integral over @c kernel is one. If this is not the case, you have to * multiply all output values with the kernels integral after convolution. * * This function does not reverse one of the input functions, therefore this * function is not adhering to the strict definition of a convolution. * * This function does not use an FFT to calculate the convolution, and is * therefore O(dataSize x kernelSize). * * @param data The data to be convolved (will also be the output) * @param dataSize Number of samples in data * @param kernel The kernel to be convolved, central sample = kernelSize/2 * @param kernelSize Number of samples in the kernel, probably desired to be * odd if the kernel is symmetric. */ static void OneDimensionalConvolutionBorderInterp(num_t* data, unsigned dataSize, const num_t* kernel, unsigned kernelSize) { num_t* tmp = new num_t[dataSize]; for (unsigned i = 0; i < dataSize; ++i) { unsigned kStart, kEnd; const int offset = i - kernelSize / 2; // Make sure that kStart >= 0 if (offset < 0) kStart = -offset; else kStart = 0; // Make sure that kEnd + offset <= dataSize if (offset + kernelSize > dataSize) kEnd = dataSize - offset; else kEnd = kernelSize; num_t sum = 0.0; num_t weight = 0.0; for (unsigned k = kStart; k < kEnd; ++k) { sum += data[k + offset] * kernel[k]; weight += kernel[k]; } // Weighting is performed to correct for the "missing data" outside the // domain of data. The actual correct value should be sum * (sumover // kernel / sumover kernel-used ). We however assume "sumover kernel" to // be 1. sumover kernel-used is the weight. tmp[i] = sum / weight; } for (unsigned i = 0; i < dataSize; ++i) data[i] = tmp[i]; delete[] tmp; } static void OneDimensionalGausConvolution(num_t* data, unsigned dataSize, num_t sigma) { unsigned kernelSize = (unsigned)roundn(sigma * 3.0L); if (kernelSize % 2 == 0) ++kernelSize; if (kernelSize > dataSize * 2) { if (dataSize == 0) return; kernelSize = dataSize * 2 - 1; } unsigned centreElement = kernelSize / 2; num_t* kernel = new num_t[kernelSize]; for (unsigned i = 0; i < kernelSize; ++i) { num_t x = ((num_t)i - (num_t)centreElement); kernel[i] = RNG::EvaluateGaussian(x, sigma); } OneDimensionalConvolutionBorderInterp(data, dataSize, kernel, kernelSize); delete[] kernel; } /** * Perform a sinc convolution. This is equivalent with a low-pass filter, * where @c frequency specifies the frequency in index units. * * With frequency=1, the data will be convolved with the * delta function and have no effect. With frequency = 0.25, * all fringes faster than 0.25 fringes/index units will be * filtered. * * The function is O(dataSize^2). */ static void OneDimensionalSincConvolution(num_t* data, unsigned dataSize, num_t frequency) { if (dataSize == 0) return; const unsigned kernelSize = dataSize * 2 - 1; const unsigned centreElement = kernelSize / 2; num_t* kernel = new num_t[kernelSize]; const numl_t factor = 2.0 * frequency * M_PInl; numl_t sum = 0.0; for (unsigned i = 0; i < kernelSize; ++i) { const numl_t x = (((numl_t)i - (numl_t)centreElement) * factor); if (x != 0.0) kernel[i] = (num_t)(sinnl(x) / x); else kernel[i] = 1.0; sum += kernel[i]; } for (unsigned i = 0; i < kernelSize; ++i) { kernel[i] /= sum; } OneDimensionalConvolutionBorderZero(data, dataSize, kernel, kernelSize); delete[] kernel; } /** * Perform a sinc convolution, with a convolution kernel that has been Hamming * windowed. Because of the hamming window, the filter has less of a steep * cutting edge, but less ripples. * * See OneDimensionalSincConvolution() for more info. * * The function is O(dataSize^2). */ static void OneDimensionalSincConvolutionHammingWindow(num_t* data, unsigned dataSize, num_t frequency) { if (dataSize == 0) return; const unsigned kernelSize = dataSize * 2 - 1; const unsigned centreElement = kernelSize / 2; num_t* kernel = new num_t[kernelSize]; const numl_t sincFactor = 2.0 * frequency * M_PInl; const numl_t hammingFactor = 2.0 * M_PInl * (numl_t)(kernelSize - 1); numl_t sum = 0.0; for (unsigned i = 0; i < kernelSize; ++i) { const numl_t hamming = 0.54 - 0.46 * cosnl(hammingFactor * (numl_t)i); const numl_t x = (((numl_t)i - (numl_t)centreElement) * sincFactor); if (x != 0.0) kernel[i] = (num_t)(sinnl(x) / x) * hamming; else kernel[i] = 1.0; sum += kernel[i]; } for (unsigned i = 0; i < kernelSize; ++i) { kernel[i] /= sum; } OneDimensionalConvolutionBorderZero(data, dataSize, kernel, kernelSize); delete[] kernel; } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/baselinetimeplaneimager.cpp0000644000175000017500000001054414507760372022063 0ustar olesoles#include "baselinetimeplaneimager.h" #include "../util/logger.h" #include #include #include #include namespace algorithms { template void BaselineTimePlaneImager::Image( NumType uTimesLambda, NumType vTimesLambda, NumType wTimesLambda, NumType lowestFrequency, NumType frequencyStep, size_t channelCount, const std::complex* data, Image2D& output) { NumType phi = atan2(vTimesLambda, uTimesLambda); const size_t imgSize = output.Width(); NumType minLambda = frequencyToWavelength( lowestFrequency + frequencyStep * (NumType)channelCount); NumType uvDist = sqrt(uTimesLambda * uTimesLambda + vTimesLambda * vTimesLambda) / minLambda; NumType scale = 1.0; // scale down from all sky to ... // Steps to be taken: // 1. Create a 1D array with the data in it (in 'u' dir) and otherwise zerod. // This represents a cut through the uvw plane. The highest non-zero // samples have uv-distance 2*|uvw|. Channels are not regridded. Therefore, // the distance in samples is 2 * (lowestFrequency / frequencyStep + // channelCount) (Two times larger than necessary to prevent border // issues). // // 2. Fourier transform this (FFT 1D) // The 1D FFT is of size max(imgSize * 2, sampleDist * 2). // 3. Stretch, rotate and make it fill the plane // - Stretch with 1/|uvw| // - Rotate with phi // 4. Add to output const size_t sampleDist = 2 * ((size_t)round(lowestFrequency / frequencyStep) + channelCount); const size_t fftSize = std::max((size_t)(imgSize * sampleDist / (scale * (2.0 * uvDist))), 2 * sampleDist); fftw_complex* fftInp = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (fftSize / 2 + 1)); double* fftOut = (double*)fftw_malloc(sizeof(double) * fftSize); fftw_plan plan = fftw_plan_dft_c2r_1d(fftSize, fftInp, fftOut, FFTW_ESTIMATE); const size_t startChannel = (lowestFrequency / frequencyStep); for (size_t i = 0; i != (fftSize / 2 + 1); ++i) { fftInp[i][0] = 0.0; fftInp[i][1] = 0.0; } for (size_t ch = 0; ch != channelCount; ++ch) { // fftInp[fftSize - (startChannel + ch)][0] = data->real(); // fftInp[fftSize - (startChannel + ch)][1] = data->imag(); // fftInp[(startChannel + ch)][0] = data->real(); // fftInp[(startChannel + ch)][1] = -data->imag(); fftInp[(startChannel + ch)][0] = data->real(); fftInp[(startChannel + ch)][1] = data->imag(); ++data; } // Logger::Debug << "FFT...\n"; fftw_execute(plan); fftw_free(fftInp); // fftw gives unnormalized results; have to divide by sqrt fftSize. NumType fftFactor = 1.0 / sqrt(fftSize); for (size_t i = 0; i != fftSize; ++i) { fftOut[i] *= fftFactor; } Logger::Debug << "phi=" << phi << ",imgSize=" << imgSize << ",minLambda=" << minLambda << ",fftSize=" << fftSize << ",uvOnlyDist=" << uvDist << ",sampleDist=" << sampleDist << '\n'; const size_t fftCentre = fftSize / 2; NumType cosPhi = cos(phi), sinPhi = sin(phi); NumType mid = (NumType)imgSize / 2.0; NumType transformGen = scale * (2.0 * uvDist / sampleDist) * (fftSize / imgSize); NumType transformX = cosPhi * transformGen; // Negative rotation (thus positive sin sign) NumType transformY = sinPhi * transformGen; NumType tanZsinChi = 1.0, tanZcosChi = 1.0; // TODO testing! for (size_t y = 0; y != imgSize; ++y) { num_t* destPtr = output.ValuePtr(0, y); NumType m = (NumType)y - mid; for (size_t x = 0; x != imgSize; ++x) { NumType l = (NumType)x - mid; // We need lookup table for ''(sqrt(1-l*l-m*m)-1)'' NumType mSeen = m - (sqrt(1 - l * l - m * m) - 1) * tanZsinChi; NumType lSeen = l + (sqrt(1 - l * l - m * m) - 1) * tanZcosChi; NumType yrTransformed = mSeen * transformY; NumType srcX = lSeen * transformX + yrTransformed; const size_t srcXIndex = (size_t)round(srcX) + fftCentre; if (srcXIndex < fftSize) { if (srcXIndex < fftCentre) *destPtr += fftOut[srcXIndex + fftCentre]; else *destPtr += fftOut[srcXIndex - fftCentre]; } ++destPtr; } } fftw_destroy_plan(plan); fftw_free(fftOut); } template class BaselineTimePlaneImager; template class BaselineTimePlaneImager; } // namespace algorithms aoflagger-v3.4.0/algorithms/testsetgenerator.cpp0000644000175000017500000005474014507760372020625 0ustar olesoles#include "testsetgenerator.h" #include #include #include #include "combinatorialthresholder.h" #include "highpassfilter.h" #include "../structures/image2d.h" #include "../msio/pngfile.h" #include "../util/logger.h" #include "../util/ffttools.h" #include "../util/stopwatch.h" #include "../imaging/defaultmodels.h" #include "../imaging/model.h" #include "../imaging/observatorium.h" namespace algorithms { void TestSetGenerator::AddSpectralLine(Image2D& data, Mask2D& rfi, double lineStrength, size_t startChannel, size_t nChannels, double timeRatio, double timeOffsetRatio, enum BroadbandShape shape) { const size_t width = data.Width(); const size_t tStart = size_t(timeOffsetRatio * width); const size_t tEnd = size_t((timeOffsetRatio + timeRatio) * width); const double tDuration = tEnd - tStart; for (size_t t = tStart; t != tEnd; ++t) { // x will run from -1 to 1 const double x = (double)((t - tStart) * 2) / tDuration - 1.0; const double factor = shapeLevel(shape, x); for (size_t ch = startChannel; ch < startChannel + nChannels; ++ch) { const double value = lineStrength * factor; data.AddValue(t, ch, value); if (value != 0.0) rfi.SetValue(t, ch, true); } } } void TestSetGenerator::AddIntermittentSpectralLine(Image2D& data, Mask2D& rfi, double strength, size_t channel, double probability, std::mt19937& mt) { std::uniform_real_distribution distribution(0.0, 1.0); const size_t width = data.Width(); for (size_t t = 0; t != width; ++t) { if (distribution(mt) < probability) { data.AddValue(t, channel, strength); rfi.SetValue(t, channel, true); } } } void TestSetGenerator::AddBroadbandLine(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration, double frequencyRatio, double frequencyOffsetRatio) { const size_t frequencyCount = data.Height(); const unsigned fStart = (size_t)(frequencyOffsetRatio * frequencyCount); const unsigned fEnd = (size_t)((frequencyOffsetRatio + frequencyRatio) * frequencyCount); AddBroadbandLinePos(data, rfi, lineStrength, startTime, duration, fStart, fEnd, UniformShape); } void TestSetGenerator::AddBroadbandLinePos(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration, unsigned frequencyStart, double frequencyEnd, enum BroadbandShape shape) { const double s = frequencyEnd - frequencyStart; for (size_t f = frequencyStart; f < frequencyEnd; ++f) { // x will run from -1 to 1 const double x = (double)((f - frequencyStart) * 2) / s - 1.0; const double factor = shapeLevel(shape, x); for (size_t t = startTime; t < startTime + duration; ++t) { data.AddValue(t, f, lineStrength * factor); if (lineStrength > 0.0) rfi.SetValue(t, f, true); } } } void TestSetGenerator::AddSlewedBroadbandLinePos( Image2D& data, Mask2D& rfi, double lineStrength, double slewrate, size_t startTime, size_t duration, unsigned frequencyStart, double frequencyEnd, enum BroadbandShape shape) { const double s = (frequencyEnd - frequencyStart); for (size_t f = frequencyStart; f < frequencyEnd; ++f) { // x will run from -1 to 1 const double x = (double)((f - frequencyStart) * 2) / s - 1.0; const double factor = shapeLevel(shape, x); const double slew = slewrate * (double)f; const size_t slewInt = (size_t)slew; const double slewRest = slew - slewInt; data.AddValue(startTime + slewInt, f, lineStrength * factor * (1.0 - slewRest)); if (lineStrength > 0.0) rfi.SetValue(startTime + slewInt, f, true); for (size_t t = startTime + 1; t < startTime + duration; ++t) { data.AddValue(t + slewInt, f, lineStrength * factor); if (lineStrength > 0.0) rfi.SetValue(t + slewInt, f, true); } data.AddValue(startTime + duration + slewInt, f, lineStrength * factor * slewRest); if (lineStrength > 0.0) rfi.SetValue(startTime + duration + slewInt, f, true); } } void TestSetGenerator::AddRfiPos(Image2D& data, Mask2D& rfi, double lineStrength, size_t startTime, size_t duration, unsigned frequencyPos) { for (size_t t = startTime; t < startTime + duration; ++t) { data.AddValue(t, frequencyPos, lineStrength); if (lineStrength > 0) rfi.SetValue(t, frequencyPos, true); } } Image2D TestSetGenerator::MakeRayleighData(unsigned width, unsigned height) { Image2D image = Image2D::MakeUnsetImage(width, height); for (unsigned y = 0; y < height; ++y) { for (unsigned x = 0; x < width; ++x) { image.SetValue(x, y, RNG::Rayleigh()); } } return image; } Image2D TestSetGenerator::MakeGaussianData(unsigned width, unsigned height) { Image2D image = Image2D::MakeUnsetImage(width, height); for (unsigned y = 0; y < height; ++y) { for (unsigned x = 0; x < width; ++x) { image.SetValue(x, y, RNG::Gaussian()); } } return image; } std::string TestSetGenerator::GetDescription(BackgroundTestSet backgroundSet) { switch (backgroundSet) { case BackgroundTestSet::Empty: return "Empty"; case BackgroundTestSet::LowFrequency: return "Low frequency sinusoid"; case BackgroundTestSet::HighFrequency: return "High frequency sinusoids"; case BackgroundTestSet::ThreeSources: return "Three sources"; case BackgroundTestSet::FiveSources: return "Five sources"; case BackgroundTestSet::FiveFilteredSources: return "Five filtered sources"; case BackgroundTestSet::StaticSidelobeSource: return "Static sidelobe source"; case BackgroundTestSet::StrongVariableSidelobeSource: return "Strong sidelobe source"; case BackgroundTestSet::FaintVariableSidelobeSource: return "Faint sidelobe source"; case BackgroundTestSet::Checker: return "Checker grid"; } return ""; } std::string TestSetGenerator::GetDescription(RFITestSet rfiSet) { switch (rfiSet) { case RFITestSet::Empty: return "Empty"; case RFITestSet::SpectralLines: return "Spectral lines"; case RFITestSet::GaussianSpectralLines: return "Gaussian spectral lines"; case RFITestSet::IntermittentSpectralLines: return "Intermittent spectral lines"; case RFITestSet::FullBandBursts: return "Full-band bursts / A"; case RFITestSet::HalfBandBursts: return "Half-band bursts / B"; case RFITestSet::VaryingBursts: return "Varying bursts / C"; case RFITestSet::GaussianBursts: return "Gaussian bursts"; case RFITestSet::SinusoidalBursts: return "Sinusodial bursts"; case RFITestSet::SlewedGaussians: return "Slewed Gaussian bursts"; case RFITestSet::FluctuatingBursts: return "Fluctuating bursts"; case RFITestSet::StrongPowerLaw: return "Strong power law RFI"; case RFITestSet::MediumPowerLaw: return "Medium power law RFI"; case RFITestSet::WeakPowerLaw: return "Weak power law RFI"; case RFITestSet::PolarizedSpike: return "Polarized spike"; } return std::string(); } TimeFrequencyData TestSetGenerator::MakeTestSet(RFITestSet rfiSet, BackgroundTestSet backgroundSet, size_t width, size_t height) { TimeFrequencyData data; if (rfiSet == algorithms::RFITestSet::PolarizedSpike) { std::vector images(8); images[0] = Image2D::CreateZeroImagePtr(width, height); for (size_t p = 1; p != 8; ++p) { images[p] = images[0]; } data = TimeFrequencyData::FromLinear(images[0], images[1], images[2], images[3], images[4], images[5], images[6], images[7]); } else { const Image2DPtr real = Image2D::MakePtr(TestSetGenerator::MakeNoise(width, height, 1.0)); const Image2DPtr imag = Image2D::MakePtr(TestSetGenerator::MakeNoise(width, height, 1.0)); data = TimeFrequencyData(aocommon::Polarization::StokesI, real, imag); } TestSetGenerator::MakeTestSet(rfiSet, data); TestSetGenerator::MakeBackground(backgroundSet, data); return data; } void TestSetGenerator::MakeBackground(BackgroundTestSet testSet, TimeFrequencyData& data) { if (testSet == BackgroundTestSet::StaticSidelobeSource || testSet == BackgroundTestSet::StrongVariableSidelobeSource || testSet == BackgroundTestSet::FaintVariableSidelobeSource) { SourceSet source; switch (testSet) { default: case BackgroundTestSet::StaticSidelobeSource: source = SourceSet::ConstantDistortion; break; case BackgroundTestSet::StrongVariableSidelobeSource: source = SourceSet::StrongVariableDistortion; break; case BackgroundTestSet::FaintVariableSidelobeSource: source = SourceSet::FaintVariableDistortion; break; } const size_t channelCount = data.ImageHeight(); double bandwidth; bandwidth = (double)channelCount / 16.0 * 2500000.0; const std::pair pair = DefaultModels::LoadSet(DefaultModels::NCPSet, source, 0.0, channelCount, bandwidth); data = pair.first; } else { for (size_t polIndex = 0; polIndex != data.PolarizationCount(); ++polIndex) { TimeFrequencyData polData = data.MakeFromPolarizationIndex(polIndex); for (size_t imageIndex = 0; imageIndex != polData.ImageCount(); ++imageIndex) { const bool isImaginary = imageIndex == 1; if (isImaginary) { const Image2DPtr image = Image2D::MakePtr(*polData.GetImage(imageIndex)); const size_t width = image->Width(); const size_t height = image->Height(); switch (testSet) { default: case BackgroundTestSet::Empty: break; case BackgroundTestSet::LowFrequency: for (unsigned y = 0; y < image->Height(); ++y) { for (unsigned x = 0; x < image->Width(); ++x) { image->AddValue( x, y, sinn(num_t(x) * M_PIn * 5.0 / image->Width()) + 0.1); } } break; case BackgroundTestSet::HighFrequency: for (unsigned y = 0; y < image->Height(); ++y) { for (unsigned x = 0; x < image->Width(); ++x) { image->AddValue(x, y, sinn((long double)(x + y * 0.1) * M_PIn * 5.0L / image->Width() + 0.1)); image->AddValue(x, y, sinn((long double)(x + pown(y, 1.1)) * M_PIn * 50.0L / image->Width() + 0.1)); } } for (unsigned y = 0; y < image->Height(); ++y) { for (unsigned x = 0; x < image->Width(); ++x) { image->AddValue(x, y, 1.0); } } break; case BackgroundTestSet::ThreeSources: SetModelData(*image, 3, width, height); break; case BackgroundTestSet::FiveSources: SetModelData(*image, 5, width, height); break; case BackgroundTestSet::FiveFilteredSources: SetModelData(*image, 5, width, height); SubtractBackground(*image); break; case BackgroundTestSet::Checker: for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { image->SetValue(x, y, ((x + y) % 2 == 0) ? -1 : 2); } } break; } polData.SetImage(imageIndex, image); } // if is imaginary } // for over image index data.SetPolarizationData(polIndex, polData); } // for over polarizations } } void TestSetGenerator::MakeTestSet(RFITestSet testSet, TimeFrequencyData& data) { for (size_t polIndex = 0; polIndex != data.PolarizationCount(); ++polIndex) { TimeFrequencyData polData = data.MakeFromPolarizationIndex(polIndex); const Mask2DPtr rfi(Mask2D::MakePtr(*polData.GetSingleMask())); for (size_t imageIndex = 0; imageIndex != polData.ImageCount(); ++imageIndex) { const bool isImaginary = imageIndex == 1; const Image2DPtr image = Image2D::MakePtr(*polData.GetImage(imageIndex)); const size_t width = image->Width(); const size_t height = image->Height(); if (polIndex == 2 && isImaginary && testSet == RFITestSet::PolarizedSpike) { // Set one absurdly high value which all strategies should detect size_t rfiX = width / 2, rfiY = height / 2; image->SetValue(rfiX, rfiY, 1000.0); } else if (!isImaginary) { switch (testSet) { case RFITestSet::Empty: break; case RFITestSet::SpectralLines: AddSpectralLinesToTestSet(*image, *rfi, 1.0, UniformShape); break; case RFITestSet::GaussianSpectralLines: AddSpectralLinesToTestSet(*image, *rfi, 1.0, GaussianShape); break; case RFITestSet::IntermittentSpectralLines: AddIntermittentSpectralLinesToTestSet(*image, *rfi, 10.0); break; case RFITestSet::FullBandBursts: AddBroadbandToTestSet(*image, *rfi, 1.0); break; case RFITestSet::HalfBandBursts: AddBroadbandToTestSet(*image, *rfi, 0.5); break; case RFITestSet::VaryingBursts: AddVarBroadbandToTestSet(*image, *rfi); break; case RFITestSet::GaussianBursts: AddBroadbandToTestSet(*image, *rfi, 1.0, 1.0, GaussianShape); break; case RFITestSet::SinusoidalBursts: AddBroadbandToTestSet(*image, *rfi, 1.0, 1.0, SinusoidalShape); break; case RFITestSet::SlewedGaussians: AddSlewedBroadbandToTestSet(*image, *rfi, 1.0); break; case RFITestSet::FluctuatingBursts: AddBurstBroadbandToTestSet(*image, *rfi); break; case RFITestSet::StrongPowerLaw: *image += sampleRFIDistribution(width, height, 1.0); rfi->SetAll(); break; case RFITestSet::MediumPowerLaw: *image += sampleRFIDistribution(width, height, 0.1); rfi->SetAll(); break; case RFITestSet::WeakPowerLaw: *image += sampleRFIDistribution(width, height, 0.01); rfi->SetAll(); break; case RFITestSet::PolarizedSpike: break; } } polData.SetImage(imageIndex, image); } polData.SetGlobalMask(rfi); data.SetPolarizationData(polIndex, polData); } } void TestSetGenerator::AddSpectralLinesToTestSet(Image2D& image, Mask2D& rfi, double baseStrength, enum BroadbandShape shape) { for (size_t i = 0; i != 10; ++i) { const size_t channel = ((i * 2 + 1) * image.Height()) / 20; const double strength = baseStrength * (1.0 + (i * 2.0 / 10.0)); AddSpectralLine(image, rfi, strength, channel, 1, 1.0, 0.0, shape); } } void TestSetGenerator::AddIntermittentSpectralLinesToTestSet(Image2D& image, Mask2D& rfi, double strength) { std::mt19937 mt; for (size_t i = 0; i != 20; ++i) { const size_t channel = ((i * 2 + 1) * image.Height()) / 40; const double probability = (i + 5) * 1.0 / 28.0; AddIntermittentSpectralLine(image, rfi, strength, channel, probability, mt); } } void TestSetGenerator::AddBroadbandToTestSet(Image2D& image, Mask2D& rfi, double length, double strength, enum BroadbandShape shape) { const size_t frequencyCount = image.Height(); const unsigned step = image.Width() / 11; const unsigned fStart = (unsigned)((0.5 - length / 2.0) * frequencyCount); const unsigned fEnd = (unsigned)((0.5 + length / 2.0) * frequencyCount); AddBroadbandLinePos(image, rfi, 3.0 * strength, step * 1, 3, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 2.5 * strength, step * 2, 3, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 2.0 * strength, step * 3, 3, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 1.8 * strength, step * 4, 3, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 1.6 * strength, step * 5, 3, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 3.0 * strength, step * 6, 1, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 2.5 * strength, step * 7, 1, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 2.0 * strength, step * 8, 1, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 1.8 * strength, step * 9, 1, fStart, fEnd, shape); AddBroadbandLinePos(image, rfi, 1.6 * strength, step * 10, 1, fStart, fEnd, shape); } void TestSetGenerator::AddSlewedBroadbandToTestSet(Image2D& image, Mask2D& rfi, double length, double strength, double slewrate, enum BroadbandShape shape) { const size_t frequencyCount = image.Height(); const unsigned step = image.Width() / 11; const unsigned fStart = (unsigned)((0.5 - length / 2.0) * frequencyCount); const unsigned fEnd = (unsigned)((0.5 + length / 2.0) * frequencyCount); AddSlewedBroadbandLinePos(image, rfi, 3.0 * strength, slewrate, step * 1, 3, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 2.5 * strength, slewrate, step * 2, 3, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 2.0 * strength, slewrate, step * 3, 3, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 1.8 * strength, slewrate, step * 4, 3, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 1.6 * strength, slewrate, step * 5, 3, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 3.0 * strength, slewrate, step * 6, 1, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 2.5 * strength, slewrate, step * 7, 1, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 2.0 * strength, slewrate, step * 8, 1, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 1.8 * strength, slewrate, step * 9, 1, fStart, fEnd, shape); AddSlewedBroadbandLinePos(image, rfi, 1.6 * strength, slewrate, step * 10, 1, fStart, fEnd, shape); } void TestSetGenerator::AddVarBroadbandToTestSet(Image2D& image, Mask2D& rfi) { // The "randomness" should be reproducable randomness, so calling // the random number generator to generate the numbers is not a good // idea. const unsigned step = image.Width() / 11; AddBroadbandLine(image, rfi, 3.0, step * 1, 3, 0.937071, 0.0185952); AddBroadbandLine(image, rfi, 2.5, step * 2, 3, 0.638442, 0.327689); AddBroadbandLine(image, rfi, 2.0, step * 3, 3, 0.859308, 0.0211675); AddBroadbandLine(image, rfi, 1.8, step * 4, 3, 0.418327, 0.324842); AddBroadbandLine(image, rfi, 1.6, step * 5, 3, 0.842374, 0.105613); AddBroadbandLine(image, rfi, 3.0, step * 6, 1, 0.704607, 0.163653); AddBroadbandLine(image, rfi, 2.5, step * 7, 1, 0.777955, 0.0925143); AddBroadbandLine(image, rfi, 2.0, step * 8, 1, 0.288418, 0.222322); AddBroadbandLine(image, rfi, 1.8, step * 9, 1, 0.892462, 0.0381083); AddBroadbandLine(image, rfi, 1.6, step * 10, 1, 0.444377, 0.240526); } void TestSetGenerator::SetModelData(Image2D& image, unsigned sources, size_t width, size_t height) { class Model model; if (sources >= 5) { model.AddSource(0.1, 0.1, 0.5); model.AddSource(0.1, 0.0, 0.35); model.AddSource(.101, 0.001, 0.45); model.AddSource(1.0, 0.0, 1.0); model.AddSource(4.0, 3.0, 0.9); } else { if (sources >= 1) model.AddSource(0.1, 0.1, 0.7); if (sources >= 2) model.AddSource(0.1, 0.0, 0.5); if (sources >= 3) model.AddSource(1.0, 0.0, 1.0); } WSRTObservatorium wsrt(size_t(0), size_t(1), height); const std::pair data = model.SimulateObservation(width, wsrt, 0.05, 0.05, 0, 1); image = *data.first.GetRealPart(); } void TestSetGenerator::SubtractBackground(Image2D& image) { const Mask2DPtr zero = Mask2D::CreateSetMaskPtr(image.Width(), image.Height()); HighPassFilter filter; filter.SetHKernelSigmaSq(7.5 * 7.5); filter.SetVKernelSigmaSq(15.0 * 15.0); filter.SetHWindowSize(20); filter.SetVWindowSize(40); const Image2DPtr imagePtr = Image2D::MakePtr(image); image = *filter.ApplyHighPass(imagePtr, zero); } Image2D TestSetGenerator::sampleRFIDistribution(unsigned width, unsigned height, double ig_over_rsq) { Image2D image = Image2D::MakeUnsetImage(width, height); const double sigma = 1.0; for (size_t f = 0; f < height; ++f) { for (size_t t = 0; t < width; ++t) { image.SetValue(t, f, Rand(Gaussian) * sigma + ig_over_rsq / RNG::Uniform()); } } return image; } } // namespace algorithms aoflagger-v3.4.0/algorithms/timefrequencystatistics.cpp0000644000175000017500000000172114507760372022205 0ustar olesoles#include "timefrequencystatistics.h" #include #include #include namespace algorithms { TimeFrequencyStatistics::TimeFrequencyStatistics(const TimeFrequencyData& data) : _data(data) {} num_t TimeFrequencyStatistics::GetFlaggedRatio() { size_t total = 0, flagged = 0; for (size_t i = 0; i < _data.MaskCount(); ++i) { const Mask2DCPtr mask = _data.GetMask(i); flagged += mask->GetCount(); total += mask->Width() * mask->Height(); } if (total != 0) return (num_t)flagged / (num_t)total; else return 0; } std::string TimeFrequencyStatistics::FormatRatio(num_t ratio) { std::stringstream s; if (ratio > 0.01) s << (round(ratio * 10000.0) / 100.0) << "%"; else if (ratio > 0.001) s << (round(ratio * 100000.0) / 1000.0) << "%"; else if (ratio > 0.0001) s << (round(ratio * 1000000.0) / 10000.0) << "%"; else s << (ratio * 100.0) << "%"; return s.str(); } } // namespace algorithms aoflagger-v3.4.0/algorithms/combinatorialthresholder.h0000644000175000017500000000135014507760372021744 0ustar olesoles#ifndef COMBINATORIAL_THRESHOLDER_H #define COMBINATORIAL_THRESHOLDER_H #include #include #include "../structures/image2d.h" #include "../structures/mask2d.h" namespace algorithms { class CombinatorialThresholder { public: static void VarThreshold(const Image2D* input, Mask2D* mask, size_t length, num_t threshold); static void HorizontalVarThreshold(const Image2D* input, Mask2D* mask, size_t length, num_t threshold); static void VerticalVarThreshold(const Image2D* input, Mask2D* mask, size_t length, num_t threshold); private: CombinatorialThresholder() = delete; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/svdmitigater.cpp0000644000175000017500000001323114507760372017713 0ustar olesoles#include "../util/stopwatch.h" #include "svdmitigater.h" #ifdef HAVE_GTKMM #include "../plot/xyplot.h" #endif extern "C" { int zgesvd_(char* jobu, char* jobvt, integer* m, integer* n, doublecomplex* a, integer* lda, doublereal* s, doublecomplex* u, integer* ldu, doublecomplex* vt, integer* ldvt, doublecomplex* work, integer* lwork, doublereal* rwork, integer* info); } namespace algorithms { SVDMitigater::SVDMitigater() : _background(nullptr), _singularValues(nullptr), _leftSingularVectors(nullptr), _rightSingularVectors(nullptr), _m(0), _n(0), _iteration(0), _removeCount(10), _verbose(false) {} SVDMitigater::~SVDMitigater() { Clear(); } void SVDMitigater::Clear() { if (IsDecomposed()) { delete[] _singularValues; delete[] _leftSingularVectors; delete[] _rightSingularVectors; _singularValues = nullptr; _leftSingularVectors = nullptr; _rightSingularVectors = nullptr; } if (_background != nullptr) delete _background; } // lda = leading dimension /*int cgebrd_(integer *m, integer *n, complex *a, integer *lda, real *d__, real *e, complex *tauq, complex *taup, complex *work, integer *lwork, integer *info);*/ void SVDMitigater::Decompose() { if (_verbose) std::cout << "Decomposing..." << std::endl; Stopwatch watch; watch.Start(); Clear(); // Remember that the axes have to be turned; in 'a', time is along the // vertical axis. _m = _data.ImageHeight(); _n = _data.ImageWidth(); const int minmn = _m < _n ? _m : _n; char rowsOfU = 'A'; // all rows of u char rowsOfVT = 'A'; // all rows of VT doublecomplex* a = new doublecomplex[_m * _n]; Image2DCPtr real = _data.GetRealPart(), imaginary = _data.GetImaginaryPart(); for (int t = 0; t < _n; ++t) { for (int f = 0; f < _m; ++f) { a[t * _m + f].r = real->Value(t, f); a[t * _m + f].i = imaginary->Value(t, f); } } long int lda = _m; _singularValues = new double[minmn]; for (int i = 0; i < minmn; ++i) _singularValues[i] = 0.0; _leftSingularVectors = new doublecomplex[_m * _m]; for (int i = 0; i < _m * _m; ++i) { _leftSingularVectors[i].r = 0.0; _leftSingularVectors[i].i = 0.0; } _rightSingularVectors = new doublecomplex[_n * _n]; for (int i = 0; i < _n * _n; ++i) { _rightSingularVectors[i].r = 0.0; _rightSingularVectors[i].i = 0.0; } long int info = 0; doublecomplex complexWorkAreaSize; long int workAreaSize = -1; double* workArea2 = new double[5 * minmn]; // Determine optimal workareasize zgesvd_(&rowsOfU, &rowsOfVT, &_m, &_n, a, &lda, _singularValues, _leftSingularVectors, &_m, _rightSingularVectors, &_n, &complexWorkAreaSize, &workAreaSize, workArea2, &info); if (info == 0) { if (_verbose) std::cout << "zgesvd_..." << std::endl; workAreaSize = (int)complexWorkAreaSize.r; doublecomplex* workArea1 = new doublecomplex[workAreaSize]; zgesvd_(&rowsOfU, &rowsOfVT, &_m, &_n, a, &lda, _singularValues, _leftSingularVectors, &_m, _rightSingularVectors, &_n, workArea1, &workAreaSize, workArea2, &info); delete[] workArea1; } delete[] workArea2; delete[] a; if (_verbose) { for (int i = 0; i < minmn; ++i) std::cout << _singularValues[i] << ","; std::cout << std::endl; std::cout << watch.ToString() << std::endl; } } void SVDMitigater::Compose() { if (_verbose) std::cout << "Composing..." << std::endl; Stopwatch watch; watch.Start(); const Image2DPtr real = Image2D::CreateUnsetImagePtr(_data.ImageWidth(), _data.ImageHeight()); const Image2DPtr imaginary = Image2D::CreateUnsetImagePtr(_data.ImageWidth(), _data.ImageHeight()); const int minmn = _m < _n ? _m : _n; for (int t = 0; t < _n; ++t) { for (int f = 0; f < _m; ++f) { double a_tf_r = 0.0; double a_tf_i = 0.0; // A = U S V^T , so: // a_tf = \sum_{g=0}^{minmn} U_{gf} S_{gg} V^T_{tg} // Note that _rightSingularVectors=V^T, thus is already stored rowwise for (int g = 0; g < minmn; ++g) { const double u_r = _leftSingularVectors[g * _m + f].r; const double u_i = _leftSingularVectors[g * _m + f].i; const double s = _singularValues[g]; const double v_r = _rightSingularVectors[t * _n + g].r; const double v_i = _rightSingularVectors[t * _n + g].i; a_tf_r += s * (u_r * v_r - u_i * v_i); a_tf_i += s * (u_r * v_i + u_i * v_r); } real->SetValue(t, f, a_tf_r); imaginary->SetValue(t, f, a_tf_i); } } if (_background != nullptr) delete _background; _background = new TimeFrequencyData(aocommon::Polarization::StokesI, real, imaginary); if (_verbose) std::cout << watch.ToString() << std::endl; } #ifdef HAVE_GTKMM void SVDMitigater::CreateSingularValueGraph(const TimeFrequencyData& data, XYPlot& plot) { const size_t polarisationCount = data.PolarizationCount(); plot.SetTitle("Distribution of singular values"); plot.YAxis().SetLogarithmic(true); for (size_t i = 0; i < polarisationCount; ++i) { const TimeFrequencyData polarizationData(data.MakeFromPolarizationIndex(i)); SVDMitigater svd; svd.Initialize(polarizationData); svd.Decompose(); const size_t minmn = svd._m < svd._n ? svd._m : svd._n; XYPointSet& pointSet = plot.StartLine(polarizationData.Description()); pointSet.SetXDesc("Singular value index"); pointSet.SetYDesc("Singular value"); for (size_t i = 0; i < minmn; ++i) plot.PushDataPoint(i, svd.SingularValue(i)); } } #else void SVDMitigater::CreateSingularValueGraph(const TimeFrequencyData&, XYPlot&) { } #endif } // namespace algorithms aoflagger-v3.4.0/algorithms/thresholdconfig.cpp0000644000175000017500000001075414507760372020402 0ustar olesoles#include "thresholdconfig.h" #include #include #include #include "../structures/image2d.h" #include "../util/rng.h" #include "thresholdtools.h" #include "sumthreshold.h" #include "sumthresholdmissing.h" namespace algorithms { ThresholdConfig::ThresholdConfig() : _distribution(Gaussian) {} void ThresholdConfig::InitializeLengthsDefault(unsigned count) { if (count > 9 || count == 0) count = 9; constexpr size_t lengths[9] = {1, 2, 4, 8, 16, 32, 64, 128, 256}; _horizontalOperations.clear(); _horizontalOperations.reserve(count); _verticalOperations.clear(); _verticalOperations.reserve(count); for (unsigned i = 0; i < count; ++i) { _horizontalOperations.emplace_back(lengths[i]); _verticalOperations.emplace_back(lengths[i]); } } void ThresholdConfig::InitializeLengthsSingleSample() { _horizontalOperations.emplace_back(1); _verticalOperations.emplace_back(1); } void ThresholdConfig::InitializeThresholdsFromFirstThreshold( num_t firstThreshold, Distribution noiseDistribution) { constexpr num_t exp_base = 1.5; for (ThresholdConfig::ThresholdOperation& op : _horizontalOperations) { op.threshold = firstThreshold * std::pow(exp_base, std::log2(op.length)) / op.length; } for (ThresholdConfig::ThresholdOperation& op : _verticalOperations) { op.threshold = firstThreshold * std::pow(exp_base, std::log2(op.length)) / op.length; } _distribution = noiseDistribution; } void ThresholdConfig::Execute(const Image2D* image, Mask2D* mask, bool additive, num_t timeSensitivity, num_t frequencySensitivity) const { ExecuteWithMissing(image, mask, nullptr, additive, timeSensitivity, frequencySensitivity); } void ThresholdConfig::ExecuteWithMissing(const Image2D* image, Mask2D* mask, const Mask2D* missing, bool additive, num_t timeSensitivity, num_t frequencySensitivity) const { num_t timeFactor = timeSensitivity; num_t frequencyFactor = frequencySensitivity; Image2D modified_image; if (!image->AllFinite()) { modified_image = image->MakeFiniteCopy(); image = &modified_image; } switch (_distribution) { case Gaussian: { num_t mean, stddev; if (missing == nullptr) ThresholdTools::WinsorizedMeanAndStdDev(image, mask, mean, stddev); else ThresholdTools::WinsorizedMeanAndStdDev(image, mask, missing, mean, stddev); if (stddev != 0.0L) { timeFactor = stddev * timeSensitivity; frequencyFactor = stddev * frequencySensitivity; } } break; case Rayleigh: { num_t mode; if (missing == nullptr) mode = ThresholdTools::WinsorizedMode(image, mask); else mode = ThresholdTools::WinsorizedMode(image, mask, missing); if (mode != 0.0L) { timeFactor = timeSensitivity * mode; frequencyFactor = frequencySensitivity * mode; } } break; } if (!additive) mask->SetAll(); Mask2D scratch(*mask); const size_t operationCount = std::max(_horizontalOperations.size(), _verticalOperations.size()); SumThreshold::VerticalScratch normalScratch(mask->Width(), mask->Height()); SumThresholdMissing::VerticalCache vMissingCache; if (missing) SumThresholdMissing::InitializeVertical(vMissingCache, *image, *missing); for (size_t i = 0; i < operationCount; ++i) { if (i < _horizontalOperations.size()) { if (missing == nullptr) { SumThreshold::HorizontalLarge( image, mask, &scratch, _horizontalOperations[i].length, _horizontalOperations[i].threshold * timeFactor); } else { SumThresholdMissing::Horizontal( *image, *mask, *missing, scratch, _horizontalOperations[i].length, _horizontalOperations[i].threshold * timeFactor); } } if (i < _verticalOperations.size()) { if (missing == nullptr) SumThreshold::VerticalLarge( image, mask, &scratch, &normalScratch, _verticalOperations[i].length, _verticalOperations[i].threshold * frequencyFactor); else SumThresholdMissing::VerticalStacked( vMissingCache, *image, *mask, *missing, scratch, _verticalOperations[i].length, _verticalOperations[i].threshold * frequencyFactor); } } } } // namespace algorithms aoflagger-v3.4.0/algorithms/sumthreshold.cpp0000644000175000017500000017337314507760372017750 0ustar olesoles#include "sumthreshold.h" #include "../structures/image2d.h" #include "../util/logger.h" #include #if defined(__SSE__) || defined(__x86_64__) #include #include #include #endif namespace algorithms { SumThreshold::VerticalScratch::VerticalScratch() : lastFlaggedPos(nullptr, [](void*) noexcept {}), sum(nullptr, [](void*) noexcept {}), count(nullptr, [](void*) noexcept {}) {} SumThreshold::VerticalScratch::VerticalScratch(size_t width, size_t) : lastFlaggedPos(static_cast(boost::alignment::aligned_alloc( 64, sizeof(int) * width)), &free), sum(static_cast( boost::alignment::aligned_alloc(64, sizeof(num_t) * width)), &free), count(static_cast( boost::alignment::aligned_alloc(64, sizeof(int) * width)), &free) {} template void SumThreshold::Horizontal(const Image2D* input, Mask2D* mask, num_t threshold) { if (Length <= input->Width()) { const size_t width = input->Width() - Length + 1; for (size_t y = 0; y < input->Height(); ++y) { for (size_t x = 0; x < width; ++x) { num_t sum = 0.0; size_t count = 0; for (size_t i = 0; i < Length; ++i) { if (!mask->Value(x + i, y)) { sum += input->Value(x + i, y); count++; } } if (count > 0 && fabs(sum / count) > threshold) { for (size_t i = 0; i < Length; ++i) mask->SetValue(x + i, y, true); } } } } } template void SumThreshold::Vertical(const Image2D* input, Mask2D* mask, num_t threshold) { if (Length <= input->Height()) { const size_t height = input->Height() - Length + 1; for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < input->Width(); ++x) { num_t sum = 0.0; size_t count = 0; for (size_t i = 0; i < Length; ++i) { if (!mask->Value(x, y + i)) { sum += input->Value(x, y + i); count++; } } if (count > 0 && fabs(sum / count) > threshold) { for (size_t i = 0; i < Length; ++i) mask->SetValue(x, y + i, true); } } } } } template void SumThreshold::HorizontalLarge(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold) { *scratch = *mask; const size_t width = mask->Width(), height = mask->Height(); if (Length <= width) { for (size_t y = 0; y < height; ++y) { num_t sum = 0.0; size_t count = 0, xLeft, xRight; for (xRight = 0; xRight < Length - 1; ++xRight) { if (!mask->Value(xRight, y)) { sum += input->Value(xRight, y); count++; } } xLeft = 0; while (xRight < width) { // add the sample at the right if (!mask->Value(xRight, y)) { sum += input->Value(xRight, y); ++count; } // Check if (count > 0 && std::fabs(sum / count) > threshold) { scratch->SetHorizontalValues(xLeft, y, true, Length); } // subtract the sample at the left if (!mask->Value(xLeft, y)) { sum -= input->Value(xLeft, y); --count; } ++xLeft; ++xRight; } } } *mask = std::move(*scratch); } template void SumThreshold::VerticalLarge(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold) { *scratch = *mask; const size_t width = mask->Width(), height = mask->Height(); if (Length <= height) { for (size_t x = 0; x < width; ++x) { num_t sum = 0.0; size_t count = 0, yTop, yBottom; for (yBottom = 0; yBottom < Length - 1; ++yBottom) { if (!mask->Value(x, yBottom)) { sum += input->Value(x, yBottom); ++count; } } yTop = 0; while (yBottom < height) { // add the sample at the bottom if (!mask->Value(x, yBottom)) { sum += input->Value(x, yBottom); ++count; } // Check if (count > 0 && std::fabs(sum / count) > threshold) { for (size_t i = 0; i < Length; ++i) scratch->SetValue(x, yTop + i, true); } // subtract the sample at the top if (!mask->Value(x, yTop)) { sum -= input->Value(x, yTop); --count; } ++yTop; ++yBottom; } } } *mask = std::move(*scratch); } void SumThreshold::HorizontalLargeReference(const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold) { switch (length) { case 1: Horizontal<1>(input, mask, threshold); break; case 2: HorizontalLarge<2>(input, mask, scratch, threshold); break; case 4: HorizontalLarge<4>(input, mask, scratch, threshold); break; case 8: HorizontalLarge<8>(input, mask, scratch, threshold); break; case 16: HorizontalLarge<16>(input, mask, scratch, threshold); break; case 32: HorizontalLarge<32>(input, mask, scratch, threshold); break; case 64: HorizontalLarge<64>(input, mask, scratch, threshold); break; case 128: HorizontalLarge<128>(input, mask, scratch, threshold); break; case 256: HorizontalLarge<256>(input, mask, scratch, threshold); break; default: throw std::runtime_error("Invalid value for length"); } } void SumThreshold::VerticalLargeReference(const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold) { switch (length) { case 1: Vertical<1>(input, mask, threshold); break; case 2: VerticalLarge<2>(input, mask, scratch, threshold); break; case 4: VerticalLarge<4>(input, mask, scratch, threshold); break; case 8: VerticalLarge<8>(input, mask, scratch, threshold); break; case 16: VerticalLarge<16>(input, mask, scratch, threshold); break; case 32: VerticalLarge<32>(input, mask, scratch, threshold); break; case 64: VerticalLarge<64>(input, mask, scratch, threshold); break; case 128: VerticalLarge<128>(input, mask, scratch, threshold); break; case 256: VerticalLarge<256>(input, mask, scratch, threshold); break; default: throw std::runtime_error("Invalid value for length"); } } #if defined(__SSE__) || defined(__x86_64__) __attribute__((target("sse"))) void SumThreshold::VerticalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold) { switch (length) { case 1: Vertical<1>(input, mask, threshold); break; case 2: VerticalLargeSSE<2>(input, mask, scratch, threshold); break; case 4: VerticalLargeSSE<4>(input, mask, scratch, threshold); break; case 8: VerticalLargeSSE<8>(input, mask, scratch, threshold); break; case 16: VerticalLargeSSE<16>(input, mask, scratch, threshold); break; case 32: VerticalLargeSSE<32>(input, mask, scratch, threshold); break; case 64: VerticalLargeSSE<64>(input, mask, scratch, threshold); break; case 128: VerticalLargeSSE<128>(input, mask, scratch, threshold); break; case 256: VerticalLargeSSE<256>(input, mask, scratch, threshold); break; default: throw std::runtime_error("Invalid value for length"); } } __attribute__((target("sse"))) void SumThreshold::HorizontalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold) { switch (length) { case 1: Horizontal<1>(input, mask, threshold); break; case 2: HorizontalLargeSSE<2>(input, mask, scratch, threshold); break; case 4: HorizontalLargeSSE<4>(input, mask, scratch, threshold); break; case 8: HorizontalLargeSSE<8>(input, mask, scratch, threshold); break; case 16: HorizontalLargeSSE<16>(input, mask, scratch, threshold); break; case 32: HorizontalLargeSSE<32>(input, mask, scratch, threshold); break; case 64: HorizontalLargeSSE<64>(input, mask, scratch, threshold); break; case 128: HorizontalLargeSSE<128>(input, mask, scratch, threshold); break; case 256: HorizontalLargeSSE<256>(input, mask, scratch, threshold); break; default: throw std::runtime_error("Invalid value for length"); } } #endif // defined(__SSE__) || defined(__x86_64__) #if defined(__AVX2__) || defined(__x86_64__) __attribute__((target("avx2"))) void SumThreshold::VerticalLargeAVX( const Image2D* input, Mask2D* mask, Mask2D* scratch, size_t length, num_t threshold) { switch (length) { case 1: Vertical<1>(input, mask, threshold); break; case 2: VerticalLargeAVX<2>(input, mask, scratch, threshold); break; case 4: VerticalLargeAVX<4>(input, mask, scratch, threshold); break; case 8: VerticalLargeAVX<8>(input, mask, scratch, threshold); break; case 16: VerticalLargeAVX<16>(input, mask, scratch, threshold); break; case 32: VerticalLargeAVX<32>(input, mask, scratch, threshold); break; case 64: VerticalLargeAVX<64>(input, mask, scratch, threshold); break; case 128: VerticalLargeAVX<128>(input, mask, scratch, threshold); break; case 256: VerticalLargeAVX<256>(input, mask, scratch, threshold); break; default: throw std::runtime_error("Invalid value for length"); } } __attribute__((target("avx2"))) void SumThreshold::HorizontalAVXDumas( const Image2D* input, Mask2D* mask, size_t length, num_t threshold) { switch (length) { case 1: HorizontalAVXDumas<1>(input, mask, threshold); break; case 2: HorizontalAVXDumas<2>(input, mask, threshold); break; case 4: HorizontalAVXDumas<4>(input, mask, threshold); break; case 8: HorizontalAVXDumas<8>(input, mask, threshold); break; case 16: HorizontalAVXDumas<16>(input, mask, threshold); break; case 32: HorizontalAVXDumas<32>(input, mask, threshold); break; case 64: HorizontalAVXDumas<64>(input, mask, threshold); break; case 128: HorizontalAVXDumas<128>(input, mask, threshold); break; case 256: HorizontalAVXDumas<256>(input, mask, threshold); break; default: throw std::runtime_error("Invalid value for length"); } } __attribute__((target("avx2"))) void SumThreshold::VerticalAVXDumas( const Image2D* input, Mask2D* mask, VerticalScratch* scratch, size_t length, num_t threshold) { switch (length) { case 1: VerticalAVXDumas<1>(input, mask, scratch, threshold); break; case 2: VerticalAVXDumas<2>(input, mask, scratch, threshold); break; case 4: VerticalAVXDumas<4>(input, mask, scratch, threshold); break; case 8: VerticalAVXDumas<8>(input, mask, scratch, threshold); break; case 16: VerticalAVXDumas<16>(input, mask, scratch, threshold); break; case 32: VerticalAVXDumas<32>(input, mask, scratch, threshold); break; case 64: VerticalAVXDumas<64>(input, mask, scratch, threshold); break; case 128: VerticalAVXDumas<128>(input, mask, scratch, threshold); break; case 256: VerticalAVXDumas<256>(input, mask, scratch, threshold); break; default: throw std::runtime_error("Invalid value for length"); } } #endif // defined(__AVX2__) || defined(__x86_64__) #if defined(__SSE__) || defined(__x86_64__) /** * The SSE version of the Vertical SumThreshold algorithm using intrinsics. * * The SumThreshold algorithm is applied on 4 time steps at a time. Since the * SSE has instructions that operate on 4 floats at a time, this could in theory * speed up the processing with a factor of 4. However, a lot of time is lost * shuffling the data in the right order/registers, and since a timestep * consists of 1 byte booleans and 4 byte floats, there's a penalty. Finally, * since the 4 timesteps have to be processed exactly the same way, conditional * branches had to be replaced by conditional moves. * * The average profit of SSE intrinsics vs no SSE seems to be about a factor * of 1.5 to 2-3, depending on the Length parameter, but also depending on the * number of flags (With Length=256, it can make a factor of 3 difference). It * might also vary on different processors; e.g. on my Desktop Xeon with older * gcc, the profit was less pronounced, while my Intel i5 at home showed an avg * factor of over 2 difference. * * The algorithm works with Length=1, but since that is a normal thresholding * operation, computing a sumthreshold has a lot of overhead, hence is not * optimal at that size. */ template __attribute__((target("sse"))) void SumThreshold::VerticalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold) { *scratch = *mask; const size_t width = mask->Width(), height = mask->Height(); const __m128 zero4 = _mm_set1_ps(0.0); const __m128i zero4i = _mm_set1_epi32(0); const __m128i ones4 = _mm_set1_epi32(1); const __m128 threshold4Pos = _mm_set1_ps(threshold); const __m128 threshold4Neg = _mm_set1_ps(-threshold); if (Length <= height) { for (size_t x = 0; x < width; x += 4) { __m128 sum4 = _mm_set1_ps(0.0); __m128i count4 = _mm_set1_epi32(0); size_t yBottom; for (yBottom = 0; yBottom + 1 < Length; ++yBottom) { const bool* rowPtr = mask->ValuePtr(x, yBottom); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 const __m128 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(rowPtr[3], rowPtr[2], rowPtr[1], rowPtr[0]), zero4i)); // Conditionally increment counters count4 = _mm_add_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Add values with conditional move const __m128 m = _mm_and_ps(_mm_load_ps(input->ValuePtr(x, yBottom)), conditionMask); sum4 = _mm_add_ps(sum4, _mm_or_ps(m, _mm_andnot_ps(conditionMask, zero4))); } size_t yTop = 0; while (yBottom < height) { // ** Add the 4 sample at the bottom ** // get a ptr const bool* rowPtr = mask->ValuePtr(x, yBottom); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 __m128 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(rowPtr[3], rowPtr[2], rowPtr[1], rowPtr[0]), zero4i)); // Conditionally increment counters count4 = _mm_add_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Add values with conditional move sum4 = _mm_add_ps( sum4, _mm_or_ps(_mm_and_ps(_mm_load_ps(input->ValuePtr(x, yBottom)), conditionMask), _mm_andnot_ps(conditionMask, zero4))); // ** Check sum ** // if sum/count > threshold || sum/count < -threshold const __m128 avg4 = _mm_div_ps(sum4, _mm_cvtepi32_ps(count4)); const unsigned flagConditions = _mm_movemask_ps(_mm_cmpgt_ps(avg4, threshold4Pos)) | _mm_movemask_ps(_mm_cmplt_ps(avg4, threshold4Neg)); // | _mm_movemask_ps(_mm_cmplt_ps(count4, zero4i)); // The assumption is that most of the values are actually not // thresholded, hence, if this is the case, we circumvent the whole loop // at the cost of one extra comparison: if (flagConditions != 0) { union { bool theChars[4]; uint32_t theInt; } outputValues = { {(flagConditions & 1) != 0, (flagConditions & 2) != 0, (flagConditions & 4) != 0, (flagConditions & 8) != 0}}; for (size_t i = 0; i < Length; ++i) { uint32_t* outputPtr = reinterpret_cast(scratch->ValuePtr(x, yTop + i)); *outputPtr |= outputValues.theInt; } } // ** Subtract the sample at the top ** // get a ptr const bool* tRowPtr = mask->ValuePtr(x, yTop); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(tRowPtr[3], tRowPtr[2], tRowPtr[1], tRowPtr[0]), zero4i)); // Conditionally decrement counters count4 = _mm_sub_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Subtract values with conditional move sum4 = _mm_sub_ps( sum4, _mm_or_ps(_mm_and_ps(_mm_load_ps(input->ValuePtr(x, yTop)), conditionMask), _mm_andnot_ps(conditionMask, zero4))); // ** Next... ** ++yTop; ++yBottom; } } } std::swap(*mask, *scratch); } template __attribute__((target("sse"))) void SumThreshold::HorizontalLargeSSE( const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold) { // The idea of the horizontal SSE version is to read four ('y') rows and // process them simultaneously. // Currently, this SSE horizontal version is not significant faster // (less than ~3%) than the // Non-SSE horizontal version. This has probably to do with // rather randomly reading through the set (first (0,0)-(0,3), then // (1,0)-(1,3), etc) this introduces cache misses and/or many smaller reading // requests *scratch = *mask; const size_t width = mask->Width(), height = mask->Height(); const __m128 zero4 = _mm_set1_ps(0.0); const __m128i zero4i = _mm_set1_epi32(0); const __m128i ones4 = _mm_set1_epi32(1); const __m128 threshold4Pos = _mm_set1_ps(threshold); const __m128 threshold4Neg = _mm_set1_ps(-threshold); if (Length <= width) { for (size_t y = 0; y < height; y += 4) { __m128 sum4 = _mm_set1_ps(0.0); __m128i count4 = _mm_set1_epi32(0); size_t xRight; const bool *rFlagPtrA = mask->ValuePtr(0, y + 3), *rFlagPtrB = mask->ValuePtr(0, y + 2), *rFlagPtrC = mask->ValuePtr(0, y + 1), *rFlagPtrD = mask->ValuePtr(0, y); const num_t *rValPtrA = input->ValuePtr(0, y + 3), *rValPtrB = input->ValuePtr(0, y + 2), *rValPtrC = input->ValuePtr(0, y + 1), *rValPtrD = input->ValuePtr(0, y); for (xRight = 0; xRight + 1 < Length; ++xRight) { // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 const __m128 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(*rFlagPtrA, *rFlagPtrB, *rFlagPtrC, *rFlagPtrD), zero4i)); // Conditionally increment counters (nr unflagged samples) count4 = _mm_add_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Load 4 samples const __m128 v = _mm_set_ps(*rValPtrA, *rValPtrB, *rValPtrC, *rValPtrD); // Add values with conditional move sum4 = _mm_add_ps(sum4, _mm_or_ps(_mm_and_ps(v, conditionMask), _mm_andnot_ps(conditionMask, zero4))); ++rFlagPtrA; ++rFlagPtrB; ++rFlagPtrC; ++rFlagPtrD; ++rValPtrA; ++rValPtrB; ++rValPtrC; ++rValPtrD; } size_t xLeft = 0; const bool *lFlagPtrA = mask->ValuePtr(0, y + 3), *lFlagPtrB = mask->ValuePtr(0, y + 2), *lFlagPtrC = mask->ValuePtr(0, y + 1), *lFlagPtrD = mask->ValuePtr(0, y); const num_t *lValPtrA = input->ValuePtr(0, y + 3), *lValPtrB = input->ValuePtr(0, y + 2), *lValPtrC = input->ValuePtr(0, y + 1), *lValPtrD = input->ValuePtr(0, y); while (xRight < width) { // ** Add the sample at the right ** // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 __m128 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(*rFlagPtrA, *rFlagPtrB, *rFlagPtrC, *rFlagPtrD), zero4i)); // Conditionally increment counters count4 = _mm_add_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Load 4 samples __m128 v = _mm_set_ps(*rValPtrA, *rValPtrB, *rValPtrC, *rValPtrD); // Add values with conditional move (sum4 += (v & m) | (m & ~0) ). sum4 = _mm_add_ps(sum4, _mm_or_ps(_mm_and_ps(v, conditionMask), _mm_andnot_ps(conditionMask, zero4))); // ** Check sum ** // if sum/count > threshold || sum/count < -threshold const __m128 count4AsSingle = _mm_cvtepi32_ps(count4); const unsigned flagConditions = _mm_movemask_ps( _mm_cmpgt_ps(_mm_div_ps(sum4, count4AsSingle), threshold4Pos)) | _mm_movemask_ps( _mm_cmplt_ps(_mm_div_ps(sum4, count4AsSingle), threshold4Neg)); if ((flagConditions & 1) != 0) scratch->SetHorizontalValues(xLeft, y, true, Length); if ((flagConditions & 2) != 0) scratch->SetHorizontalValues(xLeft, y + 1, true, Length); if ((flagConditions & 4) != 0) scratch->SetHorizontalValues(xLeft, y + 2, true, Length); if ((flagConditions & 8) != 0) scratch->SetHorizontalValues(xLeft, y + 3, true, Length); // ** Subtract the sample at the left ** // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(*lFlagPtrA, *lFlagPtrB, *lFlagPtrC, *lFlagPtrD), zero4i)); // Conditionally decrement counters count4 = _mm_sub_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Load 4 samples v = _mm_set_ps(*lValPtrA, *lValPtrB, *lValPtrC, *lValPtrD); // Subtract values with conditional move sum4 = _mm_sub_ps(sum4, _mm_or_ps(_mm_and_ps(v, conditionMask), _mm_andnot_ps(conditionMask, zero4))); // ** Next... ** ++xLeft; ++xRight; ++rFlagPtrA; ++rFlagPtrB; ++rFlagPtrC; ++rFlagPtrD; ++lFlagPtrA; ++lFlagPtrB; ++lFlagPtrC; ++lFlagPtrD; ++rValPtrA; ++rValPtrB; ++rValPtrC; ++rValPtrD; ++lValPtrA; ++lValPtrB; ++lValPtrC; ++lValPtrD; } } } std::swap(*mask, *scratch); } template void SumThreshold::VerticalLargeSSE<2>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeSSE<4>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeSSE<8>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeSSE<16>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeSSE<32>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeSSE<64>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeSSE<128>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeSSE<256>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<2>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<4>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<8>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<16>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<32>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<64>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<128>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::HorizontalLargeSSE<256>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); #endif #if defined(__AVX2__) || defined(__x86_64__) #include template __attribute__((target("avx2"))) void SumThreshold::VerticalLargeAVX( const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold) { *scratch = *mask; const size_t width = mask->Width(), height = mask->Height(); const __m256 zero8 = _mm256_set1_ps(0.0); const __m256i zero8i = _mm256_set1_epi32(0); const __m256i ones8 = _mm256_set1_epi32(1); const __m256 threshold8Pos = _mm256_set1_ps(threshold); const __m256 threshold8Neg = _mm256_set1_ps(-threshold); if (Length <= height) { size_t x = 0; for (; x + 4 < width; x += 8) { __m256 sum8 = _mm256_set1_ps(0.0); __m256i count8 = _mm256_set1_epi32(0); size_t yBottom; for (yBottom = 0; yBottom + 1 < Length; ++yBottom) { const bool* rowPtr = mask->ValuePtr(x, yBottom); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 const __m256 conditionMask = _mm256_castsi256_ps(_mm256_cmpeq_epi32( _mm256_set_epi32(rowPtr[7], rowPtr[6], rowPtr[5], rowPtr[4], rowPtr[3], rowPtr[2], rowPtr[1], rowPtr[0]), zero8i)); // Conditionally increment counters count8 = _mm256_add_epi32( count8, _mm256_and_si256(_mm256_castps_si256(conditionMask), ones8)); // Add values with conditional move const __m256 m = _mm256_and_ps( _mm256_load_ps(input->ValuePtr(x, yBottom)), conditionMask); sum8 = _mm256_add_ps( sum8, _mm256_or_ps(m, _mm256_andnot_ps(conditionMask, zero8))); } size_t yTop = 0; while (yBottom < height) { // ** Add the 8 sample at the bottom ** // get a ptr const bool* rowPtr = mask->ValuePtr(x, yBottom); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 __m256 conditionMask = _mm256_castsi256_ps(_mm256_cmpeq_epi32( _mm256_set_epi32(rowPtr[7], rowPtr[6], rowPtr[5], rowPtr[4], rowPtr[3], rowPtr[2], rowPtr[1], rowPtr[0]), zero8i)); // Conditionally increment counters count8 = _mm256_add_epi32( count8, _mm256_and_si256(_mm256_castps_si256(conditionMask), ones8)); // Add values with conditional move sum8 = _mm256_add_ps( sum8, _mm256_or_ps( _mm256_and_ps(_mm256_load_ps(input->ValuePtr(x, yBottom)), conditionMask), _mm256_andnot_ps(conditionMask, zero8))); // ** Check sum ** // if sum/count > threshold || sum/count < -threshold const __m256 avg8 = _mm256_div_ps(sum8, _mm256_cvtepi32_ps(count8)); // float a[8]; // _mm256_storeu_ps(a, avg8); // std::cout << a[0] << '\n'; const int flagConditions = _mm256_movemask_ps(_mm256_cmp_ps(avg8, threshold8Pos, _CMP_GT_OQ)) | _mm256_movemask_ps(_mm256_cmp_ps(avg8, threshold8Neg, _CMP_LT_OQ)); // The assumption is that most of the values are actually not // thresholded, hence, if this is the case, we circumvent the whole loop // at the cost of one extra comparison: if (flagConditions != 0) { // std::cout << "y=" << yTop << ", flagConditions = " << // flagConditions << "\n"; union { bool theChars[8]; uint64_t theInt; } outputValues = { {(flagConditions & 1) != 0, (flagConditions & 2) != 0, (flagConditions & 4) != 0, (flagConditions & 8) != 0, (flagConditions & 16) != 0, (flagConditions & 32) != 0, (flagConditions & 64) != 0, (flagConditions & 128) != 0}}; for (size_t i = 0; i < Length; ++i) { uint64_t* outputPtr = reinterpret_cast(scratch->ValuePtr(x, yTop + i)); *outputPtr |= outputValues.theInt; } } // ** Subtract the sample at the top ** // get a ptr const bool* tRowPtr = mask->ValuePtr(x, yTop); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 conditionMask = _mm256_castsi256_ps(_mm256_cmpeq_epi32( _mm256_set_epi32(tRowPtr[7], tRowPtr[6], tRowPtr[5], tRowPtr[4], tRowPtr[3], tRowPtr[2], tRowPtr[1], tRowPtr[0]), zero8i)); // Conditionally decrement counters count8 = _mm256_sub_epi32( count8, _mm256_and_si256(_mm256_castps_si256(conditionMask), ones8)); // Subtract values with conditional move sum8 = _mm256_sub_ps( sum8, _mm256_or_ps(_mm256_and_ps(_mm256_load_ps(input->ValuePtr(x, yTop)), conditionMask), _mm256_andnot_ps(conditionMask, zero8))); // ** Next... ** ++yTop; ++yBottom; } } // ============================================================================= // Since images are aligned on 4 values and we are stepping with 8 values, // there might be 4 values left. These are done with the 'SSE' algorithm. // (this code is a literal copy of the above SSE algorithm) // ============================================================================= if (x < width) { const __m128i zero4i = _mm_set1_epi32(0); const __m128i ones4 = _mm_set1_epi32(1); const __m128 zero4 = _mm_set1_ps(0.0); const __m128 threshold4Pos = _mm_set1_ps(threshold); const __m128 threshold4Neg = _mm_set1_ps(-threshold); __m128 sum4 = _mm_set1_ps(0.0); __m128i count4 = _mm_set1_epi32(0); size_t yBottom; for (yBottom = 0; yBottom + 1 < Length; ++yBottom) { const bool* rowPtr = mask->ValuePtr(x, yBottom); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 const __m128 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(rowPtr[3], rowPtr[2], rowPtr[1], rowPtr[0]), zero4i)); // Conditionally increment counters count4 = _mm_add_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Add values with conditional move const __m128 m = _mm_and_ps(_mm_load_ps(input->ValuePtr(x, yBottom)), conditionMask); sum4 = _mm_add_ps(sum4, _mm_or_ps(m, _mm_andnot_ps(conditionMask, zero4))); } size_t yTop = 0; while (yBottom < height) { // ** Add the 4 sample at the bottom ** // get a ptr const bool* rowPtr = mask->ValuePtr(x, yBottom); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 __m128 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(rowPtr[3], rowPtr[2], rowPtr[1], rowPtr[0]), zero4i)); // Conditionally increment counters count4 = _mm_add_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Add values with conditional move sum4 = _mm_add_ps( sum4, _mm_or_ps(_mm_and_ps(_mm_load_ps(input->ValuePtr(x, yBottom)), conditionMask), _mm_andnot_ps(conditionMask, zero4))); // ** Check sum ** // if sum/count > threshold || sum/count < -threshold const __m128 avg4 = _mm_div_ps(sum4, _mm_cvtepi32_ps(count4)); const unsigned flagConditions = _mm_movemask_ps(_mm_cmpgt_ps(avg4, threshold4Pos)) | _mm_movemask_ps(_mm_cmplt_ps(avg4, threshold4Neg)); // | _mm_movemask_ps(_mm_cmplt_ps(count4, zero4i)); // The assumption is that most of the values are actually not // thresholded, hence, if this is the case, we circumvent the whole loop // at the cost of one extra comparison: if (flagConditions != 0) { union { bool theChars[4]; unsigned theInt; } outputValues = { {(flagConditions & 1) != 0, (flagConditions & 2) != 0, (flagConditions & 4) != 0, (flagConditions & 8) != 0}}; for (size_t i = 0; i < Length; ++i) { unsigned* outputPtr = reinterpret_cast(scratch->ValuePtr(x, yTop + i)); *outputPtr |= outputValues.theInt; } } // ** Subtract the sample at the top ** // get a ptr const bool* tRowPtr = mask->ValuePtr(x, yTop); // Assign each integer to one bool in the mask // Convert true to 0xFFFFFFFF and false to 0 conditionMask = _mm_castsi128_ps(_mm_cmpeq_epi32( _mm_set_epi32(tRowPtr[3], tRowPtr[2], tRowPtr[1], tRowPtr[0]), zero4i)); // Conditionally decrement counters count4 = _mm_sub_epi32( count4, _mm_and_si128(_mm_castps_si128(conditionMask), ones4)); // Subtract values with conditional move sum4 = _mm_sub_ps( sum4, _mm_or_ps(_mm_and_ps(_mm_load_ps(input->ValuePtr(x, yTop)), conditionMask), _mm_andnot_ps(conditionMask, zero4))); // ** Next... ** ++yTop; ++yBottom; } } } std::swap(*mask, *scratch); } template void SumThreshold::VerticalLargeAVX<2>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeAVX<4>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeAVX<8>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeAVX<16>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeAVX<32>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeAVX<64>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeAVX<128>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template void SumThreshold::VerticalLargeAVX<256>(const Image2D* input, Mask2D* mask, Mask2D* scratch, num_t threshold); template __attribute__((target("avx2"))) void SumThreshold::VerticalAVXDumas( const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold) { if (Length <= mask->Height()) { int* lastFlaggedPos = scratch->lastFlaggedPos.get(); num_t* sum = scratch->sum.get(); int* count = scratch->count.get(); std::fill(lastFlaggedPos, lastFlaggedPos + input->Width(), -1); std::fill(sum, sum + input->Width(), 0); std::fill(count, count + input->Width(), 0); constexpr int vectorWidth = 8; const int parallelizableLength = (int)mask->Width() - (int)mask->Width() % vectorWidth; const __m256 threshold_m256 = _mm256_set1_ps(threshold); const __m256 sign_mask_m256 = _mm256_xor_ps( _mm256_set1_ps(-0.0f), _mm256_castsi256_ps(_mm256_set1_epi32(-1))); // Truncates dwords to bytes for each 256 bit const __m256i shuffle_1f126i_cvtepi32_epu8_m256i = _mm256_set_epi8( '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\x0c', '\x08', '\x04', '\x00', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\x0c', '\x08', '\x04', '\x00'); const __m128i first_dword_true_m128i = _mm_set_epi8( '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x01', '\x01', '\x01', '\x01', '\x01', '\x01', '\x01'); constexpr int64_t true_m32i = 0x01010101L; // Set sum and count for initial window position for (int maxRow = 0; maxRow < (int)Length - 1; ++maxRow) { for (int iCol = 0; iCol < parallelizableLength; iCol += vectorWidth) { /* * Implements: * sum(iCol) += input(maxRow, iCol) * !mask(maxRow, iCol); * count(iCol) += !mask(maxRow, iCol); */ // Load sum vector __m256 sum_m256 = _mm256_load_ps(&sum[iCol]); // Load count vector __m256i count_m256i = _mm256_load_si256((__m256i*)&count[iCol]); // Load input vector const __m256 input_m256 = _mm256_load_ps(input->ValuePtr(iCol, maxRow)); // Load mask vector const __m64 mask_m64 = *(__m64*)mask->ValuePtr(iCol, maxRow); const __m128i mask_m128i = _mm_set_epi64(_mm_setzero_si64(), mask_m64); const __m128i imask_m128i = _mm_xor_si128(first_dword_true_m128i, mask_m128i); // Invert mask vector const __m256i imask_m256i = _mm256_cvtepu8_epi32(imask_m128i); const __m256 imask_m256 = _mm256_cvtepi32_ps(imask_m256i); // Sum += input * !mask const __m256 tmp_m256 = _mm256_mul_ps(imask_m256, input_m256); sum_m256 = _mm256_add_ps(sum_m256, tmp_m256); // Store sum _mm256_store_ps(&sum[iCol], sum_m256); // count += !mask count_m256i = _mm256_add_epi32(count_m256i, imask_m256i); // Store count _mm256_store_si256((__m256i*)&count[iCol], count_m256i); } for (int iCol = parallelizableLength; iCol < (int)mask->Width(); ++iCol) { sum[iCol] += input->Value(iCol, maxRow) * !mask->Value(iCol, maxRow); count[iCol] += !mask->Value(iCol, maxRow); } } // Iterate through positions for (int maxRow = (int)Length - 1; maxRow < (int)mask->Height(); ++maxRow) { const int minRow = maxRow - (int)Length + 1; // load maxRow vector const __m256i maxRow_m256i = _mm256_set1_epi32(maxRow); // Load 'minRow take 1' vector const __m256i minRowt1_m256i = _mm256_set1_epi32(minRow - 1); for (int iCol = 0; iCol < parallelizableLength; iCol += vectorWidth) { // Load sum vector __m256 sum_m256 = _mm256_load_ps(&sum[iCol]); // Load count vector __m256i count_m256i = _mm256_load_si256((__m256i*)&count[iCol]); /* * Implements: * sum(iCol) += input(maxRow, iCol) * !mask(maxRow, iCol); * count(iCol) += !mask(maxRow, iCol); */ { // Load input vector const __m256 input_m256 = _mm256_load_ps(input->ValuePtr(iCol, maxRow)); // Load mask vector const __m64 mask_m64 = *(__m64*)mask->ValuePtr(iCol, maxRow); const __m128i mask_m128i = _mm_set_epi64(_mm_setzero_si64(), mask_m64); const __m128i imask_m128i = _mm_xor_si128( first_dword_true_m128i, mask_m128i); // Invert mask vector const __m256i imask_m256i = _mm256_cvtepu8_epi32(imask_m128i); const __m256 imask_m256 = _mm256_cvtepi32_ps(imask_m256i); // Sum += input * !mask const __m256 tmp_m256 = _mm256_mul_ps(imask_m256, input_m256); sum_m256 = _mm256_add_ps(sum_m256, tmp_m256); // count += !mask count_m256i = _mm256_add_epi32(count_m256i, imask_m256i); } /* * Implements: * if (abs(sum(iCol)) > count(iCol) * threshold) * lastFlaggedPos(iCol) = maxRow; */ { // cast count const __m256 count_m256 = _mm256_cvtepi32_ps(count_m256i); // tmp1 = threshold * count const __m256 tmp1_m256 = _mm256_mul_ps(threshold_m256, count_m256); // tmp2 = abs(sum) const __m256 tmp2_m256 = _mm256_and_ps(sum_m256, sign_mask_m256); // tmp3 = tmp2 > tmp1 const __m256 tmp3_m256 = _mm256_cmp_ps(tmp2_m256, tmp1_m256, _CMP_GT_OQ); // cast tmp3 const __m256i tmp3_m256i = _mm256_castps_si256(tmp3_m256); // store lastFlaggedPos _mm256_maskstore_epi32(&lastFlaggedPos[iCol], tmp3_m256i, maxRow_m256i); } /* * Implements: * sum(iCol) -= input(minRow, iCol) * !mask(minRow, iCol); * count(iCol) -= !mask(minRow, iCol); */ { // Load input vector const __m256 input_m256 = _mm256_load_ps(input->ValuePtr(iCol, minRow)); // Load mask vector const __m64 mask_m64 = *(__m64*)mask->ValuePtr(iCol, minRow); const __m128i mask_m128i = _mm_set_epi64(_mm_setzero_si64(), mask_m64); const __m128i imask_m128i = _mm_xor_si128( first_dword_true_m128i, mask_m128i); // Invert mask vector const __m256i imask_m256i = _mm256_cvtepu8_epi32(imask_m128i); const __m256 imask_m256 = _mm256_cvtepi32_ps(imask_m256i); // Sum -= input * !mask const __m256 tmp_m256 = _mm256_mul_ps(imask_m256, input_m256); sum_m256 = _mm256_sub_ps(sum_m256, tmp_m256); // count -= !mask count_m256i = _mm256_sub_epi32(count_m256i, imask_m256i); } // Store sum _mm256_store_ps(&sum[iCol], sum_m256); // Store count _mm256_store_si256((__m256i*)&count[iCol], count_m256i); /* * Implements: * mask(minRow, iCol) |= (lastFlaggedPos(iCol) > minRow - 1); */ { // Load lastFlaggedPos vector const __m256i lastFlaggedPos_m256i = _mm256_load_si256((__m256i*)&lastFlaggedPos[iCol]); __m256i tmp_m256i = _mm256_cmpgt_epi32(lastFlaggedPos_m256i, minRowt1_m256i); tmp_m256i = _mm256_shuffle_epi8(tmp_m256i, shuffle_1f126i_cvtepi32_epu8_m256i); ((int32_t*)mask->ValuePtr(iCol, minRow))[0] |= true_m32i & _mm256_extract_epi32(tmp_m256i, 0); ((int32_t*)mask->ValuePtr(iCol, minRow))[1] |= true_m32i & _mm256_extract_epi32(tmp_m256i, 4); } } for (int iCol = parallelizableLength; iCol < (int)mask->Width(); ++iCol) { const int minRow = maxRow - (int)Length + 1; // add the sample at the right sum[iCol] += input->Value(iCol, maxRow) * !mask->Value(iCol, maxRow); count[iCol] += !mask->Value(iCol, maxRow); // Check current pos lastFlaggedPos[iCol] += int(abs(sum[iCol]) > count[iCol] * threshold) * (maxRow - lastFlaggedPos[iCol]); // subtract the sample past the left sum[iCol] -= input->Value(iCol, minRow) * !mask->Value(iCol, minRow); count[iCol] -= !mask->Value(iCol, minRow); // Flag left edge *mask->ValuePtr(iCol, minRow) |= (lastFlaggedPos[iCol] >= minRow); } } // Flag last window for (int minRow = (int)mask->Height() - (int)Length + 1; minRow < (int)mask->Height(); ++minRow) { const __m256i minRowt1_m256i = _mm256_set1_epi32(minRow - 1); for (int iCol = 0; iCol < parallelizableLength; iCol += 8) { /* * Implements: * mask(minRow, iCol) |= (lastFlaggedPos(iCol) > minRow - 1); */ const __m256i lastFlaggedPos_m256i = _mm256_load_si256((__m256i*)&lastFlaggedPos[iCol]); const __m256i tmp1_m256i = _mm256_cmpgt_epi32(lastFlaggedPos_m256i, minRowt1_m256i); const __m256i tmp2_m256i = _mm256_shuffle_epi8(tmp1_m256i, shuffle_1f126i_cvtepi32_epu8_m256i); ((int32_t*)mask->ValuePtr(iCol, minRow))[0] |= true_m32i & _mm256_extract_epi32(tmp2_m256i, 0); ((int32_t*)mask->ValuePtr(iCol, minRow))[1] |= true_m32i & _mm256_extract_epi32(tmp2_m256i, 4); } for (int iCol = parallelizableLength; iCol < (int)mask->Width(); ++iCol) { *mask->ValuePtr(iCol, minRow) |= (lastFlaggedPos[iCol] > minRow - 1); } } } } template __attribute__((target("avx2"))) void SumThreshold::HorizontalAVXDumas( const Image2D* input, Mask2D* mask, num_t threshold) { if (Length <= mask->Width()) { #ifndef NDEBUG if (input->Stride() * 7 * sizeof(float) > 0xFFFFFFFF) { throw std::runtime_error("Array too big for gather intrinsic"); } #endif const __m256i gather_input_indexes_m256i = _mm256_set_epi32(input->Stride() * 7 * sizeof(float), input->Stride() * 6 * sizeof(float), input->Stride() * 5 * sizeof(float), input->Stride() * 4 * sizeof(float), input->Stride() * 3 * sizeof(float), input->Stride() * 2 * sizeof(float), input->Stride() * 1 * sizeof(float), input->Stride() * 0 * sizeof(float)); const size_t stride = mask->Stride(); const __m256i gather_mask_indexes_m256i = _mm256_set_epi32( (stride * 7 - 3) * sizeof(bool), (stride * 6 - 2) * sizeof(bool), (stride * 5 - 1) * sizeof(bool), stride * 4 * sizeof(bool), stride * 3 * sizeof(bool), stride * 2 * sizeof(bool), stride * 1 * sizeof(bool), stride * 0 * sizeof(bool)); const __m256i epi32_lo_set_m256i = _mm256_set_epi32( 0xFF000000, 0xFF0000, 0xFF00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); const __m256i epi32_1_m256i = _mm256_set_epi32(1, 1, 1, 1, 1, 1, 1, 1); constexpr int vectorWidth = 8; const __m256 sign_mask_m256 = _mm256_xor_ps( _mm256_set1_ps(-0.0f), _mm256_castsi256_ps(_mm256_set1_epi32(-1))); const __m256 threshold_m256 = _mm256_set1_ps(threshold); for (int iRow = 0; iRow < (int)mask->Height() - (int)mask->Height() % vectorWidth; iRow += vectorWidth) { __m256 sum_m256; __m256i count_m256i; __m256i lastFlaggedPos_m256i = _mm256_set1_epi32(-1); sum_m256 = _mm256_setzero_ps(); count_m256i = _mm256_setzero_si256(); // Set sum and count for initial window position for (int maxCol = 0; maxCol < (int)Length - 1; ++maxCol) { /* * Implements: * sum += input(iRow, maxCol) * !mask(iRow, maxCol); * count += !mask(iRow, maxCol); */ const __m256 input_m256 = _mm256_i32gather_ps( input->ValuePtr(maxCol, iRow), gather_input_indexes_m256i, 1); const __m256i mask_m256i = _mm256_i32gather_epi32( (int*)mask->ValuePtr(maxCol, iRow), gather_mask_indexes_m256i, 1); const __m256i tmp1_m256i = _mm256_and_si256(mask_m256i, epi32_lo_set_m256i); const __m256i tmp2_m256i = _mm256_cmpeq_epi32(tmp1_m256i, _mm256_setzero_si256()); const __m256 tmp3_m256 = _mm256_castsi256_ps(tmp2_m256i); const __m256 tmp4_m256 = _mm256_and_ps(tmp3_m256, input_m256); sum_m256 = _mm256_add_ps(sum_m256, tmp4_m256); const __m256i tmp5_m256i = _mm256_and_si256(tmp2_m256i, epi32_1_m256i); count_m256i = _mm256_add_epi32(count_m256i, tmp5_m256i); } // Iterate through positions for (int maxCol = (int)Length - 1; maxCol < (int)mask->Width(); ++maxCol) { const int minCol = maxCol - (int)Length + 1; /* * Implements: * sum += input(iRow, maxCol) * !mask(iRow, maxCol); * count += !mask(iRow,maxCol); */ { const __m256 input_m256 = _mm256_i32gather_ps( input->ValuePtr(maxCol, iRow), gather_input_indexes_m256i, 1); const __m256i mask_m256i = _mm256_i32gather_epi32( (int*)mask->ValuePtr(maxCol, iRow), gather_mask_indexes_m256i, 1); const __m256i tmp1_m256i = _mm256_and_si256(mask_m256i, epi32_lo_set_m256i); const __m256i tmp2_m256i = _mm256_cmpeq_epi32(tmp1_m256i, _mm256_setzero_si256()); const __m256 tmp3_m256 = _mm256_castsi256_ps(tmp2_m256i); const __m256 tmp4_m256 = _mm256_and_ps(tmp3_m256, input_m256); sum_m256 = _mm256_add_ps(sum_m256, tmp4_m256); const __m256i tmp5_m256i = _mm256_and_si256(tmp2_m256i, epi32_1_m256i); count_m256i = _mm256_add_epi32(count_m256i, tmp5_m256i); } /* * Implements: * if (abs(sum) > count * threshold) * lastFlaggedPos = maxCol; */ { // cast count const __m256 count_m256 = _mm256_cvtepi32_ps(count_m256i); // tmp1 = threshold * count const __m256 tmp1_m256 = _mm256_mul_ps(threshold_m256, count_m256); // tmp2 = abs(sum) const __m256 tmp2_m256 = _mm256_and_ps(sum_m256, sign_mask_m256); // tmp3 = tmp2 > tmp1 const __m256 tmp3_m256 = _mm256_cmp_ps(tmp2_m256, tmp1_m256, _CMP_GT_OQ); // cast tmp3 const __m256i tmp3_m256i = _mm256_castps_si256(tmp3_m256); // get maxCol vector` const __m256i maxCol_m256i = _mm256_set1_epi32(maxCol); // store lastFlaggedPos lastFlaggedPos_m256i = _mm256_blendv_epi8(lastFlaggedPos_m256i, maxCol_m256i, tmp3_m256i); } /* * Implements: * sum -= input(iRow, minCol) * !mask(iRow, minCol); * count -= !mask(iRow, minCol); */ { const __m256 input_m256 = _mm256_i32gather_ps( input->ValuePtr(minCol, iRow), gather_input_indexes_m256i, 1); const __m256i mask_m256i = _mm256_i32gather_epi32( (int*)mask->ValuePtr(minCol, iRow), gather_mask_indexes_m256i, 1); const __m256i tmp1_m256i = _mm256_and_si256(mask_m256i, epi32_lo_set_m256i); const __m256i tmp2_m256i = _mm256_cmpeq_epi32(tmp1_m256i, _mm256_setzero_si256()); const __m256 tmp3_m256 = _mm256_castsi256_ps(tmp2_m256i); const __m256 tmp4_m256 = _mm256_and_ps(tmp3_m256, input_m256); sum_m256 = _mm256_sub_ps(sum_m256, tmp4_m256); const __m256i tmp5_m256i = _mm256_and_si256(tmp2_m256i, epi32_1_m256i); count_m256i = _mm256_sub_epi32(count_m256i, tmp5_m256i); } /* * Implements: * mask(iRow, minCol) |= (lastFlaggedPos > minCol - 1); */ { const __m256i minColt1_m256i = _mm256_set1_epi32(minCol - 1); const __m256i masked_m256i = _mm256_cmpgt_epi32(lastFlaggedPos_m256i, minColt1_m256i); const __m256i boolMask_m256i = _mm256_and_si256(masked_m256i, epi32_1_m256i); // 5 asm instructions/store with regular bool cast (extract, mov, // test, setne, or) 1 asm instructions/store with reinterpret hack uint8_t* maskPtr = (uint8_t*)mask->ValuePtr(minCol, iRow); maskPtr[mask->Stride() * 0] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 0)); maskPtr[mask->Stride() * 1] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 1)); maskPtr[mask->Stride() * 2] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 2)); maskPtr[mask->Stride() * 3] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 3)); maskPtr[mask->Stride() * 4] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 4)); maskPtr[mask->Stride() * 5] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 5)); maskPtr[mask->Stride() * 6] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 6)); maskPtr[mask->Stride() * 7] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 7)); } } // Flag last window for (int minCol = (int)mask->Width() - Length + 1; minCol < (int)mask->Width(); ++minCol) { /* * Implements: * mask(iRow, minCol) |= (lastFlaggedPos > minCol - 1); */ const __m256i minColt1_m256i = _mm256_set1_epi32(minCol - 1); const __m256i masked_m256i = _mm256_cmpgt_epi32(lastFlaggedPos_m256i, minColt1_m256i); const __m256i boolMask_m256i = _mm256_and_si256(masked_m256i, epi32_1_m256i); uint8_t* maskPtr = (uint8_t*)mask->ValuePtr(minCol, iRow); maskPtr[mask->Stride() * 0] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 0)); maskPtr[mask->Stride() * 1] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 1)); maskPtr[mask->Stride() * 2] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 2)); maskPtr[mask->Stride() * 3] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 3)); maskPtr[mask->Stride() * 4] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 4)); maskPtr[mask->Stride() * 5] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 5)); maskPtr[mask->Stride() * 6] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 6)); maskPtr[mask->Stride() * 7] |= static_cast(_mm256_extract_epi32(boolMask_m256i, 7)); } } // non-vectorised remainder for (int iRow = (int)mask->Height() - (int)mask->Height() % (int)vectorWidth; iRow < (int)mask->Height(); ++iRow) { int lastFlaggedPos = -1; num_t sum = 0; int count = 0; // Do prefix sum and count for (int maxCol = 0; maxCol < (int)Length - 1; ++maxCol) { sum += input->Value(maxCol, iRow) * !mask->Value(maxCol, iRow); count += !mask->Value(maxCol, iRow); } // Iterate through positions for (int maxCol = (int)Length - 1; maxCol < (int)mask->Width(); ++maxCol) { const int minCol = maxCol - Length + 1; // add the sample at the right sum += input->Value(maxCol, iRow) * !mask->Value(maxCol, iRow); count += !mask->Value(maxCol, iRow); // Check current pos lastFlaggedPos += int(abs(sum) > count * threshold) * (maxCol - lastFlaggedPos); // subtract the sample at the left sum -= input->Value(minCol, iRow) * !mask->Value(minCol, iRow); count -= !mask->Value(minCol, iRow); // Flag left edge *mask->ValuePtr(minCol, iRow) |= (lastFlaggedPos >= minCol); } // Flag last window for (int minCol = (int)mask->Width() - (int)Length + 1; minCol < (int)mask->Width(); ++minCol) { *mask->ValuePtr(minCol, iRow) |= (lastFlaggedPos >= minCol); } } } } template void SumThreshold::VerticalAVXDumas<2>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::VerticalAVXDumas<4>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::VerticalAVXDumas<8>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::VerticalAVXDumas<16>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::VerticalAVXDumas<32>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::VerticalAVXDumas<64>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::VerticalAVXDumas<128>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::VerticalAVXDumas<256>(const Image2D* input, Mask2D* mask, VerticalScratch* scratch, num_t threshold); template void SumThreshold::HorizontalAVXDumas<2>(const Image2D* input, Mask2D* mask, num_t threshold); template void SumThreshold::HorizontalAVXDumas<4>(const Image2D* input, Mask2D* mask, num_t threshold); template void SumThreshold::HorizontalAVXDumas<8>(const Image2D* input, Mask2D* mask, num_t threshold); template void SumThreshold::HorizontalAVXDumas<16>(const Image2D* input, Mask2D* mask, num_t threshold); template void SumThreshold::HorizontalAVXDumas<32>(const Image2D* input, Mask2D* mask, num_t threshold); template void SumThreshold::HorizontalAVXDumas<64>(const Image2D* input, Mask2D* mask, num_t threshold); template void SumThreshold::HorizontalAVXDumas<128>(const Image2D* input, Mask2D* mask, num_t threshold); template void SumThreshold::HorizontalAVXDumas<256>(const Image2D* input, Mask2D* mask, num_t threshold); #endif // defined(__AVX2__) || defined(__x86_64__) } // namespace algorithms aoflagger-v3.4.0/algorithms/sumthresholdmissing.h0000644000175000017500000000421614507760372020774 0ustar olesoles#ifndef SUMTHRESHOLD_MISSING_H #define SUMTHRESHOLD_MISSING_H #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "sumthreshold.h" #include namespace algorithms { class SumThresholdMissing { public: struct VerticalCache { std::vector positions; Image2D validImage; Mask2D validMask; SumThreshold::VerticalScratch scratch; }; static void Horizontal(const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold) { horizontal(input, mask, missing, scratch, length, threshold); } static void VerticalReference(const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold); static void InitializeVertical(VerticalCache& cache, const Image2D& input, const Mask2D& missing); static void Vertical(const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold) { // VerticalReference(input, mask, missing, scratch, length, threshold); // VerticalStacked(cache, input, mask, missing, scratch, length, threshold); VerticalConsecutive(input, mask, missing, scratch, length, threshold); } static void VerticalConsecutive(const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold); static void VerticalStacked(VerticalCache& cache, const Image2D& input, Mask2D& mask, const Mask2D& missing, Mask2D& scratch, size_t length, num_t threshold); private: template static void horizontal(const ImageLike& input, MaskLike& mask, const CMaskLike& missing, MaskLike& scratch, size_t length, num_t threshold); SumThresholdMissing() = delete; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/morphology.cpp0000644000175000017500000004011314507760372017407 0ustar olesoles#include "morphology.h" #include "morphologicalflagger.h" #include "siroperator.h" #include "../util/logger.h" #include #include namespace algorithms { size_t Morphology::BROADBAND_SEGMENT = 1, Morphology::LINE_SEGMENT = 2, Morphology::BLOB_SEGMENT = 3; void Morphology::SegmentByMaxLength(const Mask2D* mask, SegmentedImagePtr output) { int** lengthWidthValues = new int*[mask->Height()]; for (size_t y = 0; y < mask->Height(); ++y) lengthWidthValues[y] = new int[mask->Width()]; calculateOpenings(mask, lengthWidthValues); for (size_t y = 0; y < mask->Height(); ++y) { for (size_t x = 0; x < mask->Width(); ++x) output->SetValue(x, y, 0); } for (size_t y = 0; y < mask->Height(); ++y) { for (size_t x = 0; x < mask->Width(); ++x) { if (mask->Value(x, y) && output->Value(x, y) == 0) { floodFill(mask, output, lengthWidthValues, x, y, output->NewSegmentValue()); } } } for (size_t y = 0; y < mask->Height(); ++y) delete[] lengthWidthValues[y]; delete[] lengthWidthValues; } void Morphology::SegmentByLengthRatio(const Mask2D* mask, SegmentedImagePtr output) { const Mask2DPtr maskCopy(new Mask2D(*mask)); Mask2DPtr matrices[3]; for (size_t i = 0; i < 3; ++i) matrices[i] = Mask2D::CreateUnsetMaskPtr(mask->Width(), mask->Height()); int **hCounts = new int *[mask->Height()], **vCounts = new int *[mask->Height()]; for (size_t y = 0; y < mask->Height(); ++y) { hCounts[y] = new int[mask->Width()]; vCounts[y] = new int[mask->Width()]; } // Calculate convolved counts calculateHorizontalCounts(maskCopy.get(), hCounts); calculateVerticalCounts(maskCopy.get(), vCounts); calculateOpenings(maskCopy.get(), matrices, hCounts, vCounts); for (size_t y = 0; y < mask->Height(); ++y) { for (size_t x = 0; x < mask->Width(); ++x) output->SetValue(x, y, 0); } MorphologicalFlagger::DilateFlags(matrices[0].get(), _hLineEnlarging, 0); MorphologicalFlagger::DilateFlags(matrices[2].get(), 0, _vLineEnlarging); SIROperator::OperateHorizontally(*matrices[0], _hDensityEnlargeRatio); SIROperator::OperateVertically(*matrices[2], _vDensityEnlargeRatio); // Calculate counts again with new matrices calculateHorizontalCounts(matrices[0].get(), hCounts); calculateVerticalCounts(matrices[2].get(), vCounts); for (size_t z = 0; z < 3; z += 2) { for (size_t y = 0; y < mask->Height(); ++y) { for (size_t x = 0; x < mask->Width(); ++x) { if (matrices[z]->Value(x, y) && output->Value(x, y) == 0) { floodFill(mask, output, matrices, x, y, z, output->NewSegmentValue(), hCounts, vCounts); } } } } for (size_t y = 0; y < mask->Height(); ++y) { delete[] hCounts[y]; delete[] vCounts[y]; } delete[] hCounts; delete[] vCounts; } void Morphology::calculateHorizontalCounts(const Mask2D* mask, int** values) { for (size_t y = 0; y < mask->Height(); ++y) { size_t length = 0; for (size_t x = 0; x < mask->Width(); ++x) { if (mask->Value(x, y)) { ++length; } else if (length > 0) { for (size_t i = x - length; i < x; ++i) { values[y][i] = length; } length = 0; values[y][x] = 0; } else { values[y][x] = 0; } } for (size_t i = mask->Width() - length; i < mask->Width(); ++i) { values[y][i] = length; } } } void Morphology::calculateVerticalCounts(const Mask2D* mask, int** values) { for (size_t x = 0; x < mask->Width(); ++x) { size_t length = 0; for (size_t y = 0; y < mask->Height(); ++y) { if (mask->Value(x, y)) { ++length; } else if (length > 0) { for (size_t i = y - length; i < y; ++i) { values[i][x] = length; } length = 0; values[y][x] = 0; } else { values[y][x] = 0; } } for (size_t i = mask->Height() - length; i < mask->Height(); ++i) { values[i][x] = length; } } } void Morphology::calculateOpenings(const Mask2D* mask, int** values) { for (size_t y = 0; y < mask->Height(); ++y) { size_t length = 0; for (size_t x = 0; x < mask->Width(); ++x) { if (mask->Value(x, y)) { ++length; } else if (length > 0) { for (size_t i = x - length; i < x; ++i) { values[y][i] = length; } length = 0; values[y][x] = 0; } else { values[y][x] = 0; } } if (length > 0) { for (size_t i = mask->Width() - length; i < mask->Width(); ++i) { values[y][i] = length; } } } for (size_t x = 0; x < mask->Width(); ++x) { size_t length = 0; for (size_t y = 0; y < mask->Height(); ++y) { if (mask->Value(x, y)) { ++length; } else if (length > 0) { for (size_t i = y - length; i < y; ++i) { if (values[i][x] < (int)length) values[i][x] = -(int)length; } length = 0; } } if (length > 0) { for (size_t i = mask->Height() - length; i < mask->Height(); ++i) { if (values[i][x] < (int)length) values[i][x] = -(int)length; } } } } void Morphology::calculateOpenings(const Mask2D* mask, Mask2DPtr* values, int** hCounts, int** vCounts) { // const int zThreshold = 5; for (size_t y = 0; y < mask->Height(); ++y) { for (size_t x = 0; x < mask->Width(); ++x) { const bool v = mask->Value(x, y); values[0]->SetValue(x, y, v && (hCounts[y][x] > vCounts[y][x])); values[1]->SetValue(x, y, v && false); // values[1]->SetValue(x, y, v && (abs(hCounts[y][x] - vCounts[y][x]) < // zThreshold)); values[2]->SetValue(x, y, v && (hCounts[y][x] <= vCounts[y][x])); } } } struct MorphologyPoint2D { size_t x, y; }; struct MorphologyPoint3D { size_t x, y, z; }; void Morphology::floodFill(const Mask2D* mask, SegmentedImagePtr output, const int* const* lengthWidthValues, size_t x, size_t y, size_t value) { std::stack points; MorphologyPoint2D startPoint; startPoint.x = x; startPoint.y = y; points.push(startPoint); do { const MorphologyPoint2D p = points.top(); points.pop(); output->SetValue(p.x, p.y, value); const int z = lengthWidthValues[p.y][p.x]; if (p.x > 0 && output->Value(p.x - 1, p.y) == 0 && mask->Value(p.x - 1, p.y)) { const int zl = lengthWidthValues[p.y][p.x - 1]; if ((zl > 0 && z > 0) || (zl < 0 && z < 0)) { MorphologyPoint2D newP; newP.x = p.x - 1; newP.y = p.y; points.push(newP); } } if (p.x < mask->Width() - 1 && output->Value(p.x + 1, p.y) == 0 && mask->Value(p.x + 1, p.y)) { const int zr = lengthWidthValues[p.y][p.x + 1]; if ((zr > 0 && z > 0) || (zr < 0 && z < 0)) { MorphologyPoint2D newP; newP.x = p.x + 1; newP.y = p.y; points.push(newP); } } if (p.y > 0 && output->Value(p.x, p.y - 1) == 0 && mask->Value(p.x, p.y - 1)) { const int zt = lengthWidthValues[p.y - 1][p.x]; if ((zt > 0 && z > 0) || (zt < 0 && z < 0)) { MorphologyPoint2D newP; newP.x = p.x; newP.y = p.y - 1; points.push(newP); } } if (p.y < mask->Height() - 1 && output->Value(p.x, p.y + 1) == 0 && mask->Value(p.x, p.y + 1)) { const int zb = lengthWidthValues[p.y + 1][p.x]; if ((zb > 0 && z > 0) || (zb < 0 && z < 0)) { MorphologyPoint2D newP; newP.x = p.x; newP.y = p.y + 1; points.push(newP); } } } while (points.size() != 0); } void Morphology::floodFill(const Mask2D* mask, SegmentedImagePtr output, Mask2DPtr* matrices, size_t x, size_t y, size_t z, size_t value, int** hCounts, int** vCounts) { std::stack points; MorphologyPoint3D startPoint; startPoint.x = x; startPoint.y = y; startPoint.z = z; points.push(startPoint); do { const MorphologyPoint3D p = points.top(); points.pop(); if (mask->Value(p.x, p.y)) { if (output->Value(p.x, p.y) == 0) { output->SetValue(p.x, p.y, value); } else { // now we need to decide whether to change this sample to the new // segment or not if (hCounts[p.y][p.x] < vCounts[p.y][p.x] && p.z == 2) output->SetValue(p.x, p.y, value); } } const Mask2DPtr matrix = matrices[p.z]; matrix->SetValue(p.x, p.y, false); if ((p.z == 0 || p.z == 2) && matrices[1]->Value(p.x, p.y)) { MorphologyPoint3D newP; newP.x = p.x; newP.y = p.y; newP.z = 1; points.push(newP); } if (p.x > 0 && matrix->Value(p.x - 1, p.y)) { MorphologyPoint3D newP; newP.x = p.x - 1; newP.y = p.y; newP.z = p.z; points.push(newP); } if (p.x < mask->Width() - 1 && matrix->Value(p.x + 1, p.y)) { MorphologyPoint3D newP; newP.x = p.x + 1; newP.y = p.y; newP.z = p.z; points.push(newP); } if (p.y > 0 && matrix->Value(p.x, p.y - 1)) { MorphologyPoint3D newP; newP.x = p.x; newP.y = p.y - 1; newP.z = p.z; points.push(newP); } if (p.y < mask->Height() - 1 && matrix->Value(p.x, p.y + 1)) { MorphologyPoint3D newP; newP.x = p.x; newP.y = p.y + 1; newP.z = p.z; points.push(newP); } } while (points.size() != 0); } void Morphology::Cluster(SegmentedImagePtr segmentedImage) { std::map segments = createSegmentMap(segmentedImage); Logger::Debug << "Segments before clustering: " << segments.size(); for (std::map::iterator i = segments.begin(); i != segments.end(); ++i) { SegmentInfo& info1 = i->second; for (std::map::iterator j = segments.begin(); j != segments.end(); ++j) { if (info1.segment != j->second.segment && !(i->second.mark) && !(j->second.mark)) { SegmentInfo& info2 = j->second; const size_t hDist = info1.HorizontalDistance(info2); const size_t vDist = info1.VerticalDistance(info2); // The MERGE criteria bool cluster = false; // int minDist = hDist > vDist ? vDist : hDist; const int maxDist = hDist > vDist ? hDist : vDist; // int maxCount = info1.count > info2.count ? info1.count : info2.count; const int minCount = info1.count > info2.count ? info2.count : info1.count; const int maxWidth = info1.width > info2.width ? info1.width : info2.width; const int maxHeight = info1.height > info2.height ? info1.height : info2.height; const int minHeight = info1.height > info2.height ? info2.height : info1.height; // int lDist = abs((int) info1.left - (int) info2.left); // int rDist = abs((int) info1.right - (int) info2.right); // int tDist = abs((int) info1.top - (int) info2.top); // int bDist = abs((int) info1.bottom - (int) info2.bottom); const int widthDist = abs((int)info1.width - (int)info2.width); const int heightDist = abs((int)info1.height - (int)info2.height); // double x1Mean = (double) info1.xTotal / info1.count; // double x2Mean = (double) info2.xTotal / info2.count; // double xMeanDist = fabs(x1Mean - x2Mean); const double y1Mean = (double)info1.yTotal / info1.count; const double y2Mean = (double)info2.yTotal / info2.count; const double yMeanDist = fabs(y1Mean - y2Mean); bool remove1 = false, remove2 = false; // Cluster large segments with very small segments that are close // together (probably noise from the continuous transmitter) bool noiseH1 = maxDist <= 1 && info2.count > (info1.count * 20) && info2.width > info1.width * 8 && info1.height < 16 && info1.width < segmentedImage->Width() / 10, noiseH2 = maxDist <= 1 && info1.count > (info2.count * 20) && info1.width > info2.width * 8 && info2.height < 16 && info2.width < segmentedImage->Width() / 10; cluster = cluster || noiseH1 || noiseH2; remove1 = remove1 || noiseH1; remove2 = remove2 || noiseH2; bool noiseV1 = maxDist <= 1 && info2.count > (info1.count * 20) && info2.height > info1.height * 8 && info1.height < 16 && info1.width < segmentedImage->Width() / 10, noiseV2 = maxDist <= 1 && info1.count > (info2.count * 20) && info1.height > info2.height * 8 && info2.height < 16 && info2.width < segmentedImage->Width() / 10; cluster = cluster || noiseV1 || noiseV2; remove1 = remove1 || noiseV1; remove2 = remove2 || noiseV2; // Cluster same-shaped segments that are in the same channels cluster = cluster || (vDist == 0 && yMeanDist * 8 <= (maxHeight + minHeight) && widthDist <= (maxWidth / 4 + 2) && heightDist <= (maxHeight / 4 + 2) && maxDist < minCount * 32); if (cluster) { const size_t oldSegment = info2.segment; segmentedImage->MergeSegments(info1.segment, oldSegment); for (std::map::iterator i = segments.begin(); i != segments.end(); ++i) { SegmentInfo& info = i->second; if (info.segment == oldSegment) info.segment = info1.segment; } } if (remove1) info1.mark = true; if (remove2) info2.mark = true; } } } } std::map Morphology::createSegmentMap( SegmentedImageCPtr segmentedImage) const { std::map segments; for (size_t y = 0; y < segmentedImage->Height(); ++y) { for (size_t x = 0; x < segmentedImage->Width(); ++x) { const size_t segmentValue = segmentedImage->Value(x, y); if (segmentValue != 0) { if (segments.count(segmentValue) == 0) { SegmentInfo segment; segment.segment = segmentValue; segment.left = x; segment.right = x + 1; segment.top = y; segment.bottom = y + 1; segment.AddPoint(x, y); segments.insert( std::map::value_type(segmentValue, segment)); } else { SegmentInfo& segment = segments.find(segmentValue)->second; segment.AddPoint(x, y); } } } } for (std::map::iterator i = segments.begin(); i != segments.end(); ++i) { SegmentInfo& info = i->second; info.width = info.right - info.left; info.height = info.bottom - info.top; } return segments; } void Morphology::RemoveSmallSegments(SegmentedImagePtr segmentedImage, size_t thresholdLevel) { std::map segments = createSegmentMap(segmentedImage); size_t removedSegments = 0; for (std::map::iterator i = segments.begin(); i != segments.end(); ++i) { const SegmentInfo& segment = i->second; if (segment.count <= thresholdLevel) { ++removedSegments; segmentedImage->RemoveSegment(segment.segment, segment.left, segment.right, segment.top, segment.bottom); } } Logger::Debug << "Removed " << removedSegments << " segments of size " << thresholdLevel << " or smaller.\n"; } void Morphology::Classify(SegmentedImagePtr segmentedImage) { std::map segments = createSegmentMap(segmentedImage); for (std::map::iterator i = segments.begin(); i != segments.end(); ++i) { const SegmentInfo& info = i->second; if (info.width > info.height * 10) segmentedImage->MergeSegments(LINE_SEGMENT, info.segment); else if (info.height > info.width * 10) segmentedImage->MergeSegments(BROADBAND_SEGMENT, info.segment); else segmentedImage->MergeSegments(BLOB_SEGMENT, info.segment); } } } // namespace algorithms aoflagger-v3.4.0/algorithms/highpassfilter.h0000644000175000017500000001430614507760372017676 0ustar olesoles#ifndef HIGHPASS_FILTER_H #define HIGHPASS_FILTER_H #include "../structures/image2d.h" #include "../structures/mask2d.h" #ifdef __SSE__ #define USE_INTRINSICS #endif namespace algorithms { /** * This class is able to perform a Gaussian high pass filter on an * Image2D . */ class HighPassFilter { public: /** * Construct a new high pass filter with default parameters */ HighPassFilter() : _hKernel(nullptr), _hWindowSize(22), _hKernelSigmaSq(7.5), _vKernel(nullptr), _vWindowSize(45), _vKernelSigmaSq(15.0) {} ~HighPassFilter(); /** * Apply a Gaussian high pass filter on the given image. */ /*Image2DPtr ApplyHighPass(const Image2DCPtr &image) { initializeKernel(); Image2DPtr temp(new Image2D(*image)); return Image2D::CreateFromDiff(image, temp); }*/ /** * Apply a Gaussian high-pass filter on the given image, ignoring * flagged samples. */ Image2DPtr ApplyHighPass(const Image2DCPtr& image, const Mask2DCPtr& mask); /** * Apply a Gaussian low-pass filter on the given image, ignoring * flagged samples. */ Image2DPtr ApplyLowPass(const Image2DCPtr& image, const Mask2DCPtr& mask); /** * Set the horizontal size of the sliding window in samples. Must be odd: if * the given parameter is not odd, it will be incremented by one. */ void SetHWindowSize(const unsigned hWindowSize) { delete[] _hKernel; _hKernel = nullptr; if ((hWindowSize % 2) == 0) _hWindowSize = hWindowSize + 1; else _hWindowSize = hWindowSize; } /** * Horizontal size of the sliding window in samples. * @see SetHWindowSize() */ unsigned HWindowSize() const { return _hWindowSize; } /** * Set the vertical size of the sliding window in samples. Must be odd: if the * given parameter is not odd, it will be incremented by one. */ void SetVWindowSize(const unsigned vWindowSize) { delete[] _vKernel; _vKernel = nullptr; if ((vWindowSize % 2) == 0) _vWindowSize = vWindowSize + 1; else _vWindowSize = vWindowSize; } /** * Vertical size of the sliding window in samples. * @see SetVWindowSize() */ unsigned VWindowSize() const { return _vWindowSize; } /** * Gaussian sigma parameter defining the horizontal shape of the convolution. * Given in units of samples. Note that the window has limited size as defined * by * @ref HSquareSize and @ref VSquareSize. Byond those values, the kernel is * truncated. */ double HKernelSigmaSq() const { return _hKernelSigmaSq; } /** * Set the horizontal sigma parameter of the kernel. * @see HKernelSigma() */ void SetHKernelSigmaSq(double newSigmaSquared) { delete[] _hKernel; _hKernel = nullptr; _hKernelSigmaSq = newSigmaSquared; } /** * Gaussian sigma parameter defining the horizontal shape of the convolution. * Given in units of samples. Note that the window has limited size as defined * by * @ref HSquareSize and @ref VSquareSize. Byond those values, the kernel is * truncated. */ double VKernelSigmaSq() const { return _vKernelSigmaSq; } /** * Set the horizontal sigma parameter of the kernel. * @see VKernelSigma() */ void SetVKernelSigmaSq(double newSigmaSquared) { delete[] _vKernel; _vKernel = nullptr; _vKernelSigmaSq = newSigmaSquared; } private: /** * Applies the low-pass convolution. Kernel has to be initialized * before calling. */ void applyLowPass(const Image2DPtr& image) { #ifdef USE_INTRINSICS applyLowPassSSE(image); #else applyLowPassSimple(image); #endif } void applyLowPassSimple(const Image2DPtr& image); void applyLowPassSSE(const Image2DPtr& image); void initializeKernel(); void setFlaggedValuesToZeroAndMakeWeights(const Image2DCPtr& inputImage, const Image2DPtr& outputImage, const Mask2DCPtr& inputMask, const Image2DPtr& weightsOutput) { #ifdef USE_INTRINSICS setFlaggedValuesToZeroAndMakeWeightsSSE(inputImage, outputImage, inputMask, weightsOutput); #else setFlaggedValuesToZeroAndMakeWeightsSimple(inputImage, outputImage, inputMask, weightsOutput); #endif } void setFlaggedValuesToZeroAndMakeWeightsSimple( const Image2DCPtr& inputImage, const Image2DPtr& outputImage, const Mask2DCPtr& inputMask, const Image2DPtr& weightsOutput); void setFlaggedValuesToZeroAndMakeWeightsSSE(const Image2DCPtr& inputImage, const Image2DPtr& outputImage, const Mask2DCPtr& inputMask, const Image2DPtr& weightsOutput); void elementWiseDivide(const Image2DPtr& leftHand, const Image2DCPtr& rightHand) { #ifdef USE_INTRINSICS elementWiseDivideSSE(leftHand, rightHand); #else elementWiseDivideSimple(leftHand, rightHand); #endif } void elementWiseDivideSimple(const Image2DPtr& leftHand, const Image2DCPtr& rightHand); void elementWiseDivideSSE(const Image2DPtr& leftHand, const Image2DCPtr& rightHand); /** * The values of the kernel used in the convolution. This kernel is applied * horizontally. */ num_t* _hKernel; /** * The horizontal size of the sliding window in samples. Must be odd. */ unsigned _hWindowSize; /** * Gaussian sigma parameter defining the horizontal shape of the convolution. * Given in units of samples (squared). Note that the window has limited size * as defined by * @ref _hSquareSize and @ref _vSquareSize. */ double _hKernelSigmaSq; /** * Vertical kernel values, see @ref _hKernel. */ num_t* _vKernel; /** * The vertical size of the window, see @ref _hSquareSize. */ unsigned _vWindowSize; /** * Gaussian sigma (squared) parameter defining the vertical shape of the * convolution, see * @ref _hKernelSize. */ double _vKernelSigmaSq; }; } // namespace algorithms #undef USE_INTRINSICS #endif // HIGHPASS_FILTER_H aoflagger-v3.4.0/algorithms/antennaselector.h0000644000175000017500000000106714507760372020047 0ustar olesoles#ifndef ANTENNA_SELECTOR_H #define ANTENNA_SELECTOR_H class StatisticsCollection; class DefaultStatistics; #include #include #include namespace algorithms { class AntennaSelector { public: AntennaSelector() : _threshold(5.0) {} std::vector Run( const StatisticsCollection& statisticsCollection); private: void addStatistic(unsigned antIndex, const DefaultStatistics& stats, std::map& antStatistics); double _threshold; }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/restorechannelrange.h0000644000175000017500000000271714507760372020716 0ustar olesoles#ifndef RESTORE_CHANNEL_RANGE_H #define RESTORE_CHANNEL_RANGE_H #include #include #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" namespace algorithms { class RestoreChannelRange { public: static void Execute(TimeFrequencyData& lhs, const TimeFrequencyData& rhs, const TimeFrequencyMetaData& metaData, double startMHz, double endMHz) { size_t maskCount = lhs.MaskCount(); std::vector cMasks(maskCount); for (size_t m = 0; m != maskCount; ++m) cMasks[m] = Mask2D::MakePtr(*lhs.GetMask(m)); std::vector originalMasks(maskCount); if (rhs.MaskCount() == 1 && maskCount != 1) { for (size_t m = 0; m != maskCount; ++m) originalMasks[m] = rhs.GetMask(0); } else { for (size_t m = 0; m != maskCount; ++m) originalMasks[m] = rhs.GetMask(m); } const std::vector& band = metaData.Band().channels; for (size_t ch = 0; ch != band.size(); ++ch) { if (band[ch].frequencyHz >= startMHz * 1e6 && band[ch].frequencyHz <= endMHz * 1e6) { for (size_t m = 0; m != maskCount; ++m) { for (size_t x = 0; x != originalMasks[m]->Width(); ++x) cMasks[m]->SetValue(x, ch, originalMasks[m]->Value(x, ch)); } } } for (size_t m = 0; m != maskCount; ++m) lhs.SetMask(m, std::move(cMasks[m])); } }; } // namespace algorithms #endif aoflagger-v3.4.0/algorithms/sinusfitter.h0000644000175000017500000000424014507760372017235 0ustar olesoles#ifndef SINUSFITTER_H #define SINUSFITTER_H #include #include #include "../structures/types.h" namespace algorithms { class SinusFitter { public: SinusFitter(); ~SinusFitter(); void FindPhaseAndAmplitude(num_t& phase, num_t& amplitude, const num_t* dataX, const num_t* dataT, const size_t dataSize, const num_t frequency) const throw(); void FindPhaseAndAmplitudeComplex(num_t& phase, num_t& amplitude, const num_t* dataR, const num_t* dataI, const num_t* dataT, const size_t dataSize, const num_t frequency) const throw(); num_t FindMean(const num_t phase, const num_t amplitude, const num_t* dataX, const num_t* dataT, const size_t dataSize, const num_t frequency); static num_t Value(const num_t phase, const num_t amplitude, const num_t t, const num_t frequency, num_t mean) { return cosn(phase + t * frequency) * amplitude + mean; } /*template static T Phase(T real, T imaginary) { if(real==0.0L) { if(imaginary==0.0L) return 0.0L; else if(imaginary > 0.0L) return M_PIn*0.5; else return -M_PIn*0.5; } else if(real>0.0L) { if(imaginary>=0.0L) // first return atannl(imaginary/real); else // fourth return atannl(imaginary/real)+2.0*M_PIn; } else { if(imaginary>=0.0L) // second return atannl(imaginary/real) + 1.0*M_PIn; else // third return atannl(imaginary/real) + 1.0*M_PIn; } }*/ static num_t Phase(num_t real, num_t imaginary) { return atan2n(imaginary, real); } static numl_t Phase(numl_t real, numl_t imaginary) { return atan2nl(imaginary, real); } private: }; } // namespace algorithms #endif aoflagger-v3.4.0/msio/0000755000175000017500000000000014516225226013275 5ustar olesolesaoflagger-v3.4.0/msio/reorderedfilebuffer.h0000644000175000017500000000325714507760372017470 0ustar olesoles#ifndef REORDERED_FILE_BUFFER_H #define REORDERED_FILE_BUFFER_H #include #include #include #include "../util/logger.h" class ReorderedFileBuffer { public: ReorderedFileBuffer(std::ofstream* stream, size_t maxSize) : _nextWritePos(0), _unflushedSize(0), _maxSize(maxSize), _stream(stream) {} ~ReorderedFileBuffer() { flush(); } void seekp(size_t offset) { _nextWritePos = offset; } void write(const char* data, size_t length) { _buffer.insert(BufferEntry(_nextWritePos, data, length)); _nextWritePos += length; _unflushedSize += length + sizeof(_nextWritePos) * 2; if (_unflushedSize > _maxSize) flush(); } void flush() { Logger::Debug << "Flushing reordered file buffer...\n"; for (std::set::const_iterator i = _buffer.begin(); i != _buffer.end(); ++i) { _stream->seekp(i->position, std::ios_base::beg); _stream->write(i->data.data(), i->data.size()); if (_stream->fail()) throw std::runtime_error( "Error: failed to write to reordered file! Check access rights and " "free disk space."); } _buffer.clear(); _unflushedSize = 0; } std::ofstream& stream() { return *_stream; } private: struct BufferEntry { BufferEntry(size_t pos_, const char* data_, size_t length_) : position(pos_), data(data_, data_ + length_) {} bool operator<(const BufferEntry& other) const { return position < other.position; } size_t position; std::vector data; }; std::set _buffer; size_t _nextWritePos; size_t _unflushedSize; size_t _maxSize; std::ofstream* _stream; }; #endif aoflagger-v3.4.0/msio/memorybaselinereader.cpp0000644000175000017500000002540414507760372020212 0ustar olesoles#include "memorybaselinereader.h" #include "msselection.h" #include "../util/logger.h" #include "../util/progress/dummyprogresslistener.h" #include "../util/stopwatch.h" #include #include #include #include #include void MemoryBaselineReader::PrepareReadWrite(ProgressListener& progress) { if (!_isRead) { progress.OnStartTask("Reading measurement set into memory"); readSet(progress); _isRead = true; } } void MemoryBaselineReader::PerformReadRequests(ProgressListener& progress) { PrepareReadWrite(progress); for (size_t i = 0; i != _readRequests.size(); ++i) { const ReadRequest& request = _readRequests[i]; const BaselineID id(request.antenna1, request.antenna2, request.spectralWindow, request.sequenceId); const std::map>::const_iterator requestedBaselineIter = _baselines.find(id); if (requestedBaselineIter == _baselines.end()) { std::ostringstream errorStr; errorStr << "Exception in PerformReadRequests(): requested baseline is " "not available in measurement set " "(antenna1=" << request.antenna1 << ", antenna2=" << request.antenna2 << ", " "spw=" << request.spectralWindow << ", sequenceId=" << request.sequenceId << ")"; throw std::runtime_error(errorStr.str()); } else { _results.push_back(*requestedBaselineIter->second); } } _readRequests.clear(); progress.OnFinish(); } void MemoryBaselineReader::readSet(ProgressListener& progress) { const Stopwatch watch(true); initializeMeta(); const casacore::MeasurementSet table(OpenMS()); casacore::ScalarColumn ant1Column( table, casacore::MeasurementSet::columnName(casacore::MSMainEnums::ANTENNA1)), ant2Column(table, casacore::MeasurementSet::columnName( casacore::MSMainEnums::ANTENNA2)), dataDescIdColumn(table, casacore::MeasurementSet::columnName( casacore::MSMainEnums::DATA_DESC_ID)); casacore::ArrayColumn dataColumn(table, DataColumnName()); casacore::ArrayColumn flagColumn( table, casacore::MeasurementSet::columnName(casacore::MSMainEnums::FLAG)); casacore::ArrayColumn uvwColumn( table, casacore::MeasurementSet::columnName(casacore::MSMainEnums::UVW)); size_t antennaCount = MetaData().AntennaCount(), polarizationCount = Polarizations().size(), bandCount = MetaData().BandCount(), sequenceCount = MetaData().SequenceCount(), intStart = IntervalStart(), intEnd = IntervalEnd(); std::vector dataDescIdToSpw; MetaData().GetDataDescToBandVector(dataDescIdToSpw); std::vector bandInfos(bandCount); for (size_t b = 0; b != bandCount; ++b) bandInfos[b] = MetaData().GetBandInfo(b); // Initialize the look-up matrix // to quickly access the elements (without the map-lookup) typedef std::unique_ptr MatrixElement; typedef std::vector MatrixRow; typedef std::vector BaselineMatrix; typedef std::vector BaselineCube; BaselineCube baselineCube(sequenceCount * bandCount); for (size_t s = 0; s != sequenceCount; ++s) { for (size_t b = 0; b != bandCount; ++b) { BaselineMatrix& matrix = baselineCube[s * bandCount + b]; matrix.resize(antennaCount); for (size_t a1 = 0; a1 != antennaCount; ++a1) { matrix[a1].resize(antennaCount); for (size_t a2 = 0; a2 != antennaCount; ++a2) matrix[a1][a2] = nullptr; } } } // The actual reading of the data Logger::Debug << "Reading the data (interval={" << intStart << "..." << intEnd << "})...\n"; casacore::Array dataArray; casacore::Array flagArray; casacore::MeasurementSet ms(OpenMS()); MSSelection msSelection(ms, ObservationTimesPerSequence(), progress); msSelection.Process([&](size_t rowIndex, size_t sequenceId, size_t timeIndexInSequence) { size_t ant1 = ant1Column(rowIndex); size_t ant2 = ant2Column(rowIndex); const size_t spw = dataDescIdToSpw[dataDescIdColumn(rowIndex)]; const size_t spwFieldIndex = spw + sequenceId * bandCount; if (ant1 > ant2) std::swap(ant1, ant2); std::unique_ptr& result = baselineCube[spwFieldIndex][ant1][ant2]; if (result == nullptr) { const size_t timeStepCount = ObservationTimes(sequenceId).size(); const size_t nFreq = MetaData().FrequencyCount(spw); result.reset(new Result()); for (size_t p = 0; p != polarizationCount; ++p) { result->_realImages.emplace_back( Image2D::CreateZeroImagePtr(timeStepCount, nFreq)); result->_imaginaryImages.emplace_back( Image2D::CreateZeroImagePtr(timeStepCount, nFreq)); result->_flags.emplace_back( Mask2D::CreateSetMaskPtr(timeStepCount, nFreq)); } result->_bandInfo = bandInfos[spw]; result->_uvw.resize(timeStepCount); } dataArray = dataColumn.get(rowIndex); flagArray = flagColumn.get(rowIndex); casacore::Array uvwArray = uvwColumn.get(rowIndex); casacore::Array::const_contiter uvwPtr = uvwArray.cbegin(); UVW uvw; uvw.u = *uvwPtr; ++uvwPtr; uvw.v = *uvwPtr; ++uvwPtr; uvw.w = *uvwPtr; result->_uvw[timeIndexInSequence] = uvw; for (size_t p = 0; p != polarizationCount; ++p) { casacore::Array::const_contiter dataPtr = dataArray.cbegin(); casacore::Array::const_contiter flagPtr = flagArray.cbegin(); Image2D& real = *result->_realImages[p]; Image2D& imag = *result->_imaginaryImages[p]; Mask2D& mask = *result->_flags[p]; const size_t imgStride = real.Stride(); const size_t mskStride = mask.Stride(); num_t* realOutPtr = real.ValuePtr(timeIndexInSequence, 0); num_t* imagOutPtr = imag.ValuePtr(timeIndexInSequence, 0); bool* flagOutPtr = mask.ValuePtr(timeIndexInSequence, 0); for (size_t i = 0; i != p; ++i) { ++dataPtr; ++flagPtr; } const size_t frequencyCount = bandInfos[spw].channels.size(); for (size_t ch = 0; ch != frequencyCount; ++ch) { *realOutPtr = dataPtr->real(); *imagOutPtr = dataPtr->imag(); *flagOutPtr = *flagPtr; realOutPtr += imgStride; imagOutPtr += imgStride; flagOutPtr += mskStride; for (size_t i = 0; i != polarizationCount; ++i) { ++dataPtr; ++flagPtr; } } } }); // Move elements from matrix into the baseline map. for (size_t s = 0; s != sequenceCount; ++s) { for (size_t b = 0; b != bandCount; ++b) { const size_t fbIndex = s * bandCount + b; for (size_t a1 = 0; a1 != antennaCount; ++a1) { for (size_t a2 = a1; a2 != antennaCount; ++a2) { std::unique_ptr& result = baselineCube[fbIndex][a1][a2]; if (result) { _baselines.emplace(BaselineID(a1, a2, b, s), std::move(result)); } } } } } _areFlagsChanged = false; Logger::Debug << "Reading took " << watch.ToString() << ".\n"; } void MemoryBaselineReader::PerformFlagWriteRequests() { PrepareReadWrite(dummy_progress_); for (size_t i = 0; i != _writeRequests.size(); ++i) { const FlagWriteRequest& request = _writeRequests[i]; const BaselineID id(request.antenna1, request.antenna2, request.spectralWindow, request.sequenceId); std::unique_ptr& result = _baselines[id]; if (result->_flags.size() != request.flags.size()) throw std::runtime_error("Polarizations do not match"); for (size_t p = 0; p != result->_flags.size(); ++p) result->_flags[p].reset(new Mask2D(*request.flags[p])); } _areFlagsChanged = true; _writeRequests.clear(); } void MemoryBaselineReader::WriteToMs() { casacore::MeasurementSet ms(OpenMS(true)); casacore::ScalarColumn ant1Column( ms, casacore::MeasurementSet::columnName(casacore::MSMainEnums::ANTENNA1)), ant2Column(ms, casacore::MeasurementSet::columnName( casacore::MSMainEnums::ANTENNA2)), dataDescIdColumn(ms, casacore::MeasurementSet::columnName( casacore::MSMainEnums::DATA_DESC_ID)); casacore::ArrayColumn flagColumn( ms, casacore::MeasurementSet::columnName(casacore::MSMainEnums::FLAG)); std::vector dataIdToSpw; MetaData().GetDataDescToBandVector(dataIdToSpw); const size_t polarizationCount = Polarizations().size(); Logger::Debug << "Flags have changed, writing them back to the set...\n"; DummyProgressListener dummy; MSSelection msSelection(ms, ObservationTimesPerSequence(), dummy); msSelection.Process([&](size_t rowIndex, size_t sequenceId, size_t timeIndexInSequence) { size_t ant1 = ant1Column(rowIndex); size_t ant2 = ant2Column(rowIndex); const size_t spw = dataIdToSpw[dataDescIdColumn(rowIndex)]; if (ant1 > ant2) std::swap(ant1, ant2); const size_t frequencyCount = MetaData().FrequencyCount(spw); casacore::IPosition flagShape = casacore::IPosition(2); flagShape[0] = polarizationCount; flagShape[1] = frequencyCount; casacore::Array flagArray(flagShape); const BaselineID baselineID(ant1, ant2, spw, sequenceId); const std::map>::iterator resultIter = _baselines.find(baselineID); std::unique_ptr& result = resultIter->second; casacore::Array::contiter flagPtr = flagArray.cbegin(); std::vector masks(polarizationCount); for (size_t p = 0; p != polarizationCount; ++p) masks[p] = result->_flags[p].get(); for (size_t ch = 0; ch != frequencyCount; ++ch) { for (size_t p = 0; p != polarizationCount; ++p) { *flagPtr = masks[p]->Value(timeIndexInSequence, ch); ++flagPtr; } } flagColumn.put(rowIndex, flagArray); }); _areFlagsChanged = false; } bool MemoryBaselineReader::IsEnoughMemoryAvailable(uint64_t size) { const uint64_t totalMem = aocommon::system::TotalMemory(); if (size * 2 >= totalMem) { Logger::Warn << (size / 1000000) << " MB required, but " << (totalMem / 1000000) << " MB available.\n" "Because this is not at least twice as much, the reordering " "mode (slower!) will be used.\n"; return false; } else { Logger::Debug << (size / 1000000) << " MB required, " << (totalMem / 1000000) << " MB available: will use memory read mode.\n"; return true; } } aoflagger-v3.4.0/msio/singlebaselinefile.h0000644000175000017500000000237114507760372017303 0ustar olesoles#ifndef SINGLE_BASELINE_FILE_H #define SINGLE_BASELINE_FILE_H #include #include #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "../util/progress/progresslistener.h" class SingleBaselineFile { public: void Read(std::istream& stream, ProgressListener& progress); void Write(std::ostream& stream); static void Serialize(std::ostream& stream, const TimeFrequencyData& data); static void Serialize(std::ostream& stream, const TimeFrequencyMetaData& metaData); static void Serialize(std::ostream& stream, const Image2D& image); static void Serialize(std::ostream& stream, const Mask2D& mask); static TimeFrequencyData UnserializeTFData(std::istream& stream, ProgressListener& progress); static TimeFrequencyMetaData UnserializeMetaData(std::istream& stream); static Image2D UnserializeImage(std::istream& stream, ProgressListener& progress, size_t progressOffset, size_t progressMax); static Mask2D UnserializeMask(std::istream& stream); TimeFrequencyData data; TimeFrequencyMetaData metaData; std::string telescopeName; }; #endif aoflagger-v3.4.0/msio/baselinereader.h0000644000175000017500000002114714507760372016426 0ustar olesoles#ifndef BASELINEREADER_H #define BASELINEREADER_H #include "../structures/antennainfo.h" #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../structures/msmetadata.h" #include #include #include #include #include #include #include typedef std::shared_ptr BaselineReaderPtr; typedef std::shared_ptr BaselineReaderCPtr; class BaselineReader { public: explicit BaselineReader(const std::string& msFile); virtual ~BaselineReader(); /** * Has the measurement set been modified? * * When it's been modified the changes need to be written to the measurement * set. By default the destructor of the subclasses should execute this * operation. In order to allow writing to multiple measurement sets in * parallel the functionality is exposed. */ virtual bool IsModified() const = 0; /** * Writes the changes to the measurement set. * * @post @c IsModified() == @c false. */ virtual void WriteToMs() = 0; /** * Prepares the reader before usage. * * Some readers have a preparation step that can be done in parallel. Calling * this function is optional; when not called manually the reader shall * execute the preparation itself. * * @note When no @a progress is needed use the @ref dummy_progress_. */ virtual void PrepareReadWrite(class ProgressListener& progress) = 0; static class DummyProgressListener dummy_progress_; bool ReadFlags() const { return _readFlags; } void SetReadFlags(bool readFlags) { _readFlags = readFlags; } bool ReadData() const { return _readData; } void SetReadData(bool readData) { _readData = readData; } const std::string& DataColumnName() const { return _dataColumnName; } void SetDataColumnName(const std::string& name) { _dataColumnName = name; } const std::vector& Polarizations() { initializePolarizations(); return _polarizations; } casacore::MeasurementSet OpenMS(bool writeAccess = false) const { if (writeAccess) return casacore::MeasurementSet(_msMetaData.Path(), casacore::TableLock::PermanentLockingWait, casacore::Table::Update); else return casacore::MeasurementSet( _msMetaData.Path(), casacore::TableLock::PermanentLockingWait); } MSMetaData& MetaData() { return _msMetaData; } const std::map& ObservationTimes(size_t sequenceId) const { return _observationTimes[sequenceId]; } std::vector ObservationTimes(size_t startIndex, size_t endIndex) const { std::vector times; times.insert(times.begin(), _observationTimesVector.begin() + startIndex, _observationTimesVector.begin() + endIndex); return times; } void AddReadRequest(size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId); void AddReadRequest(size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId, size_t startIndex, size_t endIndex) { addReadRequest(antenna1, antenna2, spectralWindow, sequenceId, startIndex, endIndex); } virtual void PerformReadRequests(class ProgressListener& progress) = 0; void AddWriteTask(std::vector flags, size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId) { initializePolarizations(); if (flags.size() != _polarizations.size()) { std::stringstream s; s << "Trying to write image with " << flags.size() << " polarizations to a measurement set with " << _polarizations.size(); throw std::runtime_error(s.str()); } FlagWriteRequest task; task.flags = flags; task.antenna1 = antenna1; task.antenna2 = antenna2; task.spectralWindow = spectralWindow; task.sequenceId = sequenceId; task.startIndex = 0; task.endIndex = flags[0]->Width(); task.leftBorder = 0; task.rightBorder = 0; _writeRequests.push_back(task); } virtual void PerformFlagWriteRequests() = 0; virtual void PerformDataWriteTask(std::vector _realImages, std::vector _imaginaryImages, size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId) = 0; TimeFrequencyData GetNextResult(std::vector& uvw); virtual size_t GetMinRecommendedBufferSize(size_t threadCount) { return threadCount; } virtual size_t GetMaxRecommendedBufferSize(size_t threadCount) { return 2 * threadCount; } static uint64_t MeasurementSetDataSize(const std::string& filename); /** * Returns an estimate of the size of the measurement set. * * This estimate can be used to see whether the memory reader can be used. * * The \a start and \a end are an optional, this allows using * \ref Options::startTimestep and \ref Options::endTimestep in this function * call. */ static uint64_t MeasurementSetIntervalDataSize(const string& filename, std::optional start, std::optional end); void SetInterval(std::optional start, std::optional end) { _intervalStart = start; _intervalEnd = end; if (_intervalStart) _msMetaData.SetIntervalStart(IntervalStart()); if (_intervalEnd) _msMetaData.SetIntervalEnd(IntervalEnd()); } bool HasIntervalStart() const { return (bool)_intervalStart; } bool HasIntervalEnd() const { return (bool)_intervalEnd; } size_t IntervalStart() const { if (HasIntervalStart()) return *_intervalStart; else return 0; } size_t IntervalEnd() const { if (HasIntervalEnd()) return *_intervalEnd; else return _observationTimesVector.size(); } protected: struct ReadRequest { int antenna1; int antenna2; int spectralWindow; unsigned sequenceId; size_t startIndex; size_t endIndex; }; struct FlagWriteRequest { FlagWriteRequest() = default; FlagWriteRequest(const FlagWriteRequest& source) : flags(source.flags), antenna1(source.antenna1), antenna2(source.antenna2), spectralWindow(source.spectralWindow), sequenceId(source.sequenceId), startIndex(source.startIndex), endIndex(source.endIndex), leftBorder(source.leftBorder), rightBorder(source.rightBorder) {} std::vector flags; int antenna1; int antenna2; int spectralWindow; unsigned sequenceId; size_t startIndex; size_t endIndex; size_t leftBorder; size_t rightBorder; }; struct Result { Result() = default; Result(const Result& source) : _realImages(source._realImages), _imaginaryImages(source._imaginaryImages), _flags(source._flags), _uvw(source._uvw), _bandInfo(source._bandInfo) {} std::vector _realImages; std::vector _imaginaryImages; std::vector _flags; std::vector _uvw; BandInfo _bandInfo; }; void initializeMeta() { initObservationTimes(); initializePolarizations(); } const std::vector>& ObservationTimesPerSequence() const { return _observationTimes; } std::vector _readRequests; std::vector _writeRequests; std::vector _results; private: BaselineReader(const BaselineReader&) = delete; BaselineReader& operator=(const BaselineReader&) = delete; void initializePolarizations(); void initObservationTimes(); void addReadRequest(size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId, size_t startIndex, size_t endIndex) { ReadRequest request; request.antenna1 = antenna1; request.antenna2 = antenna2; request.spectralWindow = spectralWindow; request.sequenceId = sequenceId; request.startIndex = startIndex; request.endIndex = endIndex; _readRequests.push_back(request); } MSMetaData _msMetaData; std::string _dataColumnName; bool _readData, _readFlags; std::vector> _observationTimes; std::vector _observationTimesVector; std::vector _polarizations; std::optional _intervalStart, _intervalEnd; }; #endif // BASELINEREADER_H aoflagger-v3.4.0/msio/spatialtimeloader.h0000644000175000017500000000163714507760372017166 0ustar olesoles#ifndef SPATIALTIMELOADER_H #define SPATIALTIMELOADER_H #include #include #include "../structures/timefrequencydata.h" #include "../structures/msmetadata.h" /** * Loader for time x baseline matrices. These are mainly used for SVD * experiments. This class is used in the SpatialTimeImageSet . */ class SpatialTimeLoader { public: explicit SpatialTimeLoader(MSMetaData& measurementSet); ~SpatialTimeLoader(); TimeFrequencyData Load(unsigned channelIndex, bool fringeStop = true); unsigned ChannelCount() const { return _channelCount; } unsigned TimestepsCount() const { return _timestepsCount; } private: MSMetaData& _msMetaData; std::unique_ptr _sortedTable; std::unique_ptr _tableIter; unsigned _channelCount; unsigned _timestepsCount; unsigned _antennaCount; unsigned _polarizationCount; }; #endif aoflagger-v3.4.0/msio/directbaselinereader.cpp0000644000175000017500000003205214507760372020151 0ustar olesoles#include "directbaselinereader.h" #include "msselection.h" #include "../structures/timefrequencydata.h" #include "../util/logger.h" #include "../util/progress/dummyprogresslistener.h" #include "../util/stopwatch.h" #include #include #include #include #include DirectBaselineReader::DirectBaselineReader(const std::string& msFile) : BaselineReader(msFile), _ms(OpenMS()) {} void DirectBaselineReader::initBaselineCache() { // Pass one time through the entire measurement set and store the rownumbers // of the baselines. Logger::Debug << "Determining sequence positions within file for direct " "baseline reader...\n"; std::vector dataIdToSpw; MetaData().GetDataDescToBandVector(dataIdToSpw); casacore::ScalarColumn antenna1Column(_ms, "ANTENNA1"); casacore::ScalarColumn antenna2Column(_ms, "ANTENNA2"); casacore::ScalarColumn dataDescIdColumn(_ms, "DATA_DESC_ID"); DummyProgressListener progress; // TODO MSSelection msSelection(_ms, ObservationTimesPerSequence(), progress); msSelection.Process( [&](size_t rowIndex, size_t sequenceId, size_t /*timeIndexInSequence*/) { int antenna1 = antenna1Column(rowIndex), antenna2 = antenna2Column(rowIndex), dataDescId = dataDescIdColumn(rowIndex); const int spectralWindow = dataIdToSpw[dataDescId]; addRowToBaselineCache(antenna1, antenna2, spectralWindow, sequenceId, rowIndex); }); } void DirectBaselineReader::addRowToBaselineCache(size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId, size_t row) { BaselineCacheIndex searchItem; searchItem.antenna1 = antenna1; searchItem.antenna2 = antenna2; searchItem.spectralWindow = spectralWindow; searchItem.sequenceId = sequenceId; const std::map::iterator cacheItemIter = _baselineCache.find(searchItem); if (cacheItemIter == _baselineCache.end()) { BaselineCacheValue cacheValue; cacheValue.rows.push_back(row); _baselineCache.insert(std::make_pair(searchItem, cacheValue)); } else { cacheItemIter->second.rows.push_back(row); } } void DirectBaselineReader::addRequestRows( ReadRequest request, size_t requestIndex, std::vector>& rows) { BaselineCacheIndex searchItem; searchItem.antenna1 = request.antenna1; searchItem.antenna2 = request.antenna2; searchItem.spectralWindow = request.spectralWindow; searchItem.sequenceId = request.sequenceId; auto cacheItemIter = _baselineCache.find(searchItem); if (cacheItemIter != _baselineCache.end()) { const std::vector& cacheRows = cacheItemIter->second.rows; for (const size_t j : cacheRows) rows.emplace_back(j, requestIndex); } } void DirectBaselineReader::addRequestRows( FlagWriteRequest request, size_t requestIndex, std::vector>& rows) { BaselineCacheIndex searchItem; searchItem.antenna1 = request.antenna1; searchItem.antenna2 = request.antenna2; searchItem.spectralWindow = request.spectralWindow; searchItem.sequenceId = request.sequenceId; auto cacheItemIter = _baselineCache.find(searchItem); if (cacheItemIter != _baselineCache.end()) { const std::vector& cacheRows = cacheItemIter->second.rows; for (const size_t j : cacheRows) rows.emplace_back(j, requestIndex); } } void DirectBaselineReader::PerformReadRequests(ProgressListener& progress) { progress.OnStartTask("Reading measurement set"); const Stopwatch stopwatch(true); initializeMeta(); if (_baselineCache.empty()) initBaselineCache(); // Each element contains (row number, corresponding request index) std::vector> rows; for (size_t i = 0; i != _readRequests.size(); ++i) addRequestRows(_readRequests[i], i, rows); std::sort(rows.begin(), rows.end()); _results.resize(_readRequests.size()); for (size_t reqIndex = 0; reqIndex != _readRequests.size(); ++reqIndex) { const ReadRequest& request = _readRequests[reqIndex]; Result& result = _results[reqIndex]; size_t startIndex = request.startIndex, endIndex = request.endIndex, band = request.spectralWindow, channelCount = MetaData().FrequencyCount(band); const size_t width = endIndex - startIndex; for (size_t p = 0; p < Polarizations().size(); ++p) { if (ReadData()) { result._realImages.emplace_back( Image2D::CreateZeroImagePtr(width, channelCount)); result._imaginaryImages.emplace_back( Image2D::CreateZeroImagePtr(width, channelCount)); } if (ReadFlags()) { // The flags should be initialized to true, as a baseline might // miss some time scans that other baselines do have, and these // should be flagged. result._flags.emplace_back( Mask2D::CreateSetMaskPtr(width, channelCount)); } } result._uvw.resize(width); } const casacore::ScalarColumn timeColumn(_ms, "TIME"); const casacore::ArrayColumn weightColumn(_ms, "WEIGHT"); const casacore::ArrayColumn uvwColumn(_ms, "UVW"); const casacore::ArrayColumn flagColumn(_ms, "FLAG"); std::unique_ptr> dataColumn; if (ReadData()) dataColumn.reset( new casacore::ArrayColumn(_ms, DataColumnName())); for (size_t i = 0; i != rows.size(); ++i) { progress.OnProgress(i, rows.size()); const std::pair p = rows[i]; const size_t rowIndex = p.first; const size_t requestIndex = p.second; const double time = timeColumn(rowIndex); const ReadRequest& request = _readRequests[requestIndex]; size_t timeIndex = ObservationTimes(request.sequenceId).find(time)->second, startIndex = request.startIndex, endIndex = request.endIndex, band = request.spectralWindow; const bool timeIsSelected = timeIndex >= startIndex && timeIndex < endIndex; if (ReadData() && timeIsSelected) { // if(BaselineReader::DataKind() == WeightData) // readWeights(requestIndex, timeIndex-startIndex, // MetaData().FrequencyCount(band), weightColumn(rowIndex)); else readTimeData(requestIndex, timeIndex - startIndex, MetaData().FrequencyCount(band), (*dataColumn)(rowIndex)); } if (ReadFlags() && timeIsSelected) { readTimeFlags(requestIndex, timeIndex - startIndex, MetaData().FrequencyCount(band), flagColumn(rowIndex)); } if (timeIsSelected) { casacore::Array arr = uvwColumn(rowIndex); casacore::Array::const_contiter i = arr.cbegin(); _results[requestIndex]._uvw[timeIndex - startIndex].u = *i; ++i; _results[requestIndex]._uvw[timeIndex - startIndex].v = *i; ++i; _results[requestIndex]._uvw[timeIndex - startIndex].w = *i; } } _readRequests.clear(); progress.OnFinish(); } std::vector DirectBaselineReader::ReadUVW(unsigned antenna1, unsigned antenna2, unsigned spectralWindow, unsigned sequenceId) { const Stopwatch stopwatch(true); initializeMeta(); if (_baselineCache.empty()) initBaselineCache(); const std::map& observationTimes = ObservationTimes(sequenceId); // Each element contains (row number, corresponding request index) std::vector> rows; ReadRequest request; request.antenna1 = antenna1; request.antenna2 = antenna2; request.spectralWindow = spectralWindow; request.sequenceId = sequenceId; request.startIndex = 0; request.endIndex = observationTimes.size(); addRequestRows(request, 0, rows); std::sort(rows.begin(), rows.end()); const size_t width = observationTimes.size(); const casacore::ScalarColumn timeColumn(_ms, "TIME"); const casacore::ArrayColumn uvwColumn(_ms, "UVW"); std::vector uvws; uvws.resize(width); for (std::vector>::const_iterator i = rows.begin(); i != rows.end(); ++i) { const size_t rowIndex = i->first; const double time = timeColumn(rowIndex); const size_t timeIndex = observationTimes.find(time)->second; casacore::Array arr = uvwColumn(rowIndex); casacore::Array::const_contiter j = arr.cbegin(); UVW& uvw = uvws[timeIndex]; uvw.u = *j; ++j; uvw.v = *j; ++j; uvw.w = *j; } Logger::Debug << "Read of UVW took: " << stopwatch.ToString() << '\n'; return uvws; } void DirectBaselineReader::PerformFlagWriteRequests() { const Stopwatch stopwatch(true); initializeMeta(); if (_baselineCache.empty()) initBaselineCache(); // Each element contains (row number, corresponding request index) std::vector> rows; for (size_t i = 0; i != _writeRequests.size(); ++i) addRequestRows(_writeRequests[i], i, rows); std::sort(rows.begin(), rows.end()); _ms.reopenRW(); const casacore::ScalarColumn timeColumn(_ms, "TIME"); casacore::ArrayColumn flagColumn(_ms, "FLAG"); for (const FlagWriteRequest& request : _writeRequests) { const size_t band = request.spectralWindow; if (MetaData().FrequencyCount(band) != request.flags[0]->Height()) { std::cerr << "The frequency count in the measurement set (" << MetaData().FrequencyCount(band) << ") does not match the image!\n"; } if (request.endIndex - request.startIndex != request.flags[0]->Width()) { std::cerr << "The number of time scans to write in the measurement set (" << (request.endIndex - request.startIndex) << ") does not match the image (" << request.flags[0]->Width() << ") !\n"; } } size_t rowsWritten = 0; for (const std::pair& row : rows) { const size_t rowIndex = row.first; FlagWriteRequest& request = _writeRequests[row.second]; const double time = timeColumn(rowIndex); const size_t timeIndex = ObservationTimes(request.sequenceId).find(time)->second; if (timeIndex >= request.startIndex + request.leftBorder && timeIndex < request.endIndex - request.rightBorder) { casacore::Array flag = flagColumn(rowIndex); casacore::Array::iterator j = flag.begin(); for (size_t f = 0; f < (size_t)MetaData().FrequencyCount(request.spectralWindow); ++f) { for (size_t p = 0; p < Polarizations().size(); ++p) { *j = request.flags[p]->Value(timeIndex - request.startIndex, f); ++j; } } flagColumn.basePut(rowIndex, flag); ++rowsWritten; } } _writeRequests.clear(); Logger::Debug << rowsWritten << "/" << rows.size() << " rows written in " << stopwatch.ToString() << '\n'; } void DirectBaselineReader::readTimeData( size_t requestIndex, size_t xOffset, size_t frequencyCount, const casacore::Array& data) { casacore::Array::const_contiter i = data.cbegin(); const size_t polarizationCount = Polarizations().size(); for (size_t f = 0; f < (size_t)frequencyCount; ++f) { num_t rv, iv; for (size_t p = 0; p < polarizationCount; ++p) { const casacore::Complex& complex = *i; ++i; rv = complex.real(); iv = complex.imag(); _results[requestIndex]._realImages[p]->SetValue(xOffset, f, rv); _results[requestIndex]._imaginaryImages[p]->SetValue(xOffset, f, iv); } } } void DirectBaselineReader::readTimeFlags(size_t requestIndex, size_t xOffset, size_t frequencyCount, const casacore::Array& flag) { const size_t polarizationCount = Polarizations().size(); casacore::Array::const_iterator j = flag.begin(); for (size_t f = 0; f < (size_t)frequencyCount; ++f) { for (size_t p = 0; p < polarizationCount; ++p) { const bool v = *j; ++j; _results[requestIndex]._flags[p]->SetValue(xOffset, f, v); } } } void DirectBaselineReader::readWeights(size_t requestIndex, size_t xOffset, size_t frequencyCount, const casacore::Array& weight) { const size_t polarizationCount = Polarizations().size(); casacore::Array::const_iterator j = weight.begin(); std::vector values(polarizationCount); for (size_t p = 0; p < polarizationCount; ++p) { values[p] = *j; ++j; } for (size_t f = 0; f < (size_t)frequencyCount; ++f) { for (size_t p = 0; p < polarizationCount; ++p) { _results[requestIndex]._realImages[p]->SetValue(xOffset, f, values[p]); _results[requestIndex]._imaginaryImages[p]->SetValue(xOffset, f, 0.0); } } } aoflagger-v3.4.0/msio/msselection.h0000644000175000017500000000362414507760372016006 0ustar olesoles#ifndef MS_SELECTION_H #define MS_SELECTION_H #include #include #include #include #include #include #include "../util/progress/progresslistener.h" class MSSelection { public: MSSelection(casacore::MeasurementSet& ms, const std::vector>& observationTimes, ProgressListener& progress) : _observationTimes(observationTimes), _ms(ms), _progress(progress) {} template void Process(Function function) { casacore::ScalarColumn timeColumn(_ms, "TIME"); casacore::ScalarColumn fieldIdColumn(_ms, "FIELD_ID"); double prevTime = -1.0; size_t prevFieldId = size_t(-1), sequenceId = size_t(-1), timeIndexInSequence = size_t(-1); for (size_t rowIndex = 0; rowIndex != _ms.nrow(); ++rowIndex) { _progress.OnProgress(rowIndex, _ms.nrow()); double time = timeColumn(rowIndex); bool newTime = time != prevTime; size_t fieldId = fieldIdColumn(rowIndex); if (fieldId != prevFieldId) { prevFieldId = fieldId; sequenceId++; newTime = true; } if (newTime) { const std::map& observationTimes = _observationTimes[sequenceId]; prevTime = time; auto elem = observationTimes.find(time); if (elem == observationTimes.end()) timeIndexInSequence = std::numeric_limits::max(); else timeIndexInSequence = elem->second; } if (timeIndexInSequence != std::numeric_limits::max()) { function(rowIndex, sequenceId, timeIndexInSequence); } } } private: std::vector> _observationTimes; casacore::MeasurementSet& _ms; ProgressListener& _progress; }; #endif aoflagger-v3.4.0/msio/baselinematrixloader.h0000644000175000017500000000214214507760372017651 0ustar olesoles#ifndef BASELINEMATRIXLOADER_H #define BASELINEMATRIXLOADER_H #include #include #include "../structures/timefrequencydata.h" #include "../structures/msmetadata.h" /** * Loader for antenna x antenna matrices, useful for e.g. spatial analyses such * as spatial filtering. */ class BaselineMatrixLoader { public: explicit BaselineMatrixLoader(MSMetaData& measurementSet); TimeFrequencyData Load(size_t timeIndex) { return LoadSummed(timeIndex); } void LoadPerChannel(size_t timeIndex, std::vector& data); size_t TimeIndexCount() const { return _timeIndexCount; } class SpatialMatrixMetaData& MetaData() const { return *_metaData; } size_t FrequencyCount() const { return _frequencyCount; } private: TimeFrequencyData LoadSummed(size_t timeIndex); std::unique_ptr _sortedTable; std::unique_ptr _tableIter; size_t _currentIterIndex; MSMetaData _msMetaData; size_t _timeIndexCount; std::unique_ptr _metaData; size_t _frequencyCount; }; #endif aoflagger-v3.4.0/msio/baselinematrixloader.cpp0000644000175000017500000003123314507760372020207 0ustar olesoles#include "baselinematrixloader.h" #include #include #include #include "../structures/spatialmatrixmetadata.h" BaselineMatrixLoader::BaselineMatrixLoader(MSMetaData& msMetaData) : _sortedTable(), _tableIter(), _currentIterIndex(0), _msMetaData(msMetaData), _timeIndexCount(0), _metaData() { const casacore::Table rawTable(_msMetaData.Path()); casacore::Block names(4); names[0] = "DATA_DESC_ID"; names[1] = "TIME"; names[2] = "ANTENNA1"; names[3] = "ANTENNA2"; _sortedTable.reset(new casacore::Table(rawTable.sort(names))); casacore::Block selectionNames(2); selectionNames[0] = "DATA_DESC_ID"; selectionNames[1] = "TIME"; casacore::TableIterator iter(*_sortedTable, selectionNames, casacore::TableIterator::Ascending, casacore::TableIterator::NoSort); while (!iter.pastEnd()) { iter.next(); ++_timeIndexCount; } _frequencyCount = _msMetaData.FrequencyCount(0); _tableIter.reset(new casacore::TableIterator( *_sortedTable, selectionNames, casacore::TableIterator::Ascending, casacore::TableIterator::NoSort)); } TimeFrequencyData BaselineMatrixLoader::LoadSummed(size_t timeIndex) { casacore::Block selectionNames(2); selectionNames[0] = "DATA_DESC_ID"; selectionNames[1] = "TIME"; if (timeIndex < _currentIterIndex) { _tableIter.reset(new casacore::TableIterator( *_sortedTable, selectionNames, casacore::TableIterator::Ascending, casacore::TableIterator::NoSort)); _currentIterIndex = 0; } while (!_tableIter->pastEnd() && timeIndex - _currentIterIndex > 0) { _tableIter->next(); ++_currentIterIndex; } if (_tableIter->pastEnd()) { throw std::runtime_error("Time index not found"); } const casacore::Table table = _tableIter->table(); const casacore::ScalarColumn antenna1Column(table, "ANTENNA1"); const casacore::ScalarColumn antenna2Column(table, "ANTENNA2"); // Find highest antenna index int nrAntenna = 0; for (size_t i = 0; i < table.nrow(); ++i) { int a1 = antenna1Column(i), a2 = antenna2Column(i); if (a1 > nrAntenna) nrAntenna = a1; if (a2 > nrAntenna) nrAntenna = a2; } ++nrAntenna; _metaData.reset(new SpatialMatrixMetaData(nrAntenna)); const casacore::ArrayColumn flagColumn(table, "FLAG"); const casacore::ArrayColumn dataColumn(table, "DATA"); const casacore::ArrayColumn uvwColumn(table, "UVW"); Image2DPtr xxRImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), xxIImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), xyRImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), xyIImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yxRImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yxIImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yyRImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yyIImage = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna); Mask2DPtr xxMask = Mask2D::CreateUnsetMaskPtr(nrAntenna, nrAntenna), xyMask = Mask2D::CreateUnsetMaskPtr(nrAntenna, nrAntenna), yxMask = Mask2D::CreateUnsetMaskPtr(nrAntenna, nrAntenna), yyMask = Mask2D::CreateUnsetMaskPtr(nrAntenna, nrAntenna); for (size_t j = 0; j < table.nrow(); ++j) { int a1 = antenna1Column(j), a2 = antenna2Column(j); casacore::Array data = dataColumn(j); casacore::Array flags = flagColumn(j); casacore::Array::const_iterator i = data.begin(); casacore::Array::const_iterator fI = flags.begin(); num_t xxr = 0.0, xxi = 0.0, xyr = 0.0, xyi = 0.0, yxr = 0.0, yxi = 0.0, yyr = 0.0, yyi = 0.0; size_t xxc = 0, xyc = 0, yxc = 0, yyc = 0; for (size_t f = 0; f < (size_t)_frequencyCount; ++f) { const casacore::Complex& xx = *i; ++i; const casacore::Complex& xy = *i; ++i; const casacore::Complex& yx = *i; ++i; const casacore::Complex& yy = *i; ++i; const bool xxF = *fI; ++fI; const bool xyF = *fI; ++fI; const bool yxF = *fI; ++fI; const bool yyF = *fI; ++fI; if (std::isfinite(xxr) && std::isfinite(xxi) && !xxF) { xxr += xx.real(); xxi += xx.imag(); ++xxc; } if (std::isfinite(xyr) && std::isfinite(xyi) && !xyF) { xyr += xy.real(); xyi += xy.imag(); ++xyc; } if (std::isfinite(yxr) && std::isfinite(yxi) && !yxF) { yxr += yx.real(); yxi += yx.imag(); ++yxc; } if (std::isfinite(yyr) && std::isfinite(yyi) && !yyF) { yyr += yy.real(); yyi += yy.imag(); ++yyc; } } xxRImage->SetValue(a1, a2, xxr / xxc); xxIImage->SetValue(a1, a2, xxi / xxc); xyRImage->SetValue(a1, a2, xyr / xxc); xyIImage->SetValue(a1, a2, xyi / xxc); yxRImage->SetValue(a1, a2, yxr / xxc); yxIImage->SetValue(a1, a2, yxi / xxc); yyRImage->SetValue(a1, a2, yyr / xxc); yyIImage->SetValue(a1, a2, yyi / xxc); xxMask->SetValue(a1, a2, xxc == 0); xyMask->SetValue(a1, a2, xyc == 0); yxMask->SetValue(a1, a2, yxc == 0); yyMask->SetValue(a1, a2, yyc == 0); UVW uvw; casacore::Array arr = uvwColumn(j); casacore::Array::const_iterator uvwArrayIterator = arr.begin(); uvw.u = *uvwArrayIterator; ++uvwArrayIterator; uvw.v = *uvwArrayIterator; ++uvwArrayIterator; uvw.w = *uvwArrayIterator; _metaData->SetUVW(a1, a2, uvw); if (a1 != a2) { xxRImage->SetValue(a2, a1, xxr / xxc); xxIImage->SetValue(a2, a1, -xxi / xxc); xyRImage->SetValue(a2, a1, xyr / xxc); xyIImage->SetValue(a2, a1, -xyi / xxc); yxRImage->SetValue(a2, a1, yxr / xxc); yxIImage->SetValue(a2, a1, -yxi / xxc); yyRImage->SetValue(a2, a1, yyr / xxc); yyIImage->SetValue(a2, a1, -yyi / xxc); xxMask->SetValue(a2, a1, xxc == 0); xyMask->SetValue(a2, a1, xyc == 0); yxMask->SetValue(a2, a1, yxc == 0); yyMask->SetValue(a2, a1, yyc == 0); uvw.u = -uvw.u; uvw.v = -uvw.v; uvw.w = -uvw.w; _metaData->SetUVW(a2, a1, uvw); } } const casacore::ScalarColumn bandColumn(table, "DATA_DESC_ID"); const BandInfo band = _msMetaData.GetBandInfo(bandColumn(0)); _metaData->SetFrequency(band.CenterFrequencyHz()); TimeFrequencyData data = TimeFrequencyData::FromLinear(xxRImage, xxIImage, xyRImage, xyIImage, yxRImage, yxIImage, yyRImage, yyIImage); data.SetIndividualPolarizationMasks(xxMask, xyMask, yxMask, yyMask); return data; } void BaselineMatrixLoader::LoadPerChannel( size_t timeIndex, std::vector& data) { casacore::Block selectionNames(2); selectionNames[0] = "DATA_DESC_ID"; selectionNames[1] = "TIME"; if (timeIndex < _currentIterIndex) { _tableIter.reset(new casacore::TableIterator( *_sortedTable, selectionNames, casacore::TableIterator::Ascending, casacore::TableIterator::NoSort)); _currentIterIndex = 0; } while (!_tableIter->pastEnd() && timeIndex - _currentIterIndex > 0) { _tableIter->next(); ++_currentIterIndex; } if (_tableIter->pastEnd()) { throw std::runtime_error("Time index not found"); } const casacore::Table table = _tableIter->table(); const casacore::ROScalarColumn antenna1Column(table, "ANTENNA1"); const casacore::ROScalarColumn antenna2Column(table, "ANTENNA2"); // Find highest antenna index int nrAntenna = 0; for (size_t i = 0; i < table.nrow(); ++i) { int a1 = antenna1Column(i), a2 = antenna2Column(i); if (a1 > nrAntenna) nrAntenna = a1; if (a2 > nrAntenna) nrAntenna = a2; } ++nrAntenna; _metaData.reset(new SpatialMatrixMetaData(nrAntenna)); const casacore::ArrayColumn flagColumn(table, "FLAG"); const casacore::ArrayColumn dataColumn(table, "DATA"); const casacore::ArrayColumn uvwColumn(table, "UVW"); std::vector xxRImage(_frequencyCount), xxIImage(_frequencyCount), xyRImage(_frequencyCount), xyIImage(_frequencyCount), yxRImage(_frequencyCount), yxIImage(_frequencyCount), yyRImage(_frequencyCount), yyIImage(_frequencyCount); std::vector xxMask(_frequencyCount), xyMask(_frequencyCount), yxMask(_frequencyCount), yyMask(_frequencyCount); for (size_t f = 0; f < (size_t)_frequencyCount; ++f) { xxRImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), xxIImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), xyRImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), xyIImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yxRImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yxIImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yyRImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna), yyIImage[f] = Image2D::CreateZeroImagePtr(nrAntenna, nrAntenna); xxMask[f] = Mask2D::CreateSetMaskPtr(nrAntenna, nrAntenna), xyMask[f] = Mask2D::CreateSetMaskPtr(nrAntenna, nrAntenna), yxMask[f] = Mask2D::CreateSetMaskPtr(nrAntenna, nrAntenna), yyMask[f] = Mask2D::CreateSetMaskPtr(nrAntenna, nrAntenna); } for (size_t row = 0; row < table.nrow(); ++row) { int a1 = antenna1Column(row), a2 = antenna2Column(row); casacore::Array data = dataColumn(row); casacore::Array flags = flagColumn(row); casacore::Array::const_iterator i = data.begin(); casacore::Array::const_iterator fI = flags.begin(); for (size_t f = 0; f < (size_t)_frequencyCount; ++f) { const casacore::Complex xx = *i; ++i; const casacore::Complex xy = *i; ++i; const casacore::Complex yx = *i; ++i; const casacore::Complex yy = *i; ++i; bool xxF = *fI; ++fI; bool xyF = *fI; ++fI; bool yxF = *fI; ++fI; bool yyF = *fI; ++fI; if (!std::isfinite(xx.real()) || !std::isfinite(xx.imag())) xxF = true; if (!std::isfinite(xy.real()) || !std::isfinite(xy.imag())) xyF = true; if (!std::isfinite(yx.real()) || !std::isfinite(yx.imag())) yxF = true; if (!std::isfinite(yy.real()) || !std::isfinite(yy.imag())) yyF = true; xxRImage[f]->SetValue(a1, a2, xx.real()); xxIImage[f]->SetValue(a1, a2, xx.imag()); xyRImage[f]->SetValue(a1, a2, xy.real()); xyIImage[f]->SetValue(a1, a2, xy.imag()); yxRImage[f]->SetValue(a1, a2, yx.real()); yxIImage[f]->SetValue(a1, a2, yx.imag()); yyRImage[f]->SetValue(a1, a2, yy.real()); yyIImage[f]->SetValue(a1, a2, yy.imag()); xxMask[f]->SetValue(a1, a2, !xxF); xyMask[f]->SetValue(a1, a2, !xyF); yxMask[f]->SetValue(a1, a2, !yxF); yyMask[f]->SetValue(a1, a2, !yyF); if (a1 != a2) { xxRImage[f]->SetValue(a2, a1, xx.real()); xxIImage[f]->SetValue(a2, a1, -xx.imag()); xyRImage[f]->SetValue(a2, a1, xy.real()); xyIImage[f]->SetValue(a2, a1, -xy.imag()); yxRImage[f]->SetValue(a2, a1, yx.real()); yxIImage[f]->SetValue(a2, a1, -yx.imag()); yyRImage[f]->SetValue(a2, a1, yy.real()); yyIImage[f]->SetValue(a2, a1, -yy.imag()); xxMask[f]->SetValue(a2, a1, !xxF); xyMask[f]->SetValue(a2, a1, !xyF); yxMask[f]->SetValue(a2, a1, !yxF); yyMask[f]->SetValue(a2, a1, !yyF); } } UVW uvw; casacore::Array arr = uvwColumn(row); casacore::Array::const_iterator uvwArrayIterator = arr.begin(); uvw.u = *uvwArrayIterator; ++uvwArrayIterator; uvw.v = *uvwArrayIterator; ++uvwArrayIterator; uvw.w = *uvwArrayIterator; _metaData->SetUVW(a1, a2, uvw); if (a1 != a2) { uvw.u = -uvw.u; uvw.v = -uvw.v; uvw.w = -uvw.w; _metaData->SetUVW(a2, a1, uvw); } } const casacore::ScalarColumn bandColumn(table, "DATA_DESC_ID"); const BandInfo band = _msMetaData.GetBandInfo(bandColumn(0)); _metaData->SetFrequency(band.CenterFrequencyHz()); data.clear(); for (size_t f = 0; f < _frequencyCount; ++f) { TimeFrequencyData singleMatrix = TimeFrequencyData::FromLinear( xxRImage[f], xxIImage[f], xyRImage[f], xyIImage[f], yxRImage[f], yxIImage[f], yyRImage[f], yyIImage[f]); singleMatrix.SetIndividualPolarizationMasks(xxMask[f], xyMask[f], yxMask[f], yyMask[f]); data.push_back(singleMatrix); } } aoflagger-v3.4.0/msio/reorderingbaselinereader.cpp0000644000175000017500000005344614507760372021051 0ustar olesoles#include "reorderingbaselinereader.h" #include "../structures/timefrequencydata.h" #include "../util/logger.h" #include "../util/stopwatch.h" #include "../util/progress/dummyprogresslistener.h" #include "reorderedfilebuffer.h" #include "msselection.h" #include #include #include #include #include #include #include #include ReorderingBaselineReader::ReorderingBaselineReader(const std::string& msFile) : BaselineReader(msFile), direct_reader_(msFile), sequence_index_table_(), ms_is_reordered_(false), remove_reordered_files_(false), reordered_data_files_have_changed_(false), reordered_flag_files_have_changed_(false), read_uvw_(false) { // In order to use multiple readers at the same time the temporary files need // unique names. Use the address of the object to generate a unique prefix. const std::string uid = std::to_string(reinterpret_cast(this)); data_filename_ = uid + "-aoflagger-data.tmp"; flag_filename_ = uid + "-aoflagger-flag.tmp"; meta_filename_ = uid + "-ao-msinfo.tmp"; } ReorderingBaselineReader::~ReorderingBaselineReader() { WriteToMs(); removeTemporaryFiles(); } void ReorderingBaselineReader::WriteToMs() { DummyProgressListener dummy; if (reordered_data_files_have_changed_) updateOriginalMSData(dummy); if (reordered_flag_files_have_changed_) updateOriginalMSFlags(dummy); } void ReorderingBaselineReader::PrepareReadWrite(ProgressListener& progress) { if (!ms_is_reordered_) { reorderMS(progress); } } void ReorderingBaselineReader::PerformReadRequests( class ProgressListener& progress) { initializeMeta(); PrepareReadWrite(dummy_progress_); _results.clear(); for (size_t i = 0; i < _readRequests.size(); ++i) { const ReadRequest request = _readRequests[i]; _results.push_back(Result()); const size_t width = ObservationTimes(request.sequenceId).size(); for (size_t p = 0; p < Polarizations().size(); ++p) { if (ReadData()) { _results[i]._realImages.push_back(Image2D::CreateZeroImagePtr( width, MetaData().FrequencyCount(request.spectralWindow))); _results[i]._imaginaryImages.push_back(Image2D::CreateZeroImagePtr( width, MetaData().FrequencyCount(request.spectralWindow))); } if (ReadFlags()) { // The flags should be initialized to true, as a baseline might // miss some time scans that other baselines do have, and these // should be flagged. _results[i]._flags.push_back(Mask2D::CreateSetMaskPtr( width, MetaData().FrequencyCount(request.spectralWindow))); } } if (read_uvw_) { _results[i]._uvw = direct_reader_.ReadUVW(request.antenna1, request.antenna2, request.spectralWindow, request.sequenceId); } else { _results[i]._uvw.clear(); for (unsigned j = 0; j < width; ++j) _results[i]._uvw.emplace_back(0.0, 0.0, 0.0); } std::ifstream dataFile(data_filename_, std::ifstream::binary); std::ifstream flagFile(flag_filename_, std::ifstream::binary); const size_t index = sequence_index_table_->Value( request.antenna1, request.antenna2, request.spectralWindow, request.sequenceId); const size_t filePos = file_positions_[index]; dataFile.seekg(filePos * (sizeof(float) * 2), std::ios_base::beg); flagFile.seekg(filePos * sizeof(bool), std::ios_base::beg); const size_t bufferSize = MetaData().FrequencyCount(request.spectralWindow) * Polarizations().size(); for (size_t x = 0; x < width; ++x) { std::vector dataBuffer(bufferSize * 2); std::vector flagBuffer(bufferSize); dataFile.read((char*)&dataBuffer[0], bufferSize * sizeof(float) * 2); size_t dataBufferPtr = 0; flagFile.read((char*)&flagBuffer[0], bufferSize * sizeof(bool)); size_t flagBufferPtr = 0; for (size_t f = 0; f < MetaData().FrequencyCount(request.spectralWindow); ++f) { for (size_t p = 0; p < Polarizations().size(); ++p) { _results[i]._realImages[p]->SetValue(x, f, dataBuffer[dataBufferPtr]); ++dataBufferPtr; _results[i]._imaginaryImages[p]->SetValue(x, f, dataBuffer[dataBufferPtr]); ++dataBufferPtr; _results[i]._flags[p]->SetValue(x, f, flagBuffer[flagBufferPtr]); ++flagBufferPtr; } } } } _readRequests.clear(); progress.OnFinish(); } void ReorderingBaselineReader::PerformFlagWriteRequests() { for (size_t i = 0; i != _writeRequests.size(); ++i) { const FlagWriteRequest request = _writeRequests[i]; performFlagWriteTask(request.flags, request.antenna1, request.antenna2, request.spectralWindow, request.sequenceId); } _writeRequests.clear(); } void ReorderingBaselineReader::reorderMS(ProgressListener& progress) { initializeMeta(); progress.OnStartTask("Reordering measurement set"); const std::filesystem::path path(meta_filename_); bool reorderRequired = true; if (std::filesystem::exists(path)) { std::ifstream str(path.string().c_str()); std::string name; std::getline(str, name); if (std::filesystem::equivalent(std::filesystem::path(name), MetaData().Path())) { Logger::Debug << "Measurement set has already been reordered; using old " "temporary files.\n"; reorderRequired = false; ms_is_reordered_ = true; remove_reordered_files_ = false; reordered_data_files_have_changed_ = false; reordered_flag_files_have_changed_ = false; } } if (reorderRequired) { reorderFull(progress); std::ofstream str(path.string().c_str()); str << MetaData().Path() << '\n'; } else { size_t fileSize; makeLookupTables(fileSize); } } void ReorderingBaselineReader::makeLookupTables(size_t& fileSize) { std::vector sequences = MetaData().GetSequences(); const size_t antennaCount = MetaData().AntennaCount(), polarizationCount = Polarizations().size(), bandCount = MetaData().BandCount(), sequencesPerBaselineCount = MetaData().SequenceCount(); sequence_index_table_.reset(new SeqIndexLookupTable( antennaCount, bandCount, sequencesPerBaselineCount)); fileSize = 0; for (size_t i = 0; i < sequences.size(); ++i) { // Initialize look-up table to get index into Sequence-array quickly const MSMetaData::Sequence& s = sequences[i]; sequence_index_table_->Value(s.antenna1, s.antenna2, s.spw, s.sequenceId) = i; // Initialize look-up table to go from sequence array to file position. Is // in samples, so multiple times sizeof(bool) or ..(float)) for exact // position. file_positions_.push_back(fileSize); fileSize += ObservationTimes(s.sequenceId).size() * MetaData().FrequencyCount(s.spw) * polarizationCount; } } void ReorderingBaselineReader::preAllocate(const std::string& filename, size_t fileSize) { Logger::Debug << "Pre-allocating " << (fileSize / (1024 * 1024)) << " MB...\n"; const int fd = open(filename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR); if (fd < 0) { std::ostringstream s; s << "Error while opening file '" << filename << "', check access rights and free space"; throw std::runtime_error(s.str()); } #if defined(HAVE_POSIX_FALLOCATE) const int allocResult = posix_fallocate(fd, 0, fileSize); close(fd); if (allocResult != 0) { Logger::Warn << "Could not allocate temporary file '" << filename << "': posix_fallocate returned " << allocResult << ".\n" "Tried to allocate " << (fileSize / (1024 * 1024)) << " MB.\n" "Disk could be full or filesystem could not support fallocate.\n"; } #else close(fd); Logger::Warn << "Compiled without posix_fallocate() support: skipping " "pre-allocation.\n"; #endif } void ReorderingBaselineReader::reorderFull(ProgressListener& progressListener) { const Stopwatch watch(true); casacore::MeasurementSet ms = OpenMS(); casacore::ArrayColumn flagColumn(ms, "FLAG"); casacore::ScalarColumn dataDescIdColumn(ms, "DATA_DESC_ID"); casacore::ScalarColumn antenna1Column(ms, "ANTENNA1"); casacore::ScalarColumn antenna2Column(ms, "ANTENNA2"); casacore::ArrayColumn dataColumn(ms, DataColumnName()); if (ms.nrow() == 0) throw std::runtime_error("Measurement set is empty (zero rows)"); std::vector dataIdToSpw; MetaData().GetDataDescToBandVector(dataIdToSpw); size_t fileSize; makeLookupTables(fileSize); Logger::Debug << "Opening temporary files.\n"; ReorderInfo reorderInfo; preAllocate(data_filename_, fileSize * sizeof(float) * 2); reorderInfo.dataFile.reset(new std::ofstream( data_filename_, std::ofstream::binary | std::ios_base::in | std::ios_base::out)); if (reorderInfo.dataFile->fail()) throw std::runtime_error( "Error: failed to open temporary data files for writing! Check access " "rights and free disk space."); preAllocate(flag_filename_, fileSize * sizeof(bool)); reorderInfo.flagFile.reset(new std::ofstream( flag_filename_, std::ofstream::binary | std::ios_base::in | std::ios_base::out)); if (reorderInfo.flagFile->fail()) throw std::runtime_error( "Error: failed to open temporary data files for writing! Check access " "rights and free disk space."); Logger::Debug << "Reordering data set...\n"; const size_t bufferMem = std::min( aocommon::system::TotalMemory() / 10, 1024l * 1024l * 1024l); ReorderedFileBuffer dataFile(reorderInfo.dataFile.get(), bufferMem); ReorderedFileBuffer flagFile(reorderInfo.flagFile.get(), bufferMem / 8); std::vector writeFilePositions = file_positions_; std::vector timePositions(file_positions_.size(), size_t(-1)); size_t polarizationCount = Polarizations().size(); MSSelection msSelection(ms, ObservationTimesPerSequence(), progressListener); msSelection.Process( [&](size_t rowIndex, size_t sequenceId, size_t timeIndexInSequence) { size_t antenna1 = antenna1Column(rowIndex), antenna2 = antenna2Column(rowIndex), spw = dataIdToSpw[dataDescIdColumn(rowIndex)], channelCount = MetaData().FrequencyCount(spw), arrayIndex = sequence_index_table_->Value(antenna1, antenna2, spw, sequenceId), sampleCount = channelCount * polarizationCount; size_t& filePos = writeFilePositions[arrayIndex]; size_t& timePos = timePositions[arrayIndex]; casacore::Array data = dataColumn(rowIndex); casacore::Array flag = flagColumn(rowIndex); dataFile.seekp(filePos * (sizeof(float) * 2)); flagFile.seekp(filePos * sizeof(bool)); // If this baseline missed some time steps, pad the files // (we can't just skip over, because the flags should be set to true) ++timePos; while (timePos < timeIndexInSequence) { const std::vector nullData(sampleCount * 2, 0.0); const std::vector nullFlags(sampleCount, (char)true); dataFile.write(reinterpret_cast(&*nullData.begin()), sampleCount * 2 * sizeof(float)); flagFile.write(reinterpret_cast(&*nullFlags.begin()), sampleCount * sizeof(bool)); ++timePos; filePos += sampleCount; } dataFile.write(reinterpret_cast(&*data.cbegin()), sampleCount * 2 * sizeof(float)); flagFile.write(reinterpret_cast(&*flag.cbegin()), sampleCount * sizeof(bool)); filePos += sampleCount; }); const uint64_t dataSetSize = (uint64_t)fileSize * (uint64_t)(sizeof(float) * 2 + sizeof(bool)); Logger::Debug << "Done reordering data set of " << dataSetSize / (1024 * 1024) << " MB in " << watch.Seconds() << " s (" << (long double)dataSetSize / (1024.0L * 1024.0L * watch.Seconds()) << " MB/s)\n"; ms_is_reordered_ = true; remove_reordered_files_ = true; reordered_data_files_have_changed_ = false; reordered_flag_files_have_changed_ = false; } void ReorderingBaselineReader::removeTemporaryFiles() { if (ms_is_reordered_ && remove_reordered_files_) { std::filesystem::remove(meta_filename_); std::filesystem::remove(data_filename_); std::filesystem::remove(flag_filename_); Logger::Debug << "Temporary files removed.\n"; } ms_is_reordered_ = false; remove_reordered_files_ = false; reordered_data_files_have_changed_ = false; reordered_flag_files_have_changed_ = false; } void ReorderingBaselineReader::PerformDataWriteTask( std::vector _realImages, std::vector _imaginaryImages, size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId) { initializeMeta(); Logger::Debug << "Performing data write task with indirect baseline reader...\n"; const size_t polarizationCount = Polarizations().size(); if (_realImages.size() != polarizationCount || _imaginaryImages.size() != polarizationCount) throw std::runtime_error( "PerformDataWriteTask: input format did not match number of " "polarizations in measurement set"); for (size_t i = 1; i < _realImages.size(); ++i) { if (_realImages[0]->Width() != _realImages[i]->Width() || _realImages[0]->Height() != _realImages[i]->Height() || _realImages[0]->Width() != _imaginaryImages[i]->Width() || _realImages[0]->Height() != _imaginaryImages[i]->Height()) throw std::runtime_error( "PerformDataWriteTask: width and/or height of input images did not " "match"); } PrepareReadWrite(dummy_progress_); const size_t width = _realImages[0]->Width(); const size_t bufferSize = MetaData().FrequencyCount(spectralWindow) * Polarizations().size(); std::ofstream dataFile(data_filename_, std::ofstream::binary | std::ios_base::in | std::ios_base::out); const size_t index = sequence_index_table_->Value(antenna1, antenna2, spectralWindow, sequenceId); const size_t filePos = file_positions_[index]; dataFile.seekp(filePos * (sizeof(float) * 2), std::ios_base::beg); std::vector dataBuffer(bufferSize * 2); for (size_t x = 0; x < width; ++x) { size_t dataBufferPtr = 0; for (size_t f = 0; f < MetaData().FrequencyCount(spectralWindow); ++f) { for (size_t p = 0; p < Polarizations().size(); ++p) { dataBuffer[dataBufferPtr] = _realImages[p]->Value(x, f); ++dataBufferPtr; dataBuffer[dataBufferPtr] = _imaginaryImages[p]->Value(x, f); ++dataBufferPtr; } } dataFile.write(reinterpret_cast(&dataBuffer[0]), bufferSize * sizeof(float) * 2); if (dataFile.bad()) throw std::runtime_error( "Error: failed to update temporary data files! Check access rights " "and free disk space."); } reordered_data_files_have_changed_ = true; Logger::Debug << "Done writing.\n"; } void ReorderingBaselineReader::performFlagWriteTask( std::vector flags, unsigned antenna1, unsigned antenna2, unsigned spw, unsigned sequenceId) { initializeMeta(); const unsigned polarizationCount = Polarizations().size(); if (flags.size() != polarizationCount) throw std::runtime_error( "PerformDataWriteTask: input format did not match number of " "polarizations in measurement set"); for (size_t i = 1; i < flags.size(); ++i) { if (flags[0]->Width() != flags[i]->Width() || flags[0]->Height() != flags[i]->Height()) throw std::runtime_error( "PerformDataWriteTask: width and/or height of input images did not " "match"); } PrepareReadWrite(dummy_progress_); const size_t width = flags[0]->Width(); const size_t bufferSize = MetaData().FrequencyCount(spw) * Polarizations().size(); std::ofstream flagFile(flag_filename_, std::ofstream::binary | std::ios_base::in | std::ios_base::out); const size_t index = sequence_index_table_->Value(antenna1, antenna2, spw, sequenceId); const size_t filePos = file_positions_[index]; flagFile.seekp(filePos * (sizeof(bool)), std::ios_base::beg); const std::unique_ptr flagBuffer(new bool[bufferSize]); for (size_t x = 0; x < width; ++x) { size_t flagBufferPtr = 0; for (size_t f = 0; f < MetaData().FrequencyCount(spw); ++f) { for (size_t p = 0; p < polarizationCount; ++p) { flagBuffer[flagBufferPtr] = flags[p]->Value(x, f); ++flagBufferPtr; } } flagFile.write(reinterpret_cast(flagBuffer.get()), bufferSize * sizeof(bool)); if (flagFile.bad()) throw std::runtime_error( "Error: failed to update temporary flag files! Check access rights " "and free disk space."); } reordered_flag_files_have_changed_ = true; } template void ReorderingBaselineReader::updateOriginalMS(ProgressListener& progress) { casacore::MeasurementSet ms = OpenMS(); if (UpdateData || UpdateFlags) { ms.reopenRW(); } const casacore::ScalarColumn timeColumn(ms, "TIME"); const casacore::ScalarColumn antenna1Column(ms, "ANTENNA1"); const casacore::ScalarColumn antenna2Column(ms, "ANTENNA2"); const casacore::ScalarColumn fieldIdColumn(ms, "FIELD_ID"); const casacore::ScalarColumn dataDescIdColumn(ms, "DATA_DESC_ID"); casacore::ArrayColumn flagColumn(ms, "FLAG"); casacore::ArrayColumn dataColumn(ms, DataColumnName()); const std::vector sequences = MetaData().GetSequences(); std::vector dataIdToSpw; MetaData().GetDataDescToBandVector(dataIdToSpw); const size_t polarizationCount = Polarizations().size(); Logger::Debug << "Opening updated files\n"; UpdateInfo updateInfo; if (UpdateData) { updateInfo.dataFile.reset( new std::ifstream(data_filename_, std::ifstream::binary)); if (updateInfo.dataFile->fail()) throw std::runtime_error("Failed to open temporary data file"); } if (UpdateFlags) { updateInfo.flagFile.reset( new std::ifstream(flag_filename_, std::ifstream::binary)); if (updateInfo.flagFile->fail()) throw std::runtime_error("Failed to open temporary flag file"); } std::vector updatedFilePos = file_positions_; std::vector timePositions(updatedFilePos.size(), size_t(-1)); MSSelection msSelection(ms, ObservationTimesPerSequence(), progress); msSelection.Process([&](size_t rowIndex, size_t sequenceId, size_t timeIndexInSequence) { size_t antenna1 = antenna1Column(rowIndex), antenna2 = antenna2Column(rowIndex), spw = dataIdToSpw[dataDescIdColumn(rowIndex)], channelCount = MetaData().FrequencyCount(spw), arrayIndex = sequence_index_table_->Value(antenna1, antenna2, spw, sequenceId), sampleCount = channelCount * polarizationCount; size_t& filePos = updatedFilePos[arrayIndex]; size_t& timePos = timePositions[arrayIndex]; const casacore::IPosition shape(2, polarizationCount, channelCount); // Skip over samples in the temporary files that are missing in the // measurement set ++timePos; while (timePos < timeIndexInSequence) { filePos += sampleCount; ++timePos; } if (UpdateData) { casacore::Array data(shape); std::ifstream& dataFile = *updateInfo.dataFile; dataFile.seekg(filePos * (sizeof(float) * 2), std::ios_base::beg); dataFile.read(reinterpret_cast(&*data.cbegin()), sampleCount * 2 * sizeof(float)); if (dataFile.fail()) throw std::runtime_error("Error: failed to read temporary data files!"); dataColumn.basePut(rowIndex, data); } if (UpdateFlags) { casacore::Array flagArray(shape); std::ifstream& flagFile = *updateInfo.flagFile; flagFile.seekg(filePos * sizeof(bool), std::ios_base::beg); flagFile.read(reinterpret_cast(&*flagArray.cbegin()), sampleCount * sizeof(bool)); if (flagFile.fail()) throw std::runtime_error("Error: failed to read temporary flag files!"); flagColumn.basePut(rowIndex, flagArray); } filePos += sampleCount; }); Logger::Debug << "Freeing the data\n"; // Close the files updateInfo.dataFile.reset(); updateInfo.flagFile.reset(); if (UpdateData) Logger::Debug << "Done updating measurement set data\n"; if (UpdateFlags) Logger::Debug << "Done updating measurement set flags\n"; } void ReorderingBaselineReader::updateOriginalMSData( ProgressListener& progress) { Logger::Debug << "Data was changed, need to update the original MS...\n"; updateOriginalMS(progress); reordered_data_files_have_changed_ = false; } void ReorderingBaselineReader::updateOriginalMSFlags( ProgressListener& progress) { const Stopwatch watch(true); Logger::Debug << "Flags were changed, need to update the original MS...\n"; updateOriginalMS(progress); reordered_flag_files_have_changed_ = false; Logger::Debug << "Storing flags toke: " << watch.ToString() << '\n'; } aoflagger-v3.4.0/msio/spatialtimeloader.cpp0000644000175000017500000001255614507760372017523 0ustar olesoles#include "spatialtimeloader.h" #include #include #include #include #include "../util/logger.h" SpatialTimeLoader::SpatialTimeLoader(MSMetaData& msMetaData) : _msMetaData(msMetaData) { const casacore::Table rawTable(_msMetaData.Path()); casacore::Block names(4); names[0] = "DATA_DESC_ID"; names[1] = "TIME"; names[2] = "ANTENNA1"; names[3] = "ANTENNA2"; _sortedTable.reset(new casacore::Table(rawTable.sort(names))); _channelCount = _msMetaData.FrequencyCount(0); _timestepsCount = _msMetaData.TimestepCount(); _antennaCount = _msMetaData.AntennaCount(); _polarizationCount = _msMetaData.PolarizationCount(); casacore::Block selectionNames(1); selectionNames[0] = "DATA_DESC_ID"; _tableIter.reset(new casacore::TableIterator( *_sortedTable, selectionNames, casacore::TableIterator::Ascending, casacore::TableIterator::NoSort)); } SpatialTimeLoader::~SpatialTimeLoader() {} TimeFrequencyData SpatialTimeLoader::Load(unsigned channelIndex, bool fringeStop) { const unsigned baselineCount = _antennaCount * (_antennaCount - 1) / 2; const casacore::Table table = _tableIter->table(); const casacore::ScalarColumn antenna1Column(table, "ANTENNA1"); const casacore::ScalarColumn antenna2Column(table, "ANTENNA2"); const casacore::ScalarColumn timeColumn(table, "TIME"); const casacore::ArrayColumn uvwColumn(table, "UVW"); const casacore::ArrayColumn flagColumn(table, "FLAG"); const casacore::ArrayColumn dataColumn(table, "DATA"); std::vector realImages(_polarizationCount), imagImages(_polarizationCount); std::vector masks(_polarizationCount); for (unsigned p = 0; p < _polarizationCount; ++p) { realImages[p] = Image2D::CreateUnsetImagePtr(_timestepsCount, baselineCount); imagImages[p] = Image2D::CreateUnsetImagePtr(_timestepsCount, baselineCount); masks[p] = Mask2D::CreateUnsetMaskPtr(_timestepsCount, baselineCount); } const ChannelInfo channelInfo = _msMetaData.GetBandInfo(0).channels[channelIndex]; unsigned timeIndex = 0; double lastTime = timeColumn(0); for (unsigned row = 0; row < table.nrow(); ++row) { const int a1 = antenna1Column(row), a2 = antenna2Column(row); const double time = timeColumn(row); if (time != lastTime) { timeIndex++; lastTime = time; } if (a1 != a2) { const casacore::Array data = dataColumn(row); const casacore::Array flags = flagColumn(row); const casacore::Array uvws = uvwColumn(row); casacore::Array::const_iterator i = data.begin(); casacore::Array::const_iterator fI = flags.begin(); casacore::Array::const_iterator uvwIter = uvws.begin(); ++uvwIter; ++uvwIter; const double wRotation = -channelInfo.MetersToLambda(*uvwIter) * M_PI * 2.0; const unsigned baselineIndex = baselineCount - (_antennaCount - a1) * (_antennaCount - a1 - 1) / 2 + a2 - a1 - 1; for (unsigned c = 0; c < _channelCount; ++c) { if (c == channelIndex) { Logger::Debug << "Reading timeIndex=" << timeIndex << ", baselineIndex=" << baselineIndex << ", a1=" << a1 << ", a2=" << a2 << ",w=" << wRotation << "\n"; for (unsigned p = 0; p < _polarizationCount; ++p) { double realValue = i->real(); double imagValue = i->imag(); if (fringeStop) { const double newRealValue = realValue * cosn(wRotation) - imagValue * sinn(wRotation); imagValue = realValue * sinn(wRotation) + imagValue * cosn(wRotation); realValue = newRealValue; } realImages[p]->SetValue(timeIndex, baselineIndex, realValue); imagImages[p]->SetValue(timeIndex, baselineIndex, imagValue); ++i; masks[p]->SetValue(timeIndex, baselineIndex, *fI); ++fI; } } else { for (unsigned p = 0; p < _polarizationCount; ++p) { ++i; ++fI; } } } } } const casacore::ROScalarColumn bandColumn(table, "DATA_DESC_ID"); const BandInfo band = _msMetaData.GetBandInfo(bandColumn(0)); TimeFrequencyData data; if (_polarizationCount == 4) { data = TimeFrequencyData::FromLinear( realImages[0], imagImages[0], realImages[1], imagImages[1], realImages[2], imagImages[2], realImages[3], imagImages[3]); data.SetIndividualPolarizationMasks(masks[0], masks[1], masks[2], masks[3]); } else if (_polarizationCount == 2) { data = TimeFrequencyData(aocommon::Polarization::XX, realImages[0], imagImages[0], aocommon::Polarization::YY, realImages[1], imagImages[1]); data.SetIndividualPolarizationMasks(masks[0], masks[1]); } else if (_polarizationCount == 1) { data = TimeFrequencyData(aocommon::Polarization::StokesI, realImages[0], imagImages[0]); data.SetGlobalMask(masks[0]); } else { throw std::runtime_error("Unknown number of polarizations!"); } return data; } aoflagger-v3.4.0/msio/directbaselinereader.h0000644000175000017500000000666314507760372017627 0ustar olesoles#ifndef DIRECTBASELINEREADER_H #define DIRECTBASELINEREADER_H #include #include #include #include "baselinereader.h" #include "../structures/antennainfo.h" #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../structures/msmetadata.h" class DirectBaselineReader final : public BaselineReader { public: explicit DirectBaselineReader(const std::string& msFile); bool IsModified() const override { return false; } void WriteToMs() override {} void PrepareReadWrite(ProgressListener&) override {} void PerformReadRequests(class ProgressListener& listener) override; void PerformFlagWriteRequests() override; void PerformDataWriteTask( [[maybe_unused]] std::vector realImages, [[maybe_unused]] std::vector imaginaryImages, [[maybe_unused]] size_t antenna1, [[maybe_unused]] size_t antenna2, [[maybe_unused]] size_t spectralWindow, [[maybe_unused]] size_t sequenceId) override { throw std::runtime_error( "The direct baseline reader can not write data back to file: use the " "indirect reader"); } std::vector ReadUVW(unsigned antenna1, unsigned antenna2, unsigned spectralWindow, unsigned sequenceId); private: class BaselineCacheIndex { public: BaselineCacheIndex() {} BaselineCacheIndex(const BaselineCacheIndex& source) : antenna1(source.antenna1), antenna2(source.antenna2), spectralWindow(source.spectralWindow), sequenceId(source.sequenceId) {} bool operator==(const BaselineCacheIndex& rhs) const { return antenna1 == rhs.antenna1 && antenna2 == rhs.antenna2 && spectralWindow == rhs.spectralWindow && sequenceId == rhs.sequenceId; } bool operator<(const BaselineCacheIndex& rhs) const { if (antenna1 < rhs.antenna1) { return true; } else if (antenna1 == rhs.antenna1) { if (antenna2 < rhs.antenna2) { return true; } else if (antenna2 == rhs.antenna2) { if (spectralWindow < rhs.spectralWindow) return true; else if (spectralWindow == rhs.spectralWindow) return sequenceId < rhs.sequenceId; } } return false; } size_t antenna1, antenna2, spectralWindow, sequenceId; }; struct BaselineCacheValue { std::vector rows; }; void initBaselineCache(); void addRequestRows(ReadRequest request, size_t requestIndex, std::vector>& rows); void addRequestRows(FlagWriteRequest request, size_t requestIndex, std::vector>& rows); void addRowToBaselineCache(size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId, size_t row); void readUVWData(); void readTimeData(size_t requestIndex, size_t xOffset, size_t frequencyCount, const casacore::Array& data); void readTimeFlags(size_t requestIndex, size_t xOffset, size_t frequencyCount, const casacore::Array& flag); void readWeights(size_t requestIndex, size_t xOffset, size_t frequencyCount, const casacore::Array& weight); std::map _baselineCache; casacore::MeasurementSet _ms; }; #endif // DIRECTBASELINEREADER_H aoflagger-v3.4.0/msio/rspreader.cpp0000644000175000017500000003256114507760372016005 0ustar olesoles#include #include #include #include "rspreader.h" #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../structures/samplerow.h" #include "../util/logger.h" #include "../util/ffttools.h" const unsigned char RSPReader::BitReverseTable256[256] = { #define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64 #define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16) #define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4) R6(0), R6(2), R6(1), R6(3)}; const unsigned long RSPReader::STATION_INTEGRATION_STEPS = 1024; const unsigned int RSPReader::RCPBeamletData::SIZE = 8; const unsigned int RSPReader::RCPApplicationHeader::SIZE = 16; std::pair RSPReader::ReadChannelBeamlet(unsigned long timestepStart, unsigned long timestepEnd, unsigned beamletCount, unsigned beamletIndex) { const unsigned width = timestepEnd - timestepStart; std::pair data = ReadSingleBeamlet(timestepStart * (unsigned long)256, timestepEnd * (unsigned long)256, beamletCount, beamletIndex); const TimeFrequencyData allX = data.first.Make(aocommon::Polarization::XX); const TimeFrequencyData allY = data.first.Make(aocommon::Polarization::YY); const Image2DCPtr xr = allX.GetRealPart(); const Image2DCPtr xi = allX.GetImaginaryPart(); const Image2DCPtr yr = allY.GetRealPart(); const Image2DCPtr yi = allY.GetImaginaryPart(); const Mask2DCPtr mask = data.first.GetSingleMask(); Image2DPtr outXR = Image2D::CreateUnsetImagePtr(width, 256), outXI = Image2D::CreateUnsetImagePtr(width, 256), outYR = Image2D::CreateUnsetImagePtr(width, 256), outYI = Image2D::CreateUnsetImagePtr(width, 256); const Mask2DPtr outMask = Mask2D::CreateUnsetMaskPtr(width, 256); std::vector observationTimes; for (unsigned long timestep = 0; timestep < timestepEnd - timestepStart; ++timestep) { const unsigned long timestepIndex = timestep * 256; SampleRow realX = SampleRow::MakeFromRow(xr.get(), timestepIndex, 256, 0), imaginaryX = SampleRow::MakeFromRow(xi.get(), timestepIndex, 256, 0), realY = SampleRow::MakeFromRow(yr.get(), timestepIndex, 256, 0), imaginaryY = SampleRow::MakeFromRow(yi.get(), timestepIndex, 256, 0); FFTTools::FFT(realX, imaginaryX); FFTTools::FFT(realY, imaginaryY); realX.SetVerticalImageValues(outXR.get(), timestep); imaginaryX.SetVerticalImageValues(outXI.get(), timestep); realY.SetVerticalImageValues(outYR.get(), timestep); imaginaryY.SetVerticalImageValues(outYI.get(), timestep); observationTimes.push_back( data.second->ObservationTimes()[timestepIndex + 256 / 2]); size_t validValues = 0; for (unsigned y = 0; y < 256; ++y) { if (!mask->Value(timestepIndex + y, 0)) ++validValues; } for (unsigned y = 0; y < 256; ++y) { outMask->SetValue(timestep, y, validValues == 0); } } data.first = TimeFrequencyData(aocommon::Polarization::XX, outXR, outXI, aocommon::Polarization::YY, outYR, outYI); data.first.SetGlobalMask(outMask); BandInfo band = data.second->Band(); band.channels.clear(); for (unsigned i = 0; i < 256; ++i) { ChannelInfo channel; channel.frequencyHz = i + 1; channel.frequencyIndex = i; band.channels.push_back(channel); } data.second->SetBand(band); data.second->SetObservationTimes(observationTimes); return data; } std::pair RSPReader::ReadSingleBeamlet(unsigned long timestepStart, unsigned long timestepEnd, unsigned beamletCount, unsigned beamletIndex) { std::pair data = ReadAllBeamlets(timestepStart, timestepEnd, beamletCount); const unsigned width = timestepEnd - timestepStart; const Image2DPtr realX = Image2D::CreateZeroImagePtr(width, 1); const Image2DPtr imaginaryX = Image2D::CreateZeroImagePtr(width, 1); const Image2DPtr realY = Image2D::CreateZeroImagePtr(width, 1); const Image2DPtr imaginaryY = Image2D::CreateZeroImagePtr(width, 1); const Mask2DPtr mask = Mask2D::CreateUnsetMaskPtr(width, 1); const TimeFrequencyData allX = data.first.Make(aocommon::Polarization::XX); const TimeFrequencyData allY = data.first.Make(aocommon::Polarization::YY); const Image2DCPtr xr = allX.GetRealPart(); const Image2DCPtr xi = allX.GetImaginaryPart(); const Image2DCPtr yr = allY.GetRealPart(); const Image2DCPtr yi = allY.GetImaginaryPart(); const Mask2DCPtr maskWithBeamlets = data.first.GetSingleMask(); for (unsigned x = 0; x < width; ++x) { realX->SetValue(x, 0, xr->Value(x, beamletIndex)); imaginaryX->SetValue(x, 0, xi->Value(x, beamletIndex)); realY->SetValue(x, 0, yr->Value(x, beamletIndex)); imaginaryY->SetValue(x, 0, yi->Value(x, beamletIndex)); mask->SetValue(x, 0, maskWithBeamlets->Value(x, beamletIndex)); } data.first = TimeFrequencyData(aocommon::Polarization::XX, realX, imaginaryX, aocommon::Polarization::YY, realY, imaginaryY); data.first.SetGlobalMask(mask); BandInfo band = data.second->Band(); band.channels[0] = data.second->Band().channels[beamletIndex]; band.channels.resize(1); data.second->SetBand(band); return data; } unsigned long RSPReader::TimeStepCount(size_t beamletCount) const { std::ifstream stream(_rawFile.c_str(), std::ios_base::binary | std::ios_base::in); stream.seekg(0, std::ios_base::end); const unsigned long fileSize = stream.tellg(); stream.seekg(0, std::ios_base::beg); RCPApplicationHeader firstHeader; firstHeader.Read(stream); const unsigned long bytesPerFrame = beamletCount * firstHeader.nofBlocks * RCPBeamletData::SIZE + RCPApplicationHeader::SIZE; const unsigned long frames = fileSize / bytesPerFrame; Logger::Debug << "File has " << frames << " number of frames (" << ((double)(frames * firstHeader.nofBlocks * STATION_INTEGRATION_STEPS) / _clockSpeed) << "s of data)\n"; return frames * firstHeader.nofBlocks; } std::pair RSPReader::ReadAllBeamlets(unsigned long timestepStart, unsigned long timestepEnd, unsigned beamletCount) { const unsigned width = timestepEnd - timestepStart; const Image2DPtr realX = Image2D::CreateZeroImagePtr(width, beamletCount); const Image2DPtr imaginaryX = Image2D::CreateZeroImagePtr(width, beamletCount); const Image2DPtr realY = Image2D::CreateZeroImagePtr(width, beamletCount); const Image2DPtr imaginaryY = Image2D::CreateZeroImagePtr(width, beamletCount); const Mask2DPtr mask = Mask2D::CreateSetMaskPtr(width, beamletCount); std::ifstream file(_rawFile.c_str(), std::ios_base::binary | std::ios_base::in); size_t frame = 0; std::set stations; const TimeFrequencyMetaDataPtr metaData = TimeFrequencyMetaDataPtr(new TimeFrequencyMetaData()); BandInfo band; for (size_t i = 0; i < beamletCount; ++i) { ChannelInfo channel; channel.frequencyHz = i + 1; channel.frequencyIndex = i; band.channels.push_back(channel); } metaData->SetBand(band); std::vector observationTimes; // Read a header and determine the reading start position // Because timestepStart might fall within a block, the RCPApplicationHeader firstHeader; firstHeader.Read(file); const unsigned long bytesPerFrame = beamletCount * firstHeader.nofBlocks * RCPBeamletData::SIZE + RCPApplicationHeader::SIZE; const unsigned long startFrame = timestepStart / (unsigned long)firstHeader.nofBlocks; const unsigned long startByte = startFrame * bytesPerFrame; const unsigned long offsetFromStart = timestepStart - (startFrame * firstHeader.nofBlocks); // Logger::Debug << "Seeking to " << startByte << " (timestepStart=" << // timestepStart << ", offsetFromStart=" << offsetFromStart << ", startFrame=" // << startFrame << ",bytesPerFrame=" << bytesPerFrame << ")\n"; file.seekg(startByte, std::ios_base::beg); // Read the frames unsigned long x = 0; while (x < width + offsetFromStart && file.good()) { RCPApplicationHeader header; header.Read(file); if (header.versionId != 2) { std::stringstream s; s << "Corrupted header found in frame " << frame << "!"; throw std::runtime_error(s.str()); } if (stations.count(header.stationId) == 0) { stations.insert(header.stationId); AntennaInfo antenna; std::stringstream s; s << "LOFAR station with index " << header.stationId; antenna.name = s.str(); metaData->SetAntenna1(antenna); metaData->SetAntenna2(antenna); } for (size_t j = 0; j < beamletCount; ++j) { for (size_t i = 0; i < header.nofBlocks; ++i) { RCPBeamletData data; data.Read(file); if (i + x < width + offsetFromStart && i + x >= offsetFromStart) { const unsigned long pos = i + x - offsetFromStart; realX->SetValue(pos, j, data.xr); imaginaryX->SetValue(pos, j, data.xi); realY->SetValue(pos, j, data.yr); imaginaryY->SetValue(pos, j, data.yi); mask->SetValue(pos, j, false); } } } x += header.nofBlocks; ++frame; } // Logger::Debug << "Read " << frame << " frames.\n"; for (unsigned long i = 0; i < width; ++i) { const unsigned long pos = i + timestepStart; const double time = (double)pos * (double)STATION_INTEGRATION_STEPS / (double)_clockSpeed; observationTimes.push_back(time); } metaData->SetObservationTimes(observationTimes); std::pair data; data.first = TimeFrequencyData(aocommon::Polarization::XX, realX, imaginaryX, aocommon::Polarization::YY, realY, imaginaryY); data.first.SetGlobalMask(mask); data.second = metaData; return data; } void RSPReader::ReadForStatistics(unsigned beamletCount) { const long unsigned timesteps = TimeStepCount(beamletCount); const long unsigned stepSize = 1024; std::vector statistics(beamletCount), timeStartStatistics(beamletCount); std::vector statFile(beamletCount); for (unsigned i = 0; i < beamletCount; ++i) { std::ostringstream str; str << "rsp-statistics" << i << ".txt"; statFile[i] = new std::ofstream(str.str().c_str()); } double startTime = -1.0, periodStartTime = -1.0; for (unsigned long timestepIndex = 0; timestepIndex < timesteps; timestepIndex += stepSize) { // Read the data unsigned long end = timestepIndex + stepSize; if (end > timesteps) end = timesteps; const std::pair dataPair = ReadAllBeamlets(timestepIndex, end, beamletCount); const TimeFrequencyData& data = dataPair.first; if (startTime == -1.0) { startTime = dataPair.second->ObservationTimes()[0]; periodStartTime = startTime; } // Count the statistics for (unsigned imageIndex = 0; imageIndex < data.ImageCount(); ++imageIndex) { const Image2DCPtr image = data.GetImage(imageIndex); for (unsigned y = 0; y < image->Height(); ++y) { for (unsigned x = 0; x < image->Width(); ++x) { int value = (int)image->Value(x, y); if (value < 0) { value = -value; ++(statistics[y].bitUseCount[15]); } unsigned highestBit = (value != 0) ? 1 : 0; for (unsigned bit = 0; bit < 15; ++bit) { if ((value & (2 << bit)) != 0) { highestBit = bit + 1; } } for (unsigned bit = 0; bit < highestBit; ++bit) ++(statistics[y].bitUseCount[bit]); ++(statistics[y].totalCount); } } } if ((timestepIndex / stepSize) % 100000 == 0 || timestepIndex + stepSize >= timesteps) { for (unsigned i = 0; i < beamletCount; ++i) { Logger::Info << "Beamlet index " << i << ":\n"; statistics[i].Print(); } } if ((dataPair.second->ObservationTimes()[0] - periodStartTime) > 60.0) { Logger::Debug << "Processed 1 minute of data (" << (dataPair.second->ObservationTimes()[0] - startTime) << "s)\n"; for (unsigned i = 0; i < beamletCount; ++i) { (*statFile[i]) << (periodStartTime - startTime) << '\t' << (statistics[i].totalCount - timeStartStatistics[i].totalCount); statistics[i].totalCount = timeStartStatistics[i].totalCount; for (unsigned bit = 0; bit < 15; ++bit) { (*statFile[i]) << '\t' << (statistics[i].bitUseCount[bit] - timeStartStatistics[i].bitUseCount[bit]); timeStartStatistics[i].bitUseCount[bit] = statistics[i].bitUseCount[bit]; } (*statFile[i]) << '\n'; } periodStartTime = dataPair.second->ObservationTimes()[0]; } } for (unsigned i = 0; i < beamletCount; ++i) { Logger::Info << "Beamlet index " << i << ":\n"; statistics[i].Print(); delete statFile[i]; } } aoflagger-v3.4.0/msio/msstatreader.h0000644000175000017500000000773314507760372016164 0ustar olesoles#ifndef MS_STAT_READER_H #define MS_STAT_READER_H #include #include #include #include #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "../imagesets/msoptions.h" namespace aocommon { class MultiBandData; } class MSStatReader { public: MSStatReader(const std::string& filename, const std::string& dataColumn); size_t NSequences() const { return _sequenceStart.size() - 1; } size_t NBands() const { return _nBands; } typedef std::pair Result; Result Read(BaselineIntegration::Mode statType, BaselineIntegration::Differencing diffType, size_t sequenceIndex, size_t bandIndex, bool includeAutos, bool includeFlags, class ProgressListener& progress) { switch (diffType) { default: case BaselineIntegration::NoDifference: return readSamples(statType, sequenceIndex, bandIndex, includeAutos, includeFlags, false, progress); case BaselineIntegration::TimeDifference: return readTimeDiff(statType, sequenceIndex, bandIndex, includeAutos, includeFlags, progress); case BaselineIntegration::FrequencyDifference: return readSamples(statType, sequenceIndex, bandIndex, includeAutos, includeFlags, true, progress); } } std::string TelescopeName() const { return _telescopeName; } void StoreFlags(const std::vector& flags, BaselineIntegration::Differencing diffType, size_t sequenceIndex, size_t bandIndex, bool includeAutos); private: Result readSamples(BaselineIntegration::Mode statType, size_t sequenceIndex, size_t bandIndex, bool includeAutos, bool includeFlags, bool freqDiff, ProgressListener& progress); Result readTimeDiff(BaselineIntegration::Mode statType, size_t sequenceIndex, size_t bandIndex, bool includeAutos, bool includeFlags, ProgressListener& progress); void fillBand(MSStatReader::Result& result, bool freqDiff, const aocommon::MultiBandData& bands, size_t bandIndex); struct Statistic { double data1 = 0.0, data2 = 0.0, data3 = 0.0; size_t count = 0; void Add(BaselineIntegration::Mode stat, std::complex sample) { ++count; switch (stat) { case BaselineIntegration::Count: break; case BaselineIntegration::Average: data1 += sample.real(); break; case BaselineIntegration::AverageAbs: data1 += std::abs(sample); break; case BaselineIntegration::Squared: data1 += std::norm(sample); break; case BaselineIntegration::Stddev: data1 += sample.real(); data2 += sample.imag(); data3 += std::norm(sample); break; } } double Calculate(BaselineIntegration::Mode stat) const { switch (stat) { case BaselineIntegration::Count: return count; case BaselineIntegration::Average: case BaselineIntegration::AverageAbs: case BaselineIntegration::Squared: return data1 / count; case BaselineIntegration::Stddev: { double normMeanSq = std::norm(std::complex(data1, data2) / double(count)); return std::sqrt(data3 / count - normMeanSq); } } return 0.0; } }; Result makeResult(BaselineIntegration::Mode statType, const Statistic* statsData, size_t nPolarizations, size_t nChannels, size_t nTimes); void storeFlags(const std::vector& flags, size_t sequenceIndex, size_t bandIndex, bool includeAutos); const std::string _filename; const std::string _dataColumn; size_t _nBands; std::vector _sequenceStart; std::string _telescopeName; }; #endif aoflagger-v3.4.0/msio/fitsfile.cpp0000644000175000017500000004327314507760372015625 0ustar olesoles#include "fitsfile.h" #include #include #include #include #include #include "../util/logger.h" FitsFile::FitsFile(const std::string& filename) : _filename(filename), _fptr(nullptr), _isOpen(false) {} FitsFile::~FitsFile() { if (_isOpen) Close(); } void FitsFile::CheckStatus(int status) const { if (status) { /* fits_get_errstatus returns at most 30 characters */ char err_text[31]; fits_get_errstatus(status, err_text); char err_msg[81]; std::stringstream errMsg; errMsg << "CFITSIO reported error when performing IO on file '" << _filename << "':" << err_text << " ("; while (fits_read_errmsg(err_msg)) errMsg << err_msg; errMsg << ')'; throw FitsIOException(errMsg.str()); } } void FitsFile::CheckOpen() const { if (!_isOpen) throw FitsIOException("No open file, call Open() first"); } void FitsFile::Open(FitsFile::FileMode mode) { if (_isOpen) { throw FitsIOException("File was opened twice"); } else { int status = 0; int modeInt = 0; switch (mode) { case ReadOnlyMode: modeInt = READONLY; break; case ReadWriteMode: modeInt = READWRITE; break; default: throw FitsIOException("Incorrect mode specified"); break; } fits_open_diskfile(&_fptr, _filename.c_str(), modeInt, &status); CheckStatus(status); _isOpen = true; } } void FitsFile::Create() { if (_isOpen) { throw FitsIOException("File was opened twice"); } else { int status = 0; fits_create_file(&_fptr, (std::string("!") + _filename).c_str(), &status); CheckStatus(status); _isOpen = true; } } void FitsFile::Close() { if (_isOpen) { int status = 0; fits_close_file(_fptr, &status); CheckStatus(status); _isOpen = false; _fptr = nullptr; } else { throw FitsIOException("Non-opened file was closed"); } } int FitsFile::GetHDUCount() { CheckOpen(); int hdunum = 0, status = 0; fits_get_num_hdus(_fptr, &hdunum, &status); CheckStatus(status); return hdunum; } int FitsFile::GetCurrentHDU() { CheckOpen(); int hdunum = 0; fits_get_hdu_num(_fptr, &hdunum); return hdunum; } void FitsFile::MoveToHDU(int hduNumber) { CheckOpen(); int status = 0; fits_movabs_hdu(_fptr, hduNumber, nullptr, &status); CheckStatus(status); } enum FitsFile::HDUType FitsFile::GetCurrentHDUType() { CheckOpen(); int hdutypeInt = 0, status = 0; fits_get_hdu_type(_fptr, &hdutypeInt, &status); CheckStatus(status); enum HDUType hduType; switch (hdutypeInt) { case IMAGE_HDU: hduType = ImageHDUType; break; case ASCII_TBL: hduType = ASCIITableHDUType; break; case BINARY_TBL: hduType = BinaryTableHDUType; break; default: throw FitsIOException("Unknown HDUType returned"); } return hduType; } enum FitsFile::ImageType FitsFile::GetCurrentImageType() { CheckOpen(); int bitPixInt = 0, status = 0; fits_get_img_type(_fptr, &bitPixInt, &status); CheckStatus(status); enum ImageType imageType; switch (bitPixInt) { case BYTE_IMG: imageType = Int8ImageType; break; case SHORT_IMG: imageType = Int16ImageType; break; case LONG_IMG: imageType = Int32ImageType; break; case FLOAT_IMG: imageType = Float32ImageType; break; case DOUBLE_IMG: imageType = Double64ImageType; break; default: throw FitsIOException("Unknown image type returned"); } return imageType; } int FitsFile::GetCurrentImageDimensionCount() { CheckOpen(); int status = 0, naxis = 0; fits_get_img_dim(_fptr, &naxis, &status); CheckStatus(status); return naxis; } long FitsFile::GetCurrentImageSize(int dimension) { CheckOpen(); if (dimension > GetCurrentImageDimensionCount()) throw FitsIOException("Parameter outside range"); int status = 0; long* sizes = new long[dimension]; fits_get_img_size(_fptr, dimension, sizes, &status); const long size = sizes[dimension - 1]; delete[] sizes; CheckStatus(status); return size; } void FitsFile::ReadCurrentImageData(long startPos, num_t* buffer, long bufferSize, long double nullValue) { CheckOpen(); int status = 0, dimensions = GetCurrentImageDimensionCount(); long* firstpixel = new long[dimensions]; for (int i = 0; i < dimensions; i++) { firstpixel[i] = 1 + startPos % GetCurrentImageSize(i + 1); startPos = startPos / GetCurrentImageSize(i + 1); } double* dblbuffer = new double[bufferSize]; double dblNullValue = nullValue; int anynul = 0; fits_read_pix(_fptr, TDOUBLE, firstpixel, bufferSize, &dblNullValue, dblbuffer, &anynul, &status); for (int i = 0; i < bufferSize; i++) buffer[i] = dblbuffer[i]; delete[] dblbuffer; delete[] firstpixel; CheckStatus(status); } void FitsFile::AppendImageHUD(enum FitsFile::ImageType imageType, long width, long height) { int status = 0; int bitPixInt; switch (imageType) { case Int8ImageType: bitPixInt = BYTE_IMG; break; case Int16ImageType: bitPixInt = SHORT_IMG; break; case Int32ImageType: bitPixInt = LONG_IMG; break; case Float32ImageType: bitPixInt = FLOAT_IMG; break; case Double64ImageType: bitPixInt = DOUBLE_IMG; break; default: throw FitsIOException("?"); } long* naxes = new long[2]; naxes[0] = width; naxes[1] = height; fits_create_img(_fptr, bitPixInt, 2, naxes, &status); delete[] naxes; CheckStatus(status); } void FitsFile::WriteImage(long startPos, double* buffer, long bufferSize, double nullValue) { CheckOpen(); int status = 0, dimensions = GetCurrentImageDimensionCount(); long* firstpixel = new long[dimensions]; for (int i = 0; i < dimensions; i++) { firstpixel[i] = 1 + startPos % GetCurrentImageSize(i + 1); startPos = startPos / GetCurrentImageSize(i + 1); } fits_write_pixnull(_fptr, TDOUBLE, firstpixel, bufferSize, buffer, &nullValue, &status); delete[] firstpixel; CheckStatus(status); } void FitsFile::WriteImage(long startPos, float* buffer, long bufferSize, float nullValue) { CheckOpen(); int status = 0, dimensions = GetCurrentImageDimensionCount(); long* firstpixel = new long[dimensions]; for (int i = 0; i < dimensions; i++) { firstpixel[i] = 1 + startPos % GetCurrentImageSize(i + 1); startPos = startPos / GetCurrentImageSize(i + 1); } fits_write_pixnull(_fptr, TFLOAT, firstpixel, bufferSize, buffer, &nullValue, &status); delete[] firstpixel; CheckStatus(status); } int FitsFile::GetRowCount() { CheckOpen(); long rowCount; int status = 0; fits_get_num_rows(_fptr, &rowCount, &status); CheckStatus(status); return rowCount; } int FitsFile::GetKeywordCount() { int status = 0, keysexist; fits_get_hdrspace(_fptr, &keysexist, nullptr, &status); CheckStatus(status); return keysexist; } std::string FitsFile::GetKeyword(int keywordNumber) { char keyName[FLEN_KEYWORD], keyValue[FLEN_VALUE]; int status = 0; fits_read_keyn(_fptr, keywordNumber, keyName, keyValue, nullptr, &status); CheckStatus(status); return std::string(keyName); } std::string FitsFile::GetKeywordValue(int keywordNumber) { char keyName[FLEN_KEYWORD], keyValue[FLEN_VALUE]; int status = 0; fits_read_keyn(_fptr, keywordNumber, keyName, keyValue, nullptr, &status); CheckStatus(status); std::string val(keyValue); if (val.length() >= 2 && *val.begin() == '\'' && *val.rbegin() == '\'') { val = val.substr(1, val.length() - 2); boost::trim(val); } return val; } bool FitsFile::GetKeywordValue(const std::string& keywordName, std::string& value) { char keyValue[FLEN_VALUE]; int status = 0; fits_read_keyword(_fptr, const_cast(keywordName.c_str()), keyValue, nullptr, &status); if (status == 0) { value = std::string(keyValue); if (value.length() >= 2 && *value.begin() == '\'' && *value.rbegin() == '\'') { value = value.substr(1, value.length() - 2); boost::trim(value); } return true; } else { return false; } } std::string FitsFile::GetKeywordValue(const std::string& keywordName) { char keyValue[FLEN_VALUE]; int status = 0; fits_read_keyword(_fptr, const_cast(keywordName.c_str()), keyValue, nullptr, &status); CheckStatus(status); std::string val(keyValue); if (val.length() >= 2 && *val.begin() == '\'' && *val.rbegin() == '\'') { val = val.substr(1, val.length() - 2); boost::trim(val); } return val; } std::string FitsFile::GetKeywordComment(int keywordNumber) { char keyName[FLEN_KEYWORD], keyValue[FLEN_VALUE], keyComment[FLEN_COMMENT]; int status = 0; fits_read_keyn(_fptr, keywordNumber, keyName, keyValue, keyComment, &status); CheckStatus(status); return std::string(keyComment); } int FitsFile::GetColumnCount() { CheckOpen(); int rowCount, status = 0; fits_get_num_cols(_fptr, &rowCount, &status); CheckStatus(status); return rowCount; } int FitsFile::GetColumnType(int colNumber) { CheckOpen(); int typecode, status = 0; long repeat, width; fits_get_coltype(_fptr, colNumber, &typecode, &repeat, &width, &status); CheckStatus(status); return typecode; } int FitsFile::GetIntKeywordValue(int keywordNumber) { return atoi(GetKeyword(keywordNumber).c_str()); } int FitsFile::GetIntKeywordValue(const std::string& keywordName) { return atoi(GetKeywordValue(keywordName).c_str()); } double FitsFile::GetDoubleKeywordValue(int keywordNumber) { return atof(GetKeyword(keywordNumber).c_str()); } double FitsFile::GetDoubleKeywordValue(const std::string& keywordName) { return atof(GetKeywordValue(keywordName).c_str()); } bool FitsFile::HasGroups() { try { return GetKeywordValue("GROUPS") == "T"; } catch (FitsIOException& e) { return false; } } int FitsFile::GetGroupCount() { return GetIntKeywordValue("GCOUNT"); } int FitsFile::GetParameterCount() { return GetIntKeywordValue("PCOUNT"); } long FitsFile::GetImageSize() { long size = 1; for (int i = 2; i <= GetCurrentImageDimensionCount(); ++i) { size *= GetCurrentImageSize(i); } return size; } long FitsFile::GetGroupSize() { if (!HasGroups()) throw FitsIOException("HDU has no groups"); long size = 1; for (int i = 2; i <= GetCurrentImageDimensionCount(); ++i) { size *= GetCurrentImageSize(i); } size += GetParameterCount(); return size; } void FitsFile::ReadGroupParameters(long groupIndex, long double* parametersData) { int status = 0; const long pSize = GetParameterCount(); double* parameters = new double[pSize]; fits_read_grppar_dbl(_fptr, groupIndex + 1, 1, pSize, parameters, &status); CheckStatus(status); for (long i = 0; i < pSize; ++i) parametersData[i] = parameters[i]; delete[] parameters; } void FitsFile::ReadGroup(long groupIndex, long double* groupData) { int status = 0; const long size = GetImageSize(); const long pSize = GetParameterCount(); double* parameters = new double[pSize]; const double nulValue = std::numeric_limits::quiet_NaN(); int anynul = 0; fits_read_grppar_dbl(_fptr, groupIndex + 1, 1, pSize, parameters, &status); CheckStatus(status); for (long i = 0; i < pSize; ++i) groupData[i] = parameters[i]; delete[] parameters; double* data = new double[size]; fits_read_img_dbl(_fptr, groupIndex + 1, 1, size, nulValue, data, &anynul, &status); CheckStatus(status); for (long i = 0; i < size; ++i) groupData[pSize + i] = data[i]; delete[] data; if (anynul != 0) Logger::Warn << "There were nulls in the group\n"; } void FitsFile::ReadGroupData(long groupIndex, long double* groupData) { int status = 0; const long size = GetImageSize(); const double nulValue = std::numeric_limits::quiet_NaN(); int anynul = 0; double* data = new double[size]; fits_read_img_dbl(_fptr, groupIndex + 1, 1, size, nulValue, data, &anynul, &status); CheckStatus(status); for (long i = 0; i < size; ++i) groupData[i] = data[i]; delete[] data; if (anynul != 0) Logger::Warn << "There were nulls in the group data\n"; } int FitsFile::GetGroupParameterIndex(const std::string& parameterName) { if (!HasGroups()) throw FitsIOException("HDU has no groups"); const int parameterCount = GetParameterCount(); for (int i = 1; i <= parameterCount; ++i) { std::stringstream s; s << "PTYPE" << i; if (GetKeywordValue(s.str()) == parameterName) return i - 1; } throw FitsIOException(std::string("Can not find parameter with name ") + parameterName); } int FitsFile::GetGroupParameterIndex(const std::string& parameterName, int number) { if (!HasGroups()) throw FitsIOException("HDU has no groups"); const int parameterCount = GetParameterCount(); for (int i = 1; i <= parameterCount; ++i) { std::stringstream s; s << "PTYPE" << i; if (GetKeywordValue(s.str()) == parameterName) { --number; if (number == 0) return i - 1; } } throw FitsIOException(std::string("Can not find parameter with name ") + parameterName); } bool FitsFile::HasGroupParameter(const std::string& parameterName) { if (!HasGroups()) return false; const int parameterCount = GetParameterCount(); for (int i = 1; i <= parameterCount; ++i) { std::stringstream s; s << "PTYPE" << i; if (GetKeywordValue(s.str()) == parameterName) return true; } return false; } bool FitsFile::HasGroupParameter(const std::string& parameterName, int number) { if (!HasGroups()) return false; const int parameterCount = GetParameterCount(); for (int i = 1; i <= parameterCount; ++i) { std::stringstream s; s << "PTYPE" << i; if (GetKeywordValue(s.str()) == parameterName) { --number; if (number == 0) return true; } } return false; } bool FitsFile::HasTableColumn(const std::string& columnName, int& columnIndex) { const int colCount = GetColumnCount(); for (int i = 1; i <= colCount; ++i) { std::stringstream s; s << "TTYPE" << i; if (GetKeywordValue(s.str()) == columnName) { columnIndex = i; return true; } } return false; } int FitsFile::GetTableColumnIndex(const std::string& columnName) { const int colCount = GetColumnCount(); for (int i = 1; i <= colCount; ++i) { std::stringstream s; s << "TTYPE" << i; if (GetKeywordValue(s.str()) == columnName) return i; } throw FitsIOException(std::string("Can not find column with name ") + columnName); } int FitsFile::GetTableColumnArraySize(int columnIndex) { CheckOpen(); int typecode = 0, status = 0; long repeat = 0, width = 0; fits_get_coltype(_fptr, columnIndex, &typecode, &repeat, &width, &status); CheckStatus(status); return repeat; } std::vector FitsFile::GetColumnDimensions(int columnIndex) { CheckOpen(); int naxis = 0, status = 0; constexpr int maxdim = 10; std::vector axes(maxdim, 0); fits_read_tdim(_fptr, columnIndex, maxdim, &naxis, axes.data(), &status); CheckStatus(status); axes.resize(naxis); return axes; } long FitsFile::GetColumnDimensionSize(int columnIndex, int dimension) { CheckOpen(); int naxis = 0, status = 0, maxdim = 10; long naxes[10]; for (size_t i = 0; i != 10; ++i) naxes[i] = 0; fits_read_tdim(_fptr, columnIndex, maxdim, &naxis, naxes, &status); CheckStatus(status); if (dimension >= naxis) throw FitsIOException( "Requested dimension index not available in fits file"); return naxes[dimension]; } std::string FitsFile::GetTableDimensionName(int index) { CheckOpen(); std::ostringstream name; name << "CTYPE" << (index + 1); int status = 0; char valueStr[256], commentStr[256]; fits_read_key(_fptr, TSTRING, name.str().c_str(), valueStr, commentStr, &status); std::string val; if (!status) { val = valueStr; } return val; } void FitsFile::ReadTableCell(int row, int col, double* output, size_t size) { int status = 0; double nulValue = std::numeric_limits::quiet_NaN(); int anynul = 0; fits_read_col(_fptr, TDOUBLE, col, row, 1, size, &nulValue, output, &anynul, &status); } void FitsFile::ReadTableCell(int row, int col, long double* output, size_t size) { std::vector data(size); int status = 0; double nulValue = std::numeric_limits::quiet_NaN(); int anynul = 0; fits_read_col(_fptr, TDOUBLE, col, row, 1, size, &nulValue, data.data(), &anynul, &status); for (size_t i = 0; i < size; ++i) output[i] = data[i]; } void FitsFile::ReadTableCell(int row, int col, bool* output, size_t size) { std::vector data(size); int status = 0; char nulValue = 0; int anynul = 0; fits_read_col(_fptr, TBIT, col, row, 1, size, &nulValue, data.data(), &anynul, &status); for (size_t i = 0; i < size; ++i) output[i] = data[i] != 0; } void FitsFile::ReadTableCell(int row, int col, char* output) { int status = 0; double nulValue = std::numeric_limits::quiet_NaN(); int anynul = 0; fits_read_col(_fptr, TSTRING, col, row, 1, 1, &nulValue, &output, &anynul, &status); } void FitsFile::WriteTableCell(int row, int col, double* data, size_t size) { int status = 0; fits_write_col(_fptr, TDOUBLE, col, row, 1, size, data, &status); CheckStatus(status); } void FitsFile::WriteTableCell(int row, int col, const bool* data, size_t size) { std::vector dataChar(size); int status = 0; for (size_t i = 0; i < size; ++i) { dataChar[i] = data[i] ? 1 : 0; } fits_write_col(_fptr, TBIT, col, row, 1, size, dataChar.data(), &status); } aoflagger-v3.4.0/msio/pngfile.h0000644000175000017500000000414614507760372015105 0ustar olesoles/** @file * This is the header file for the PngFile class. * @author André Offringa */ #ifndef PNGFILE_H #define PNGFILE_H #include #include /** * This class wraps the libpng library. It can save an Image2D class to a .png * file. * @see Image2D */ class PngFile { public: /** * Construct a new png file with a filename, a width and a height. * @param filename Name of the png file. * @param width Width of the image * @param height Height of the image */ PngFile(const std::string& filename, size_t width, size_t height); /** * Destructor. */ ~PngFile(); /** * Start writing. * @throws IOException if something goes wrong. */ void BeginWrite(); /** * Closes the image. */ void Close(); /** * Returns the size of one pixel in bytes. * @return Size of one pixel in bytes. */ int PixelSize() const { return _pixelSize; } /** * Clears the entire image. * @param colorR Red background value. * @param colorG Green background value. * @param colorB Blue background value. * @param colorA Alfa background value. */ void Clear(int colorR = 255, int colorG = 255, int colorB = 255, int colorA = 255); /** * Sets a pixel in the image to a specific color. * @param x x-coordinate. * @param y y-coordinate. * @param colorR Red value. * @param colorG Green value. * @param colorB Blue value. * @param colorA Alfa value. */ void PlotPixel(size_t x, size_t y, int colorR, int colorG, int colorB, int colorA) { _row_pointers[y][x * _pixelSize] = colorR; _row_pointers[y][x * _pixelSize + 1] = colorG; _row_pointers[y][x * _pixelSize + 2] = colorB; _row_pointers[y][x * _pixelSize + 3] = colorA; } /** * Retrieve the array of row pointers. * @return an array of row pointers. */ png_bytep* RowPointers() const { return _row_pointers; } private: const std::string _filename; const size_t _width, _height; png_bytep* _row_pointers; png_structp _png_ptr; png_infop _info_ptr; FILE* _fp; const int _pixelSize; }; #endif aoflagger-v3.4.0/msio/msstatreader.cpp0000644000175000017500000004022714507760372016512 0ustar olesoles#include "msstatreader.h" #include "../structures/mask2d.h" #include "../structures/msmetadata.h" #include "../structures/image2d.h" #include "../util/progress/progresslistener.h" #include #include #include #include using aocommon::Polarization; using aocommon::PolarizationEnum; MSStatReader::MSStatReader(const std::string& filename, const std::string& dataColumn) : _filename(filename), _dataColumn(dataColumn) { casacore::MeasurementSet ms(filename); _nBands = ms.spectralWindow().nrow(); const casacore::ScalarColumn fieldIdCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::FIELD_ID)); const casacore::ScalarColumn timeCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::TIME)); int curField = -1; for (size_t row = 0; row != ms.nrow(); ++row) { const int field = fieldIdCol(row); if (field != curField) { _sequenceStart.emplace_back(row); curField = field; } } _sequenceStart.emplace_back(ms.nrow()); _telescopeName = MSMetaData::GetTelescopeName(ms); } MSStatReader::Result MSStatReader::readSamples( BaselineIntegration::Mode statType, size_t sequenceIndex, size_t bandIndex, bool includeAutos, bool includeFlags, bool freqDiff, ProgressListener& progress) { progress.OnStartTask("Read data & integrate baselines"); casacore::MeasurementSet ms(_filename); const casacore::ScalarColumn antenna1Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA1)); const casacore::ScalarColumn antenna2Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA2)); const casacore::ScalarColumn timeCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::TIME)); const casacore::ScalarColumn dataDescIdCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::DATA_DESC_ID)); const casacore::ArrayColumn> dataColumn(ms, _dataColumn); const casacore::ArrayColumn flagColumn( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::FLAG)); casacore::IPosition dataShape = dataColumn.shape(0); size_t nPolarizations = dataShape[0], nChannels = dataShape[1], nTotal = freqDiff ? (nPolarizations * (nChannels - 1)) : nPolarizations * nChannels; casacore::Array> dataArray(dataShape); casacore::Array flagArray(dataShape); const aocommon::MultiBandData bands(ms.spectralWindow(), ms.dataDescription()); size_t startRow = _sequenceStart[sequenceIndex], endRow = _sequenceStart[sequenceIndex + 1]; double time = timeCol(startRow) - 1; std::vector statsData; std::vector times; size_t dataPos = 0; const size_t totalProgress = (endRow - startRow) * 104 / 100; for (size_t row = startRow; row != endRow; ++row) { size_t antenna1 = antenna1Col(row), antenna2 = antenna2Col(row); const bool baselineSelected = includeAutos || (antenna1 != antenna2); if (baselineSelected && bands.GetBandIndex(dataDescIdCol(row)) == bandIndex) { if (timeCol(row) != time) { dataPos = statsData.size(); statsData.resize(statsData.size() + nTotal); time = timeCol(row); times.emplace_back(time); } dataColumn.get(row, dataArray); flagColumn.get(row, flagArray); if (freqDiff) { for (size_t i = 0; i != nTotal; ++i) { const bool flag1 = flagArray.cbegin()[i]; const bool flag2 = flagArray.cbegin()[i + nPolarizations]; if ((!flag1 && !flag2) || includeFlags) { const std::complex val = dataArray.cbegin()[i] - dataArray.cbegin()[i + nPolarizations]; statsData[dataPos + i].Add(statType, val); } } } else { for (size_t i = 0; i != nTotal; ++i) { const bool flag = flagArray.cbegin()[i]; if (!flag || includeFlags) { const std::complex val = dataArray.cbegin()[i]; statsData[dataPos + i].Add(statType, val); } } } } progress.OnProgress(row - startRow, totalProgress); } progress.OnStartTask("Combining statistics"); Result result = makeResult(statType, statsData.data(), nPolarizations, freqDiff ? (nChannels - 1) : nChannels, times.size()); result.second->SetObservationTimes(times); fillBand(result, freqDiff, bands, bandIndex); progress.OnFinish(); return result; } MSStatReader::Result MSStatReader::readTimeDiff( BaselineIntegration::Mode statType, size_t sequenceIndex, size_t bandIndex, bool includeAutos, bool includeFlags, ProgressListener& progress) { progress.OnStartTask("Read data & integrate baselines"); casacore::MeasurementSet ms(_filename); const casacore::ScalarColumn antenna1Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA1)); const casacore::ScalarColumn antenna2Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA2)); const casacore::ScalarColumn timeCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::TIME)); const casacore::ScalarColumn dataDescIdCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::DATA_DESC_ID)); const casacore::ArrayColumn> dataColumn(ms, _dataColumn); const casacore::ArrayColumn flagColumn( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::FLAG)); casacore::IPosition dataShape = dataColumn.shape(0); size_t nPolarizations = dataShape[0], nChannels = dataShape[1], nTotal = nPolarizations * nChannels; casacore::Array> dataArray(dataShape); casacore::Array flagArray(dataShape); const aocommon::MultiBandData bands(ms.spectralWindow(), ms.dataDescription()); size_t startRow = _sequenceStart[sequenceIndex], endRow = _sequenceStart[sequenceIndex + 1]; double time = timeCol(startRow) - 1; std::vector statsData; std::vector times; size_t dataPos = 0; const size_t totalProgress = (endRow - startRow) * 104 / 100; using Baseline = std::pair; using TimeData = std::vector, bool>>; std::map previousTimeData, currentTimeData; for (size_t row = startRow; row != endRow; ++row) { size_t antenna1 = antenna1Col(row), antenna2 = antenna2Col(row); const bool baselineSelected = includeAutos || (antenna1 != antenna2); if (baselineSelected && bands.GetBandIndex(dataDescIdCol(row)) == bandIndex) { const std::pair baseline(antenna1, antenna2); if (timeCol(row) != time) { time = timeCol(row); times.emplace_back(time); if (times.size() > 1) { dataPos = statsData.size(); statsData.resize(statsData.size() + nTotal); previousTimeData = std::move(currentTimeData); currentTimeData.clear(); } } dataColumn.get(row, dataArray); flagColumn.get(row, flagArray); auto& curBaseline = currentTimeData[baseline]; curBaseline.resize(nTotal); for (size_t i = 0; i != nTotal; ++i) { const bool curFlag = flagArray.cbegin()[i]; const std::complex curVal = dataArray.cbegin()[i]; curBaseline[i].first = curVal; curBaseline[i].second = curFlag; } auto prevBaselinePtr = previousTimeData.find(baseline); if (times.size() > 1 && prevBaselinePtr != previousTimeData.end()) { for (size_t i = 0; i != nTotal; ++i) { const bool curFlag = flagArray.cbegin()[i]; const bool prevFlag = prevBaselinePtr->second[i].second; if ((!curFlag && !prevFlag) || includeFlags) { const std::complex val = prevBaselinePtr->second[i].first - dataArray.cbegin()[i]; statsData[dataPos + i].Add(statType, val); } } } } progress.OnProgress(row - startRow, totalProgress); } progress.OnStartTask("Combining statistics"); Result result = makeResult(statType, statsData.data(), nPolarizations, nChannels, times.size() - 1); fillBand(result, false, bands, bandIndex); for (size_t i = 0; i != times.size() - 1; ++i) times[i] = 0.5 * (times[i] + times[i + 1]); times.resize(times.size() - 1); result.second->SetObservationTimes(times); progress.OnFinish(); return result; } MSStatReader::Result MSStatReader::makeResult( BaselineIntegration::Mode statType, const Statistic* statsData, size_t nPolarizations, size_t nChannels, size_t nTimes) { const size_t nTotal = nPolarizations * nChannels; std::vector images(nPolarizations); std::vector masks(nPolarizations); for (size_t p = 0; p != nPolarizations; ++p) { images[p] = Image2D::CreateUnsetImagePtr(nTimes, nChannels); masks[p] = Mask2D::CreateUnsetMaskPtr(nTimes, nChannels); } for (size_t y = 0; y != nChannels; ++y) { for (size_t x = 0; x != nTimes; ++x) { for (size_t p = 0; p != nPolarizations; ++p) { const Statistic& stat = statsData[x * nTotal + y * nPolarizations + p]; if (stat.count == 0) { images[p]->SetValue(x, y, 0.0); masks[p]->SetValue(x, y, true); } else { const double val = stat.Calculate(statType); images[p]->SetValue(x, y, val); masks[p]->SetValue(x, y, false); } } } } std::vector pols; if (nPolarizations == 4) pols = std::vector{Polarization::XX, Polarization::XY, Polarization ::YX, Polarization::YY}; else if (nPolarizations == 2) pols = std::vector{Polarization::XX, Polarization::YY}; else pols.emplace_back(Polarization::StokesI); std::vector tfs; for (size_t p = 0; p != nPolarizations; ++p) { tfs.emplace_back(TimeFrequencyData::AmplitudePart, pols[p], images[p]); tfs.back().SetGlobalMask(masks[p]); } Result result; if (nPolarizations == 4) result.first = TimeFrequencyData::MakeFromPolarizationCombination( tfs[0], tfs[1], tfs[2], tfs[3]); else if (nPolarizations == 2) result.first = TimeFrequencyData::MakeFromPolarizationCombination(tfs[0], tfs[1]); else result.first = std::move(tfs[0]); result.second.reset(new TimeFrequencyMetaData()); return result; } void MSStatReader::fillBand(MSStatReader::Result& result, bool freqDiff, const aocommon::MultiBandData& bands, size_t bandIndex) { BandInfo bandInfo; bandInfo.windowIndex = 0; if (freqDiff) { bandInfo.channels.resize(bands[bandIndex].ChannelCount() - 1); for (size_t i = 0; i != bands[bandIndex].ChannelCount() - 1; ++i) { bandInfo.channels[i].frequencyIndex = i; bandInfo.channels[i].frequencyHz = 0.5 * (bands[bandIndex].Channel(i).Frequency() + bands[bandIndex].Channel(i + 1).Frequency()); bandInfo.channels[i].effectiveBandWidthHz = bands[bandIndex].Channel(i).Width() + bands[bandIndex].Channel(i + 1).Width(); } } else { bandInfo.channels.resize(bands[bandIndex].ChannelCount()); for (size_t i = 0; i != bands[bandIndex].ChannelCount(); ++i) { bandInfo.channels[i].frequencyIndex = i; bandInfo.channels[i].frequencyHz = bands[bandIndex].Channel(i).Frequency(); bandInfo.channels[i].effectiveBandWidthHz = bands[bandIndex].Channel(i).Width(); } } result.second->SetBand(bandInfo); } void MSStatReader::StoreFlags(const std::vector& flags, BaselineIntegration::Differencing diffType, size_t sequenceIndex, size_t bandIndex, bool includeAutos) { std::vector appliedFlags; switch (diffType) { case BaselineIntegration::NoDifference: appliedFlags = flags; break; case BaselineIntegration::TimeDifference: for (size_t i = 0; i != flags.size(); ++i) { const Mask2DCPtr input = flags[i]; Mask2DPtr mask = Mask2D::CreateUnsetMaskPtr(input->Width() + 1, input->Height()); for (size_t y = 0; y != input->Height(); ++y) { mask->SetValue(0, y, input->Value(0, y)); for (size_t x = 1; x != input->Width(); ++x) { mask->SetValue(x, y, input->Value(x - 1, y) || input->Value(x, y)); } mask->SetValue(input->Width(), y, input->Value(input->Width() - 1, y)); } appliedFlags.emplace_back(std::move(mask)); } break; case BaselineIntegration::FrequencyDifference: for (size_t i = 0; i != flags.size(); ++i) { const Mask2DCPtr input = flags[i]; Mask2DPtr mask = Mask2D::CreateUnsetMaskPtr(input->Width(), input->Height() + 1); for (size_t x = 0; x != input->Width(); ++x) mask->SetValue(x, 0, input->Value(x, 0)); for (size_t y = 1; y != input->Height(); ++y) { for (size_t x = 0; x != input->Width(); ++x) { mask->SetValue(x, y, input->Value(x, y - 1) || input->Value(x, y)); } } for (size_t x = 0; x != input->Width(); ++x) mask->SetValue(x, input->Height(), input->Value(x, input->Height() - 1)); appliedFlags.emplace_back(std::move(mask)); } break; } storeFlags(appliedFlags, sequenceIndex, bandIndex, includeAutos); } void MSStatReader::storeFlags(const std::vector& flags, size_t sequenceIndex, size_t bandIndex, bool includeAutos) { casacore::MeasurementSet ms(_filename, casacore::MeasurementSet::TableOption::Update); const casacore::ScalarColumn antenna1Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA1)); const casacore::ScalarColumn antenna2Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA2)); const casacore::ScalarColumn timeCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::TIME)); const casacore::ScalarColumn dataDescIdCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::DATA_DESC_ID)); casacore::ArrayColumn flagColumn( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::FLAG)); casacore::IPosition dataShape = flagColumn.shape(0); size_t nPolarizations = dataShape[0], nChannels = dataShape[1]; if (nPolarizations != flags.size()) throw std::runtime_error( "Invalid nr of masks specified in call to MSStatReader::storeFlags()"); casacore::Array flagArray(dataShape); const aocommon::MultiBandData bands(ms.spectralWindow(), ms.dataDescription()); size_t startRow = _sequenceStart[sequenceIndex], endRow = _sequenceStart[sequenceIndex + 1]; double time = timeCol(startRow) - 1; size_t timeIndex = 0; for (size_t row = startRow; row != endRow; ++row) { size_t antenna1 = antenna1Col(row), antenna2 = antenna2Col(row); const bool baselineSelected = includeAutos || (antenna1 != antenna2); if (baselineSelected && bands.GetBandIndex(dataDescIdCol(row)) == bandIndex) { const std::pair baseline(antenna1, antenna2); if (timeCol(row) != time) { time = timeCol(row); ++timeIndex; } flagColumn.get(row, flagArray); auto iter = flagArray.cbegin(); for (size_t ch = 0; ch != nChannels; ++ch) { for (size_t p = 0; p != nPolarizations; ++p) { *iter = *iter || flags[p]->Value(timeIndex - 1, ch); ++iter; } } flagColumn.put(row, flagArray); } } } aoflagger-v3.4.0/msio/memorybaselinereader.h0000644000175000017500000000471414507760372017660 0ustar olesoles#ifndef MEMORY_BASELINE_READER_H #define MEMORY_BASELINE_READER_H #include #include #include #include "../structures/antennainfo.h" #include "baselinereader.h" #include "../structures/image2d.h" #include "../structures/mask2d.h" class MemoryBaselineReader final : public BaselineReader { public: explicit MemoryBaselineReader(const std::string& msFile) : BaselineReader(msFile), _isRead(false), _areFlagsChanged(false) {} ~MemoryBaselineReader() { if (_areFlagsChanged) { WriteToMs(); } } void PrepareReadWrite(ProgressListener& progress) override; void PerformReadRequests(class ProgressListener& progress) override; void PerformFlagWriteRequests() override; void PerformDataWriteTask( [[maybe_unused]] std::vector realImages, [[maybe_unused]] std::vector imaginaryImages, [[maybe_unused]] size_t antenna1, [[maybe_unused]] size_t antenna2, [[maybe_unused]] size_t spectralWindow, [[maybe_unused]] size_t sequenceId) override { throw std::runtime_error( "The full mem reader can not write data back to file: use the indirect " "reader"); } static bool IsEnoughMemoryAvailable(uint64_t size); size_t GetMinRecommendedBufferSize(size_t /*threadCount*/) override { return 1; } size_t GetMaxRecommendedBufferSize(size_t /*threadCount*/) override { return 2; } bool IsModified() const override { return _areFlagsChanged; } void WriteToMs() override; private: void readSet(class ProgressListener& progress); void clear(); bool _isRead, _areFlagsChanged; class BaselineID { public: BaselineID(unsigned a1, unsigned a2, unsigned _spw, unsigned seqId) : antenna1(a1), antenna2(a2), spw(_spw), sequenceId(seqId) { if (antenna1 > antenna2) std::swap(antenna1, antenna2); } unsigned antenna1, antenna2, spw, sequenceId; bool operator<(const BaselineID& other) const { if (antenna1 < other.antenna1) { return true; } else if (antenna1 == other.antenna1) { if (antenna2 < other.antenna2) { return true; } else if (antenna2 == other.antenna2) { if (spw < other.spw) return true; else if (spw == other.spw) return sequenceId < other.sequenceId; } } return false; } }; std::map> _baselines; }; #endif // MEMORY_BASELINE_READER_H aoflagger-v3.4.0/msio/reorderingbaselinereader.h0000644000175000017500000000724314507760372020510 0ustar olesoles#ifndef MSIO_REORDERING_BASELINE_READER_H_ #define MSIO_REORDERING_BASELINE_READER_H_ #include #include #include #include #include #include "baselinereader.h" #include "directbaselinereader.h" class ReorderingBaselineReader : public BaselineReader { public: explicit ReorderingBaselineReader(const std::string& msFile); ~ReorderingBaselineReader(); bool IsModified() const override { return reordered_data_files_have_changed_ || reordered_flag_files_have_changed_; } void WriteToMs() override; void PrepareReadWrite(ProgressListener& progress) override; virtual void PerformReadRequests( class ProgressListener& progress) final override; virtual void PerformFlagWriteRequests() final override; virtual void PerformDataWriteTask(std::vector _realImages, std::vector _imaginaryImages, size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId) final override; virtual size_t GetMinRecommendedBufferSize( size_t /*threadCount*/) final override { return 1; } virtual size_t GetMaxRecommendedBufferSize( size_t /*threadCount*/) final override { return 2; } void SetReadUVW(bool readUVW) { read_uvw_ = readUVW; } private: struct ReorderInfo { std::unique_ptr dataFile; std::unique_ptr flagFile; }; struct UpdateInfo { std::unique_ptr dataFile; std::unique_ptr flagFile; }; class SeqIndexLookupTable { public: SeqIndexLookupTable(size_t antennaCount, size_t spectralWindowCount, size_t sequenceCount) : _antennaCount(antennaCount), _table(sequenceCount) { size_t maxBaselineCount = antennaCount * antennaCount; for (size_t i = 0; i != sequenceCount; ++i) { std::vector>& spwTable = _table[i]; spwTable.resize(spectralWindowCount); for (size_t j = 0; j != spectralWindowCount; ++j) { std::vector& baselTable = spwTable[j]; baselTable.resize(maxBaselineCount); } } } size_t& Value(size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId) { return _table[sequenceId][spectralWindow] [antenna1 * _antennaCount + antenna2]; } private: size_t _antennaCount; std::vector>> _table; }; void reorderMS(class ProgressListener& progress); void reorderFull(class ProgressListener& progress); void makeLookupTables(size_t& fileSize); void updateOriginalMSData(class ProgressListener& progress); void updateOriginalMSFlags(class ProgressListener& progress); void performFlagWriteTask(std::vector flags, unsigned antenna1, unsigned antenna2, unsigned spw, unsigned sequenceId); template void updateOriginalMS(class ProgressListener& progress); void removeTemporaryFiles(); static void preAllocate(const std::string& filename, size_t fileSize); DirectBaselineReader direct_reader_; std::unique_ptr sequence_index_table_; std::vector file_positions_; std::string data_filename_; std::string flag_filename_; std::string meta_filename_; bool ms_is_reordered_; bool remove_reordered_files_; bool reordered_data_files_have_changed_; bool reordered_flag_files_have_changed_; bool read_uvw_; }; #endif // MSIO_REORDERING_BASELINE_READER_H_ aoflagger-v3.4.0/msio/fitsfile.h0000644000175000017500000002147614507760372015273 0ustar olesoles/** @file * This is the header file for the FitsFile and FitsIOException class. * @author André Offringa */ #ifndef FITSFILE_H #define FITSFILE_H #include #include #include #include #include #include "../structures/types.h" /** * This class represents an exception that occurred during reading/writing of a * FITS file. * @see FitsFile */ class FitsIOException : public std::runtime_error { public: explicit FitsIOException(const std::string& description) : std::runtime_error(description) {} ~FitsIOException() noexcept {} }; /** * This class wraps the cfitsio library. It can be used to read or write a FITS * file with a (two dimensional) image. The fits file supports some other * things, like tables, which are not supported in this class. The FITS files * generated by the MeqTrees process can be read by this file. The FITS file can * store multiple images in one file. * * This class works closely together with the Image2D class. * @see Image2D */ class FitsFile { public: /** * Specifies how a FITS file should be opened */ enum FileMode { /** * Only open for reading */ ReadOnlyMode, /** * Open for reading and writing */ ReadWriteMode }; /** * The HDU is an entity inside a FITS file. This enum defines the possible * entity types. */ enum HDUType { /** * One or more two dimensional images */ ImageHDUType, /** * An ASCII table */ ASCIITableHDUType, /** * A binary table */ BinaryTableHDUType }; /** * This enum defines the possible image types in an image HDU. */ enum ImageType { /** * Image consisting of 8 bit integers. */ Int8ImageType, /** * Image consisting of 16 bit integers. */ Int16ImageType, /** * Image consisting of 32 bit integers. */ Int32ImageType, /** * Image consisting of 32 bit floats. */ Float32ImageType, /** * Image consisting of 64 bit doubles. */ Double64ImageType }; /** * Construct a new FitsFile class associated with the specified filename. * @param filename The file name of the fits file, to be opened with Open() or * created with Create(). */ explicit FitsFile(const std::string& filename); /** * Destructor. * @throws FitsIOException in case something failed due to an IO error. */ ~FitsFile(); /** * Open the file. * @param mode In which way the file should be opened. * @throws FitsIOException in case opening failed due to an IO error. */ void Open(FileMode mode = ReadOnlyMode); /** * Create a new FITS file. * @throws FitsIOException in case writing failed due to an IO error. */ void Create(); /** * Close the file, releasing resources. * @throws FitsIOException in case something happent due to an IO error. */ void Close(); /** * Determine whether the file is ready for reading and/or writing. * @return @c true if the file has been opened. */ bool IsOpen() const { return _isOpen; } /** * Retrieve the number of HDU blocks inside the file. * @return The number of HDU blocks inside the file. * @throws FitsIOException in case reading failed due to an IO error. */ int GetHDUCount(); /** * Retrieve the index of the current HDU block. * @return The index of the current HDU block. * @throws FitsIOException in case reading failed due to an IO error. */ int GetCurrentHDU(); /** * Retrieve the type of the current HDU block. * @return The type of the current HDU block. * @throws FitsIOException in case reading failed due to an IO error. */ enum HDUType GetCurrentHDUType(); /** * Start reading another HDU block, specified by its index. * @param hduNumber Index of the HDU block to move to. * @throws FitsIOException in case reading failed due to an IO error. */ void MoveToHDU(int hduNumber); /** * Retrieve what kind of image this HDU image block is. Only call this * method if GetCurrentHDUType() returned ImageHDUType. * @return The image type. * @throws FitsIOException in case reading failed due to an IO error. */ FitsFile::ImageType GetCurrentImageType(); /** * Retrieve the number of dimensions of an image. * @return The number of dimensions. * @see GetCurrentImageSize() * @throws FitsIOException in case reading failed due to an IO error. */ int GetCurrentImageDimensionCount(); /** * Retrieve the size of a specific dimension. * @param dimension The dimension to retrieve the size for (first dimension = * 0) * @return The size of the dimension. * @see GetCurrentImageDimensionCount() * @throws FitsIOException in case reading failed due to an IO error. */ long GetCurrentImageSize(int dimension); /** * Writes a new image HUD to the FITS file. Does not write the data itself, * only the headers. The WriteImage() call should be called next. * @param imageType Type of image * @param width Width of image * @param height Height of image * @throws FitsIOException in case writing failed due to an IO error. */ void AppendImageHUD(enum FitsFile::ImageType imageType, long width, long height); /** * Reads one image into a buffer. The image will be converted to @c long @c * doubles. * @param startPos This specifies where to start reading. If several images * are stored in the 3rd or 4th dimension, they can be read one by one by * starting at different start positions. * @param buffer The buffer where the image will be stored. * @param bufferSize Size of the buffer. Reading will stop once the buffer is * full. It makes sense to use buffer the size of the 1st x 2nd dimension. * @param nullValue What value should be used to represent null values. * @throws FitsIOException in case reading failed due to an IO error. */ void ReadCurrentImageData(long startPos, num_t* buffer, long bufferSize, long double nullValue = nan("Unset value")); /** * Writes an image to the FITS file. * @param startPos Where inside the image to start writing. * @param buffer Buffer containing the image data * @param bufferSize Size of the buffer * @param nullValue What value was used to represent null values. * @see ReadCurrentImageData * @throws FitsIOException in case writing failed due to an IO error. */ void WriteImage(long startPos, double* buffer, long bufferSize, double nullValue = nan("Unset value")); void WriteImage(long startPos, float* buffer, long bufferSize, float nullValue = nan("Unset value")); int GetKeywordCount(); bool HasKeyword(const std::string& keywordName); std::string GetKeyword(int keywordNumber); std::string GetKeywordValue(int keywordNumber); std::string GetKeywordValue(const std::string& keywordName); bool GetKeywordValue(const std::string& keywordName, std::string& value); std::string GetKeywordComment(int keywordNumber); int GetRowCount(); int GetColumnCount(); int GetColumnType(int colNumber); bool HasGroups(); int GetIntKeywordValue(int keywordNumber); int GetIntKeywordValue(const std::string& keywordName); double GetDoubleKeywordValue(int keywordNumber); double GetDoubleKeywordValue(const std::string& keywordName); int GetGroupCount(); int GetParameterCount(); long GetImageSize(); long GetGroupSize(); void ReadGroup(long groupIndex, long double* groupData); void ReadGroupData(long groupIndex, long double* groupData); void ReadGroupParameters(long groupIndex, long double* parametersData); void ReadTableCell(int row, int col, long double* output, size_t size); void ReadTableCell(int row, int col, double* output, size_t size); void ReadTableCell(int row, int col, bool* output, size_t size); void ReadTableCell(int row, int col, char* output); void WriteTableCell(int row, int col, double* data, size_t size); void WriteTableCell(int row, int col, const bool* data, size_t size); bool HasTableColumn(const std::string& columnName, int& columnIndex); int GetTableColumnIndex(const std::string& columnName); int GetTableColumnArraySize(int columnIndex); std::string GetTableDimensionName(int index); std::vector GetColumnDimensions(int columnIndex); long GetColumnDimensionSize(int columnIndex, int dimension); int GetGroupParameterIndex(const std::string& parameterName); int GetGroupParameterIndex(const std::string& parameterName, int number); bool HasGroupParameter(const std::string& parameterName); bool HasGroupParameter(const std::string& parameterName, int number); const std::string& Filename() const { return _filename; } private: const std::string _filename; fitsfile* _fptr; bool _isOpen; inline void CheckStatus(int status) const; inline void CheckOpen() const; }; #endif aoflagger-v3.4.0/msio/indirectbaselinereader.h0000644000175000017500000000000014507760372020131 0ustar olesolesaoflagger-v3.4.0/msio/rspreader.h0000644000175000017500000001347514507760372015455 0ustar olesoles#ifndef RSPREADER_H #define RSPREADER_H #include #include "../util/logger.h" #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" class RSPReader { public: explicit RSPReader(const std::string& rawFile) : _rawFile(rawFile), _clockSpeed(200000000) {} ~RSPReader() {} std::pair ReadChannelBeamlet( unsigned long timestepStart, unsigned long timestepEnd, unsigned beamletCount, unsigned beamletIndex); std::pair ReadSingleBeamlet( unsigned long timestepStart, unsigned long timestepEnd, unsigned beamletCount, unsigned beamletIndex); std::pair ReadAllBeamlets( unsigned long timestepStart, unsigned long timestepEnd, unsigned beamletCount); void ReadForStatistics(unsigned beamletCount); const std::string& File() const { return _rawFile; } unsigned long TimeStepCount(size_t beamletCount) const; private: static const unsigned char BitReverseTable256[256]; static signed short toShort(unsigned char c1, unsigned char c2) { return (c2 << 8) | c1; } static unsigned short toUShort(unsigned char c1, unsigned char c2) { return (c1 << 8) | c2; } static unsigned int toUInt(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4) { return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; } const std::string _rawFile; const unsigned long _clockSpeed; static const unsigned long STATION_INTEGRATION_STEPS; struct RCPTransportHeader { unsigned char versionAndHeaderLength : 8; unsigned char typeOfService : 8; unsigned short totalLength : 16; unsigned short identification : 16; unsigned int flagsAndFragmentOffset : 8; unsigned int ttl : 8; unsigned int protocol : 8; unsigned int headerCrc : 16; unsigned int sourceIP : 32; unsigned int destinationIP : 32; unsigned int udpSourcePort : 16; unsigned int udpDestPort : 16; unsigned int udpLength : 16; unsigned int udpChecksum : 16; void Print() const { Logger::Debug << "versionAndHeaderLength=" << versionAndHeaderLength << "\n" << "typeOfService=" << typeOfService << "\n" << "totalLength=" << totalLength << "\n" << "identification=" << identification << "\n" << "flagsAndFragmentOffset=" << flagsAndFragmentOffset << "\n" << "ttl=" << ttl << "\n" << "protocol=" << protocol << "\n" << "headerCrc=" << headerCrc << "\n" << "sourceIP=" << sourceIP << "\n" << "destinationIP=" << destinationIP << "\n" << "udpSourcePort=" << udpSourcePort << "\n" << "udpDestPort=" << udpDestPort << "\n" << "udpLength=" << udpLength << "\n" << "udpChecksum=" << udpChecksum << "\n"; } }; struct RCPApplicationHeader { unsigned char versionId; unsigned char sourceInfo; unsigned short configurationId; unsigned short stationId; unsigned char nofBeamlets; unsigned char nofBlocks; unsigned int timestamp; unsigned int blockSequenceNumber; static const unsigned int SIZE; void Read(std::ifstream& stream) { unsigned char buffer[16]; stream.read(reinterpret_cast(buffer), 16); versionId = buffer[0]; sourceInfo = buffer[1]; configurationId = toUShort(buffer[3], buffer[2]); stationId = toUShort(buffer[5], buffer[4]); nofBeamlets = buffer[6]; nofBlocks = buffer[7]; timestamp = toUInt(buffer[11], buffer[10], buffer[9], buffer[8]); blockSequenceNumber = toUInt(buffer[15], buffer[14], buffer[13], buffer[12]); } void Print() const { Logger::Debug << "versionId=" << (unsigned int)versionId << "\n" << "sourceInfo=" << (unsigned int)sourceInfo << "\n" << "configurationId=" << (unsigned int)configurationId << "\n" << "stationId=" << (unsigned int)stationId << "\n" << "nofBeamlets=" << (unsigned int)nofBeamlets << "\n" << "nofBlocks=" << (unsigned int)nofBlocks << "\n" << "timestamp=" << (unsigned int)timestamp << "\n" << "blockSequenceNumber=" << (unsigned int)blockSequenceNumber << "\n"; } }; struct RCPBeamletData { signed short xr, xi; signed short yr, yi; static const unsigned int SIZE; void Read(std::ifstream& stream) { unsigned char buffer[8]; stream.read(reinterpret_cast(buffer), 8); xr = toShort(buffer[6], buffer[7]); xi = toShort(buffer[4], buffer[5]); yr = toShort(buffer[2], buffer[3]); yi = toShort(buffer[0], buffer[1]); } void Print() { Logger::Debug << "x=" << xr; if (xi > 0) Logger::Debug << "+" << xi << "i"; else Logger::Debug << "-" << (-xi) << "i"; Logger::Debug << ",y=" << yr; if (yi > 0) Logger::Debug << "+" << yi << "i\n"; else Logger::Debug << "-" << (-yi) << "i\n"; } }; struct BeamletStatistics { BeamletStatistics() : totalCount(0) { for (unsigned i = 0; i < 16; ++i) bitUseCount[i] = 0; } void Print() { for (unsigned bit = 0; bit < 16; ++bit) { Logger::Info << "Bit " << bit << " times required: " << bitUseCount[bit] << " (" << (100.0 * (double)bitUseCount[bit] / (double)totalCount) << "%)" << '\n'; } } unsigned long totalCount; unsigned long bitUseCount[16]; }; }; #endif // RSPREADER_H aoflagger-v3.4.0/msio/singlebaselinefile.cpp0000644000175000017500000002146014507760372017636 0ustar olesoles#include "singlebaselinefile.h" #include "../util/serializable.h" #include #define FILE_FORMAT_VERSION 1 void SingleBaselineFile::Read(std::istream& stream, ProgressListener& progress) { if (!stream) throw std::runtime_error("Could not open file"); char magic[9]; stream.read(magic, 8); magic[8] = 0; if (std::string(magic) != "RFIBL") throw std::runtime_error("This is not an AOFlagger single baseline file"); const unsigned fileformat = Serializable::UnserializeUInt32(stream); if (fileformat != FILE_FORMAT_VERSION) throw std::runtime_error( "This AOFlagger single baseline file has an unknown file format"); const std::string versionStr = Serializable::UnserializeString(stream); Serializable::UnserializeUInt32(stream); // maj Serializable::UnserializeUInt32(stream); // min Serializable::UnserializeUInt32(stream); // submin data = UnserializeTFData(stream, progress); metaData = UnserializeMetaData(stream); telescopeName = Serializable::UnserializeString(stream); } void SingleBaselineFile::Write(std::ostream& stream) { stream.write("RFIBL\0\0\0", 8); Serializable::SerializeToUInt32( stream, FILE_FORMAT_VERSION); // fileformat version index Serializable::SerializeToString(stream, AOFLAGGER_VERSION_DATE_STR); Serializable::SerializeToUInt32(stream, AOFLAGGER_VERSION_MAJOR); Serializable::SerializeToUInt32(stream, AOFLAGGER_VERSION_MINOR); Serializable::SerializeToUInt32(stream, AOFLAGGER_VERSION_SUBMINOR); Serialize(stream, data); Serialize(stream, metaData); Serializable::SerializeToString(stream, telescopeName); } TimeFrequencyData SingleBaselineFile::UnserializeTFData( std::istream& stream, ProgressListener& progress) { TimeFrequencyData data; const size_t polCount = Serializable::UnserializeUInt32(stream); const size_t complCode = Serializable::UnserializeUInt32(stream); enum TimeFrequencyData::ComplexRepresentation repr; switch (complCode) { default: case 0: repr = TimeFrequencyData::PhasePart; break; case 1: repr = TimeFrequencyData::AmplitudePart; break; case 2: repr = TimeFrequencyData::RealPart; break; case 3: repr = TimeFrequencyData::ImaginaryPart; break; case 4: repr = TimeFrequencyData::ComplexParts; break; } for (size_t i = 0; i != polCount; ++i) { TimeFrequencyData polData; const size_t polCode = Serializable::UnserializeUInt32(stream); const aocommon::PolarizationEnum pol = aocommon::Polarization::AipsIndexToEnum(polCode); const uint32_t imageFlagBitset = Serializable::UnserializeUInt32(stream); const size_t imageCount = imageFlagBitset & 0x03; const size_t maskCount = (imageFlagBitset & 0x04) ? 1 : 0; if (imageCount == 2) { Image2D first = UnserializeImage(stream, progress, i * 2, polCount * 2), second = UnserializeImage(stream, progress, i * 2 + 1, polCount * 2); polData = TimeFrequencyData(pol, Image2D::MakePtr(first), Image2D::MakePtr(second)); } else if (imageCount == 1) { polData = TimeFrequencyData( repr, pol, Image2D::MakePtr(UnserializeImage(stream, progress, i, polCount))); } if (maskCount == 1) polData.SetGlobalMask(Mask2D::MakePtr(UnserializeMask(stream))); if (i == 0) data = polData; else data = TimeFrequencyData::MakeFromPolarizationCombination(data, polData); } return data; } TimeFrequencyMetaData SingleBaselineFile::UnserializeMetaData( std::istream& stream) { TimeFrequencyMetaData metaData; const size_t featureSet = Serializable::UnserializeUInt64(stream); const bool hasAntenna1 = featureSet & 0x01; const bool hasAntenna2 = featureSet & 0x02; const bool hasBand = featureSet & 0x04; const bool hasObsTimes = featureSet & 0x10; if (hasAntenna1) { AntennaInfo ant; ant.Unserialize(stream); metaData.SetAntenna1(ant); } if (hasAntenna2) { AntennaInfo ant; ant.Unserialize(stream); metaData.SetAntenna2(ant); } if (hasBand) { BandInfo band; band.Unserialize(stream); metaData.SetBand(band); } if (hasObsTimes) { std::vector vals(Serializable::UnserializeUInt64(stream)); for (double& t : vals) t = Serializable::UnserializeDouble(stream); metaData.SetObservationTimes(vals); } return metaData; } Image2D SingleBaselineFile::UnserializeImage(std::istream& stream, ProgressListener& progress, size_t progressOffset, size_t progressMax) { size_t width = Serializable::UnserializeUInt64(stream), height = Serializable::UnserializeUInt64(stream); Image2D result = Image2D::MakeUnsetImage(width, height); for (size_t y = 0; y != height; ++y) { progress.OnProgress(height * progressOffset + y, height * progressMax); for (size_t x = 0; x != width; ++x) { result.SetValue(x, y, Serializable::UnserializeFloat(stream)); } } return result; } Mask2D SingleBaselineFile::UnserializeMask(std::istream& stream) { size_t width = Serializable::UnserializeUInt64(stream), height = Serializable::UnserializeUInt64(stream); Mask2D result = Mask2D::MakeUnsetMask(width, height); for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { char val; stream.read(&val, 1); result.SetValue(x, y, val != 0); } } return result; } void SingleBaselineFile::Serialize(std::ostream& stream, const TimeFrequencyData& data) { Serializable::SerializeToUInt32(stream, data.PolarizationCount()); int complCode; switch (data.ComplexRepresentation()) { default: case TimeFrequencyData::PhasePart: complCode = 0; break; case TimeFrequencyData::AmplitudePart: complCode = 1; break; case TimeFrequencyData::RealPart: complCode = 2; break; case TimeFrequencyData::ImaginaryPart: complCode = 3; break; case TimeFrequencyData::ComplexParts: complCode = 4; break; } Serializable::SerializeToUInt32(stream, complCode); for (size_t i = 0; i != data.PolarizationCount(); ++i) { const aocommon::PolarizationEnum p = data.GetPolarization(i); Serializable::SerializeToUInt32(stream, aocommon::Polarization::EnumToAipsIndex(p)); unsigned int imageFlagBitset = 0; const TimeFrequencyData polData = data.MakeFromPolarizationIndex(i); if (polData.ImageCount() == 2) imageFlagBitset = imageFlagBitset | 0x02; if (polData.ImageCount() == 1) imageFlagBitset = imageFlagBitset | 0x01; if (polData.MaskCount() == 1) imageFlagBitset = imageFlagBitset | 0x04; Serializable::SerializeToUInt32(stream, imageFlagBitset); if (polData.ImageCount() >= 1) Serialize(stream, *polData.GetImage(0)); if (polData.ImageCount() == 2) Serialize(stream, *polData.GetImage(1)); if (polData.MaskCount() == 1) Serialize(stream, *polData.GetMask(0)); } } void SingleBaselineFile::Serialize(std::ostream& stream, const TimeFrequencyMetaData& metaData) { size_t featureSet = 0; if (metaData.HasAntenna1()) featureSet = featureSet | 0x01; if (metaData.HasAntenna2()) featureSet = featureSet | 0x02; if (metaData.HasBand()) featureSet = featureSet | 0x04; // if(metaData.HasField()) // featureSet = featureSet | 0x08; if (metaData.HasObservationTimes()) featureSet = featureSet | 0x10; // if(metaData.HasUVW()) // featureSet = featureSet | 0x20; Serializable::SerializeToUInt64(stream, featureSet); if (metaData.HasAntenna1()) metaData.Antenna1().Serialize(stream); if (metaData.HasAntenna2()) metaData.Antenna2().Serialize(stream); if (metaData.HasBand()) metaData.Band().Serialize(stream); if (metaData.HasObservationTimes()) { const std::vector& vals = metaData.ObservationTimes(); Serializable::SerializeToUInt64(stream, vals.size()); for (const double& t : vals) Serializable::SerializeToDouble(stream, t); } } void SingleBaselineFile::Serialize(std::ostream& stream, const Image2D& image) { Serializable::SerializeToUInt64(stream, image.Width()); Serializable::SerializeToUInt64(stream, image.Height()); for (size_t y = 0; y != image.Height(); ++y) { for (size_t x = 0; x != image.Width(); ++x) { Serializable::SerializeToFloat(stream, image.Value(x, y)); } } } void SingleBaselineFile::Serialize(std::ostream& stream, const Mask2D& mask) { Serializable::SerializeToUInt64(stream, mask.Width()); Serializable::SerializeToUInt64(stream, mask.Height()); for (size_t y = 0; y != mask.Height(); ++y) { for (size_t x = 0; x != mask.Width(); ++x) { const char val = mask.Value(x, y) ? 1 : 0; stream.write(&val, 1); } } } aoflagger-v3.4.0/msio/rawdescfile.h0000644000175000017500000000472314507760372015752 0ustar olesoles#ifndef RAWDESCFILE_H #define RAWDESCFILE_H #include #include #include #include "../util/logger.h" class RawDescFile { public: explicit RawDescFile(const std::string& filename) : _filename(filename) { readFile(); } size_t GetCount() const { return _sets.size(); } std::string GetSet(size_t index) const { return _sets[index]; } const std::string& Filename() const { return _filename; } unsigned BeamCount() const { return _beamCount; } unsigned SubbandCount() const { return _subbandCount; } unsigned ChannelsPerSubbandCount() const { return _channelsPerSubbandCount; } unsigned TimestepsPerBlockCount() const { return _timestepsPerBlockCount; } unsigned BlockHeaderSize() const { return _blockHeaderSize; } unsigned BlockFooterSize() const { return _blockFooterSize; } unsigned SelectedBeam() const { return _selectedBeam; } double TimeResolution() const { return _timeRes; } double DisplayedTimeDuration() const { return _displayedTimeDuration; } double FrequencyResolution() const { return _freqRes; } double FrequencyStart() const { return _freqStart; } private: const std::string _filename; std::vector _sets; unsigned _beamCount; unsigned _subbandCount; unsigned _channelsPerSubbandCount; unsigned _timestepsPerBlockCount; unsigned _blockHeaderSize; unsigned _blockFooterSize; unsigned _selectedBeam; double _timeRes; double _displayedTimeDuration; double _freqRes; double _freqStart; void readFile() { std::ifstream file(_filename.c_str()); std::string l; std::getline(file, l); _beamCount = (unsigned)atol(l.c_str()); std::getline(file, l); _subbandCount = (unsigned)atol(l.c_str()); std::getline(file, l); _channelsPerSubbandCount = (unsigned)atol(l.c_str()); std::getline(file, l); _timestepsPerBlockCount = (unsigned)atol(l.c_str()); std::getline(file, l); _blockHeaderSize = (unsigned)atol(l.c_str()); std::getline(file, l); _blockFooterSize = (unsigned)atol(l.c_str()); std::getline(file, l); _selectedBeam = (unsigned)atol(l.c_str()); std::getline(file, l); _timeRes = atof(l.c_str()); std::getline(file, l); _displayedTimeDuration = atof(l.c_str()); std::getline(file, l); _freqStart = atof(l.c_str()); std::getline(file, l); _freqRes = atof(l.c_str()); while (file.good()) { std::getline(file, l); if (l != "") _sets.push_back(l); } } }; #endif aoflagger-v3.4.0/msio/parmtable.h0000644000175000017500000002046614507760372015433 0ustar olesoles#ifndef PARM_TABLE_H #define PARM_TABLE_H #include #include #include #include #include #include #include "../util/logger.h" #include "../structures/image2d.h" #include "../structures/timefrequencydata.h" class ParmTable { public: struct GainNameEntry { int index; int x, y; enum Component { Real, Imaginary } component; std::string antenna; GainNameEntry() : index(0), x(0), y(0), component(Real), antenna() {} GainNameEntry(const GainNameEntry& source) : index(source.index), x(source.x), y(source.y), component(source.component), antenna(source.antenna) {} void operator=(const GainNameEntry& source) { index = source.index; x = source.x; y = source.y; component = source.component; antenna = source.antenna; } }; explicit ParmTable(const std::string& path) : _path(path) { readNames(); } std::set GetAntennas() const { std::set antennas; for (GainNameEntryMap::const_iterator i = _nameEntries.begin(); i != _nameEntries.end(); ++i) { const GainNameEntry& entry = i->second; antennas.insert(entry.antenna); } return antennas; } TimeFrequencyData Read(const std::string& antenna) { Logger::Debug << "Reading antenna " << antenna << "\n"; // find the nameid's that we need to select const int r00 = FindEntry(0, 0, GainNameEntry::Real, antenna).index, r11 = FindEntry(1, 1, GainNameEntry::Real, antenna).index, i00 = FindEntry(0, 0, GainNameEntry::Imaginary, antenna).index, i11 = FindEntry(1, 1, GainNameEntry::Imaginary, antenna).index; Logger::Debug << "Names: r00=" << r00 << ", " << "r11=" << r11 << ", " << "i00=" << i00 << ", " << "i11=" << i11 << "\n"; casacore::Table table(_path); // Construct the images unsigned width, height; getImageDimensions(table, width, height, r00, r11, i00, i11); Image2DPtr xxReal = Image2D::CreateZeroImagePtr(width, height), yyReal = Image2D::CreateZeroImagePtr(width, height), xxImag = Image2D::CreateZeroImagePtr(width, height), yyImag = Image2D::CreateZeroImagePtr(width, height); // Read data casacore::ROScalarColumn nameIdColumn(table, "NAMEID"); casacore::ROScalarColumn startX(table, "STARTX"), startY(table, "STARTY"); casacore::ROArrayColumn values(table, "VALUES"); int xPos = 0, yPos = 0; // double currentX=startX(0); double currentY = startY(0); unsigned r00Count = 0, r11Count = 0, i00Count = 0, i11Count = 0; unsigned curXShape = 0; unsigned componentMatches = 0; for (unsigned row = 0; row < table.nrow(); ++row) { int nameId = nameIdColumn(row); if (nameId == r00 || nameId == r11 || nameId == i00 || nameId == i11) { Image2DPtr destImage; if (nameId == r00) { destImage = xxReal; ++r00Count; } else if (nameId == r11) { destImage = yyReal; ++r11Count; } else if (nameId == i00) { destImage = xxImag; ++i00Count; } else if (nameId == i11) { destImage = yyImag; ++i11Count; } const unsigned curYShape = values.shape(row)[1]; const unsigned xShape = values.shape(row)[0]; if (xShape > curXShape) curXShape = xShape; Logger::Debug << "Image has size " << xShape << " x " << curYShape << '\n'; const casacore::Array valueArray = values(row); casacore::Array::const_iterator vIter = valueArray.begin(); for (unsigned y = 0; y < curYShape; ++y) { for (unsigned x = 0; x < xShape; ++x) { destImage->SetValue(yPos + y, xPos + x, *vIter); ++vIter; } } ++componentMatches; if (componentMatches >= 4) { if (startY(row) < currentY) { xPos += curXShape; yPos = 0; curXShape = 0; } else { yPos += curYShape; } // currentX=startX(row); currentY = startY(row); componentMatches = 0; } } } Logger::Debug << "Counts: r00=" << r00Count << ", " << "r11=" << r11Count << ", " << "i00=" << i00Count << ", " << "i11=" << i11Count << "\n"; return TimeFrequencyData(aocommon::Polarization::XX, xxReal, xxImag, aocommon::Polarization::YY, yyReal, yyImag); } const GainNameEntry& FindEntry(int x, int y, enum GainNameEntry::Component c, const std::string& antenna) const { for (GainNameEntryMap::const_iterator i = _nameEntries.begin(); i != _nameEntries.end(); ++i) { const GainNameEntry& entry = i->second; if (entry.x == x && entry.y == y && entry.component == c && entry.antenna == antenna) { return entry; } } throw std::runtime_error("Entry not found"); } private: void readNames() { casacore::Table namesTable; if (_path.size() > 0 && *_path.rbegin() != '/') namesTable = casacore::Table(_path + "/NAMES"); else namesTable = casacore::Table(_path + "NAMES"); casacore::ROScalarColumn nameColumn(namesTable, "NAME"); for (unsigned i = 0; i != namesTable.nrow(); ++i) { std::string name = nameColumn(i); addName(i, name); } } void getImageDimensions(casacore::Table& table, unsigned& width, unsigned& height, int r00, int /*r11*/, int /*i00*/, int /*i11*/) { casacore::ROScalarColumn nameIdColumn(table, "NAMEID"); casacore::ROScalarColumn startX(table, "STARTX"), startY(table, "STARTY"); casacore::ROArrayColumn values(table, "VALUES"); int maxX = 0, yPos = 0; int maxY = 0; unsigned matches = 0; unsigned curXShape = 0; double currentX = startX(0), currentY = startY(0); for (unsigned row = 0; row < table.nrow(); ++row) { int nameId = nameIdColumn(row); if (nameId == r00) { const unsigned curYShape = values.shape(row)[1]; if (values.shape(row)[0] > (int)curXShape) curXShape = values.shape(row)[0]; if (startX(row) < currentX) throw std::runtime_error("Table is not correctly ordered"); yPos += curYShape; if (startY(row) < currentY) { maxX += curXShape; curXShape = 0; if (yPos > maxY) maxY = yPos; yPos = 0; } currentX = startX(row); currentY = startY(row); ++matches; } } maxX += curXShape; if (yPos > maxY) maxY = yPos; width = maxY; height = maxX; Logger::Debug << "Rows in table: " << table.nrow() << "\n" "Matching rows: " << matches << "\n" "Number of blocks: " << maxX << " x " << maxY << "\n" "Image size: " << width << " x " << height << "\n"; } void addName(unsigned index, const std::string& line) { size_t d1 = line.find(':'); std::string type = line.substr(0, d1); if (type == "Gain") { GainNameEntry entry; size_t d2 = line.find(':', d1 + 1), d3 = line.find(':', d2 + 1), d4 = line.find(':', d3 + 1); entry.index = index; entry.x = atoi(line.substr(d1 + 1, d2 - d1 - 1).c_str()); entry.y = atoi(line.substr(d2 + 1, d3 - d2 - 1).c_str()); std::string component = line.substr(d3 + 1, d4 - d3 - 1); if (component == "Real") entry.component = GainNameEntry::Real; else if (component == "Imag") entry.component = GainNameEntry::Imaginary; else throw std::runtime_error("Incorrect complex component type given"); entry.antenna = line.substr(d4 + 1); _nameEntries.insert(std::pair(index, entry)); } } std::string _path; typedef std::map GainNameEntryMap; GainNameEntryMap _nameEntries; }; #endif aoflagger-v3.4.0/msio/baselinereader.cpp0000644000175000017500000001630714507760372016763 0ustar olesoles#include "baselinereader.h" #include #include #include #include #include #include #include #include #include #include #include "../util/progress/dummyprogresslistener.h" #include "../structures/timefrequencydata.h" #include "../util/logger.h" DummyProgressListener BaselineReader::dummy_progress_; BaselineReader::BaselineReader(const std::string& msFile) : _msMetaData(msFile), _dataColumnName("DATA"), _readData(true), _readFlags(true), _polarizations() {} BaselineReader::~BaselineReader() {} void BaselineReader::initObservationTimes() { if (_observationTimes.empty()) { Logger::Debug << "Initializing observation times...\n"; const size_t sequenceCount = _msMetaData.SequenceCount(); _observationTimes.resize(sequenceCount); for (size_t sequenceId = 0; sequenceId != sequenceCount; ++sequenceId) { const std::set& times = _msMetaData.GetObservationTimesSet(sequenceId); unsigned index = 0; for (const double t : times) { _observationTimes[sequenceId].emplace(t, index); _observationTimesVector.push_back(t); ++index; } } } } void BaselineReader::AddReadRequest(size_t antenna1, size_t antenna2, size_t spectralWindow, size_t sequenceId) { initObservationTimes(); addReadRequest(antenna1, antenna2, spectralWindow, sequenceId, 0, _observationTimes[sequenceId].size()); } TimeFrequencyData BaselineReader::GetNextResult(std::vector& uvw) { const size_t requestIndex = 0; TimeFrequencyData data; data = TimeFrequencyData(_polarizations.data(), _polarizations.size(), _results[requestIndex]._realImages.data(), _results[requestIndex]._imaginaryImages.data()); data.SetIndividualPolarizationMasks(_results[requestIndex]._flags.data()); uvw = _results[0]._uvw; _results.erase(_results.begin() + requestIndex); return data; } void BaselineReader::initializePolarizations() { if (_polarizations.empty()) { casacore::MeasurementSet ms(_msMetaData.Path()); const casacore::MSDataDescription ddTable = ms.dataDescription(); if (ddTable.nrow() == 0) throw std::runtime_error("DataDescription table is empty"); const casacore::ScalarColumn polIdColumn( ddTable, casacore::MSDataDescription::columnName( casacore::MSDataDescription::POLARIZATION_ID)); const int polarizationId = polIdColumn(0); for (size_t row = 0; row != ddTable.nrow(); ++row) { if (polIdColumn(row) != polarizationId) throw std::runtime_error( "This measurement set has different polarizations listed in the " "datadescription table. This is non-standard, and AOFlagger cannot " "handle it."); } const casacore::Table polTable = ms.polarization(); const casacore::ArrayColumn corTypeColumn(polTable, "CORR_TYPE"); casacore::Array corType = corTypeColumn(polarizationId); const casacore::Array::iterator iterend(corType.end()); for (casacore::Array::iterator iter = corType.begin(); iter != iterend; ++iter) { const aocommon::PolarizationEnum polarization = aocommon::Polarization::AipsIndexToEnum(*iter); _polarizations.push_back(polarization); } } } /** * Returns an estimate of the size of the data of the MS. * * One thing that might be problematic, is that this function isn't aware of * different spectral windows ("SPW") or different scans. Unlike Dp3, AOFlagger * is used also for telescopes like JVLA that don't necessarily store all times * together. The readers do support it; the unit of a single contiguous stream * of data is called a sequence there. In rare occassions, the timesteps might * not divide the measurement set "linearly" in those cases (e.g. the scan may * use 10 Spws, whereas the second one uses 1, and both might have the same nr * of timesteps -- in which case the second one would take only 1/11th of the * obs). This is a bit more rare though, and it is after all only an estimate, * so maybe we can live with this until we get a bug report :). */ static uint64_t GetMeasurementSetDataSize(casacore::MeasurementSet& ms) { const casacore::MSSpectralWindow spwTable = ms.spectralWindow(); const casacore::ScalarColumn numChanCol( spwTable, casacore::MSSpectralWindow::columnName( casacore::MSSpectralWindowEnums::NUM_CHAN)); const size_t channelCount = numChanCol.get(0); if (channelCount == 0) throw std::runtime_error("No channels in set"); if (ms.nrow() == 0) throw std::runtime_error("Table has no rows (no data)"); typedef float num_t; typedef std::complex complex_t; const casacore::ScalarColumn ant1Column( ms, ms.columnName(casacore::MSMainEnums::ANTENNA1)); const casacore::ScalarColumn ant2Column( ms, ms.columnName(casacore::MSMainEnums::ANTENNA2)); const casacore::ArrayColumn dataColumn( ms, ms.columnName(casacore::MSMainEnums::DATA)); casacore::IPosition dataShape = dataColumn.shape(0); const unsigned polarizationCount = dataShape[0]; return (uint64_t)polarizationCount * (uint64_t)channelCount * (uint64_t)ms.nrow() * (uint64_t)(sizeof(num_t) * 2 + sizeof(bool)); } uint64_t BaselineReader::MeasurementSetDataSize(const string& filename) { casacore::MeasurementSet ms(filename); return GetMeasurementSetDataSize(ms); } static size_t GetNTimeSteps(casacore::MeasurementSet& ms) { size_t result = 0; double time = -1.0; const casacore::ScalarColumn time_column{ ms, ms.columnName(casacore::MSMainEnums::TIME)}; for (size_t i = 0; i != ms.nrow(); ++i) if (const double t = time_column(i); t != time) { ++result; time = t; } return result; } static uint64_t GetMeasurementSetIntervalDataSize(const string& filename, size_t start, size_t end) { assert(start <= end && "Reqested begin and end aren't a valid range"); casacore::MeasurementSet ms(filename); const uint64_t result = GetMeasurementSetDataSize(ms); const size_t time_steps_ms = GetNTimeSteps(ms); const size_t time_steps_requested = end - start; // When more time steps are requested than available use the available number. // Validate time_steps_ms to avoid a division by zero. if (time_steps_requested >= time_steps_ms || time_steps_ms == 0) return result; return result * static_cast(time_steps_requested) / time_steps_ms; } uint64_t BaselineReader::MeasurementSetIntervalDataSize( const string& filename, std::optional start, std::optional end) { if (start) { assert(end && "The engagement status of start and end should be the same."); return GetMeasurementSetIntervalDataSize(filename, *start, *end); } return BaselineReader::MeasurementSetDataSize(filename); } aoflagger-v3.4.0/msio/pngfile.cpp0000644000175000017500000000415314507760372015436 0ustar olesoles#include "pngfile.h" #include PngFile::PngFile(const std::string& filename, size_t width, size_t height) : _filename(filename), _width(width), _height(height), _pixelSize(4) {} PngFile::~PngFile() {} void PngFile::BeginWrite() { _fp = fopen(_filename.c_str(), "wb"); if (!_fp) throw std::runtime_error("Can not open file"); _png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp) nullptr, nullptr, nullptr); if (!_png_ptr) { fclose(_fp); throw std::runtime_error("Can not create png write structure"); } _info_ptr = png_create_info_struct(_png_ptr); if (!_info_ptr) { png_destroy_write_struct(&_png_ptr, (png_infopp) nullptr); fclose(_fp); throw std::runtime_error("Can not write info structure to file"); } if (setjmp(png_jmpbuf(_png_ptr))) { png_destroy_write_struct(&_png_ptr, &_info_ptr); fclose(_fp); throw std::runtime_error( "Unknown error occured during writing of png file"); } png_init_io(_png_ptr, _fp); png_set_IHDR(_png_ptr, _info_ptr, _width, _height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); _row_pointers = (png_bytep*)png_malloc(_png_ptr, _height * sizeof(png_bytep)); for (size_t i = 0; i < _height; i++) _row_pointers[i] = (png_bytep)png_malloc(_png_ptr, _width * _pixelSize); } void PngFile::Close() { png_set_rows(_png_ptr, _info_ptr, _row_pointers); png_write_png(_png_ptr, _info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); png_write_end(_png_ptr, _info_ptr); for (unsigned i = 0; i < _height; i++) png_free(_png_ptr, _row_pointers[i]); png_free(_png_ptr, _row_pointers); png_destroy_write_struct(&_png_ptr, &_info_ptr); fclose(_fp); } void PngFile::Clear(int colorR, int colorG, int colorB, int colorA) { for (size_t y = 0; y < _height; y++) { int xa = 0; for (unsigned x = 0; x < _width; x++) { _row_pointers[y][xa++] = colorR; _row_pointers[y][xa++] = colorG; _row_pointers[y][xa++] = colorB; _row_pointers[y][xa++] = colorA; } } } aoflagger-v3.4.0/imaging/0000755000175000017500000000000014516225226013741 5ustar olesolesaoflagger-v3.4.0/imaging/defaultmodels.h0000644000175000017500000000373214507760372016755 0ustar olesoles#ifndef DEFAULTMODELS_H #define DEFAULTMODELS_H #include #include "model.h" #include "observatorium.h" enum class SourceSet { NoDistortion, ConstantDistortion, StrongVariableDistortion, FaintVariableDistortion }; class DefaultModels { public: enum SetLocation { EmptySet, NCPSet }; static double DistortionRA() { return 4.940; } static double DistortionDec() { return 0.571; } static std::pair LoadSet( enum SetLocation setLocation, enum SourceSet distortion, double noiseSigma, size_t channelCount = 64, double bandwidth = 2500000.0 * 16.0, unsigned a1 = 0, unsigned a2 = 5) { double ra, dec, factor; getSetData(setLocation, ra, dec, factor); Model model; model.SetNoiseSigma(noiseSigma); if (setLocation != EmptySet) model.loadUrsaMajor(ra, dec, factor); switch (distortion) { case SourceSet::NoDistortion: break; case SourceSet::ConstantDistortion: model.loadUrsaMajorDistortingSource(ra, dec, factor, true); break; case SourceSet::StrongVariableDistortion: model.loadUrsaMajorDistortingVariableSource(ra, dec, factor, false, false); break; case SourceSet::FaintVariableDistortion: model.loadUrsaMajorDistortingVariableSource(ra, dec, factor, true, false); break; } WSRTObservatorium wsrtObservatorium(channelCount, bandwidth); return model.SimulateObservation(12 * 60 * 60 / 15, wsrtObservatorium, dec, ra, a1, a2); } private: static void getSetData(enum SetLocation setLocation, double& ra, double& dec, double& factor) { if (setLocation == NCPSet) { dec = 0.5 * M_PI + 0.12800; ra = -0.03000; factor = 1.0; } else { dec = 1.083; ra = 4.865; factor = 4.0; } } }; #endif aoflagger-v3.4.0/imaging/uvimager.h0000644000175000017500000001622414507760372015744 0ustar olesoles#ifndef UVIMAGER_H #define UVIMAGER_H #include #include "../structures/timefrequencymetadata.h" #include "../structures/date.h" #include "../structures/timefrequencydata.h" struct SingleFrequencySingleBaselineData { std::complex data; bool flag; bool available; double time; unsigned field; }; class UVImager { public: enum ImageKind { Homogeneous, Flagging }; UVImager(unsigned long xRes, unsigned long yRes, ImageKind imageKind = Homogeneous); ~UVImager(); void Image(class MSMetaData& msMetaData, unsigned band); void Image(class MSMetaData& msMetaData, unsigned band, const class IntegerDomain& frequencies); void Image(const class TimeFrequencyData& data, TimeFrequencyMetaDataCPtr metaData, unsigned frequencyIndex); void Image(const class TimeFrequencyData& data, TimeFrequencyMetaDataCPtr metaData) { for (unsigned y = 0; y < data.ImageHeight(); ++y) Image(data, metaData, y); } void Image(const class TimeFrequencyData& data, class SpatialMatrixMetaData* metaData); void InverseImage(class MSMetaData& prototype, unsigned band, const class Image2D& uvReal, const class Image2D& uvImaginary, unsigned antenna1, unsigned antenna2); const class Image2D& WeightImage() const { return _uvWeights; } const class Image2D& RealUVImage() const { return _uvReal; } const class Image2D& ImaginaryUVImage() const { return _uvImaginary; } void SetInvertFlagging(bool newValue) { _invertFlagging = newValue; } void SetDirectFT(bool directFT) { _directFT = directFT; } /** * This function calculates the uv position, but it's not optimized for speed, * so it's not to be used in an imager. * @param [out] u the u position (in the uv-plane domain) * @param [out] v the v position (in the uv-plane domain) * @param [in] timeIndex the time index to calculate the u,v position for * @param [in] frequencyIndex the frequency index to calculate the u,v * position for * @param [in] metaData information about the baseline */ static void GetUVPosition(num_t& u, num_t& v, size_t timeIndex, size_t frequencyIndex, TimeFrequencyMetaDataCPtr metaData); static num_t GetFringeStopFrequency(size_t time, const Baseline& baseline, num_t delayDirectionRA, num_t delayDirectionDec, num_t frequency, TimeFrequencyMetaDataCPtr metaData); // static double GetFringeCount(long double timeStart, long double timeEnd, // const Baseline &baseline, long double delayDirectionRA, long double // delayDirectionDec, long double frequency); static num_t GetFringeCount(size_t timeIndexStart, size_t timeIndexEnd, unsigned channelIndex, TimeFrequencyMetaDataCPtr metaData); static numl_t GetWPosition(numl_t delayDirectionDec, numl_t delayDirectionRA, numl_t frequency, numl_t earthLattitudeAngle, numl_t dx, numl_t dy) { numl_t wavelength = 299792458.0L / frequency; numl_t raSinEnd = sinn(-delayDirectionRA - earthLattitudeAngle); numl_t raCosEnd = cosn(-delayDirectionRA - earthLattitudeAngle); numl_t decCos = cosn(delayDirectionDec); // term "+ dz * decCos" is eliminated because of subtraction num_t wPosition = (dx * raCosEnd - dy * raSinEnd) * (-decCos) / wavelength; return wPosition; } static numl_t TimeToEarthLattitude(unsigned x, TimeFrequencyMetaDataCPtr metaData) { return TimeToEarthLattitude(metaData->ObservationTimes()[x]); } static numl_t TimeToEarthLattitude(double time) { return time * M_PInl / (12.0 * 60.0 * 60.0); } void Empty(); void PerformFFT(); bool HasUV() const { return !_uvReal.Empty(); } bool HasFFT() const { return !_uvFTReal.Empty(); } const class Image2D& FTReal() const { return _uvFTReal; } const class Image2D& FTImaginary() const { return _uvFTImaginary; } class Image2D& FTReal() { return _uvFTReal; } class Image2D& FTImaginary() { return _uvFTImaginary; } void SetUVScaling(num_t newScale) { _uvScaling = newScale; } num_t UVScaling() const { return _uvScaling; } void ApplyWeightsToUV(); void SetUVValue(num_t u, num_t v, num_t r, num_t i, num_t weight); template static T FrequencyToWavelength(const T frequency) { return SpeedOfLight() / frequency; } static long double SpeedOfLight() { return 299792458.0L; } numl_t ImageDistanceToDecRaDistance(numl_t imageDistance) const { return imageDistance * _uvScaling; } static numl_t AverageUVDistance(TimeFrequencyMetaDataCPtr metaData, const double frequencyHz) { const std::vector& uvw = metaData->UVW(); numl_t avgDist = 0.0; for (std::vector::const_iterator i = uvw.begin(); i != uvw.end(); ++i) { numl_t dist = i->u * i->u + i->v * i->v; avgDist += sqrtnl(dist); } return avgDist * frequencyHz / (SpeedOfLight() * (numl_t)uvw.size()); } static numl_t UVTrackLength(TimeFrequencyMetaDataCPtr metaData, const double frequencyHz) { const std::vector& uvw = metaData->UVW(); numl_t length = 0.0; std::vector::const_iterator i = uvw.begin(); if (i == uvw.end()) return 0.0; while ((i + 1) != uvw.end()) { std::vector::const_iterator n = i; ++n; const numl_t du = n->u - i->u, dv = n->v - i->v; length += sqrtnl(du * du + dv * dv); i = n; } return length * frequencyHz / SpeedOfLight(); } numl_t ImageDistanceToFringeSpeedInSamples( numl_t imageDistance, double frequencyHz, TimeFrequencyMetaDataCPtr metaData) const { return ImageDistanceToDecRaDistance(imageDistance) * AverageUVDistance(metaData, frequencyHz) / (0.5 * (numl_t)metaData->UVW().size()); } private: void Clear(); struct AntennaCache { num_t wavelength; num_t dx, dy, dz; }; void Image(const class IntegerDomain& frequencies); void Image(const IntegerDomain& frequencies, const IntegerDomain& antenna1Domain, const IntegerDomain& antenna2Domain); void Image(unsigned frequencyIndex, class AntennaInfo& antenna1, class AntennaInfo& antenna2, SingleFrequencySingleBaselineData* data); // This is the fast variant. void GetUVPosition(num_t& u, num_t& v, const SingleFrequencySingleBaselineData& data, const AntennaCache& cache); void SetUVFTValue(num_t u, num_t v, num_t r, num_t i, num_t weight); unsigned long _xRes, _yRes; unsigned long _xResFT, _yResFT; num_t _uvScaling; class Image2D _uvReal, _uvImaginary, _uvWeights; class Image2D _uvFTReal, _uvFTImaginary; class Image2D _timeFreq; MSMetaData* _msMetaData; unsigned _antennaCount, _fieldCount; AntennaInfo* _antennas; BandInfo _band; FieldInfo* _fields; size_t _scanCount; ImageKind _imageKind; bool _invertFlagging, _directFT; bool _ignoreBoundWarnings; }; #endif aoflagger-v3.4.0/imaging/uvimager.cpp0000644000175000017500000004554314507760372016305 0ustar olesoles#include "uvimager.h" #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../structures/msmetadata.h" #include "../structures/spatialmatrixmetadata.h" #include "../structures/timefrequencydata.h" #include "../util/integerdomain.h" #include "../util/stopwatch.h" #include "../util/ffttools.h" #include #include #include UVImager::UVImager(unsigned long xRes, unsigned long yRes, ImageKind imageKind) : _xRes(xRes), _yRes(yRes), _xResFT(xRes), _yResFT(yRes), _uvReal(), _uvImaginary(), _uvWeights(), _uvFTReal(), _uvFTImaginary(), _antennas(nullptr), _fields(nullptr), _imageKind(imageKind), _invertFlagging(false), _directFT(false), _ignoreBoundWarnings(false) { _uvScaling = 0.0001L; // testing Empty(); } UVImager::~UVImager() { Clear(); } void UVImager::Clear() { if (_antennas != nullptr) { delete[] _antennas; _antennas = nullptr; } if (_fields != nullptr) { delete[] _fields; _fields = nullptr; } } void UVImager::Empty() { Clear(); _uvReal = Image2D::MakeZeroImage(_xRes, _yRes); _uvImaginary = Image2D::MakeZeroImage(_xRes, _yRes); _uvWeights = Image2D::MakeZeroImage(_xRes, _yRes); _uvFTReal = Image2D::MakeZeroImage(_xRes, _yRes); _uvFTImaginary = Image2D::MakeZeroImage(_xRes, _yRes); } void UVImager::Image(MSMetaData& msMetaData, unsigned band) { const unsigned frequencyCount = msMetaData.FrequencyCount(band); const IntegerDomain frequencies(0, frequencyCount); _msMetaData = &msMetaData; _band = _msMetaData->GetBandInfo(band); Image(frequencies); } void UVImager::Image(class MSMetaData& msMetaData, unsigned band, const IntegerDomain& frequencies) { _msMetaData = &msMetaData; _band = _msMetaData->GetBandInfo(band); Image(frequencies); } void UVImager::Image(const IntegerDomain& frequencies) { Empty(); _antennaCount = _msMetaData->AntennaCount(); _antennas = new AntennaInfo[_antennaCount]; for (unsigned i = 0; i < _antennaCount; ++i) _antennas[i] = _msMetaData->GetAntennaInfo(i); _fieldCount = _msMetaData->FieldCount(); _fields = new FieldInfo[_fieldCount]; for (unsigned i = 0; i < _fieldCount; ++i) _fields[i] = _msMetaData->GetFieldInfo(i); const unsigned parts = (frequencies.ValueCount() - 1) / 48 + 1; for (unsigned i = 0; i < parts; ++i) { std::cout << "Imaging " << i << "/" << parts << ":" << frequencies.Split(parts, i).ValueCount() << " frequencies..." << std::endl; Image(frequencies.Split(parts, i), IntegerDomain(0, _antennaCount), IntegerDomain(0, _antennaCount)); } } /** * Add several frequency channels to the uv plane for several combinations * of antenna pairs. */ void UVImager::Image(const IntegerDomain& frequencies, const IntegerDomain& antenna1Domain, const IntegerDomain& antenna2Domain) { _scanCount = _msMetaData->TimestepCount(); std::cout << "Requesting " << frequencies.ValueCount() << " x " << antenna1Domain.ValueCount() << " x " << antenna2Domain.ValueCount() << " x " << _scanCount << " x " << sizeof(SingleFrequencySingleBaselineData) << " = " << (frequencies.ValueCount() * antenna1Domain.ValueCount() * antenna2Domain.ValueCount() * _scanCount * sizeof(SingleFrequencySingleBaselineData) / (1024 * 1024)) << "MB of memory..." << std::endl; SingleFrequencySingleBaselineData**** data = new SingleFrequencySingleBaselineData***[frequencies.ValueCount()]; for (unsigned f = 0; f < frequencies.ValueCount(); ++f) { data[f] = new SingleFrequencySingleBaselineData**[antenna1Domain.ValueCount()]; for (unsigned a1 = 0; a1 < antenna1Domain.ValueCount(); ++a1) { data[f][a1] = new SingleFrequencySingleBaselineData*[antenna2Domain.ValueCount()]; for (unsigned a2 = 0; a2 < antenna2Domain.ValueCount(); ++a2) { data[f][a1][a2] = new SingleFrequencySingleBaselineData[_scanCount]; for (unsigned scan = 0; scan < _scanCount; ++scan) { data[f][a1][a2][scan].flag = true; data[f][a1][a2][scan].available = false; } } } } std::cout << "Reading all data for " << frequencies.ValueCount() << " frequencies..." << std::flush; Stopwatch stopwatch(true); const casacore::MeasurementSet ms(_msMetaData->Path()); const casacore::ScalarColumn antenna1Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA1)); const casacore::ScalarColumn antenna2Col( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::ANTENNA2)); const casacore::ScalarColumn fieldIdCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::FIELD_ID)); const casacore::ScalarColumn dataDescIdCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::DATA_DESC_ID)); const casacore::ScalarColumn timeCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::TIME)); const casacore::ScalarColumn scanNumberCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::SCAN_NUMBER)); const casacore::ArrayColumn correctedDataCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::CORRECTED_DATA)); const casacore::ArrayColumn flagCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::FLAG)); const size_t rows = ms.nrow(); for (unsigned row = 0; row != rows; ++row) { const unsigned a1 = antenna1Col(row); const unsigned a2 = antenna2Col(row); if (antenna1Domain.IsIn(a1) && antenna2Domain.IsIn(a2)) { const unsigned scan = scanNumberCol(row); const unsigned index1 = antenna1Domain.Index(a1); const unsigned index2 = antenna1Domain.Index(a2); const int field = fieldIdCol(row); const double time = timeCol(row); casacore::Array dataArr = correctedDataCol(row); casacore::Array flagArr = flagCol(row); casacore::Array::const_iterator cdI = dataArr.begin(); casacore::Array::const_iterator fI = flagArr.begin(); for (int f = 0; f < frequencies.GetValue(0); ++f) { ++fI; ++fI; ++fI; ++fI; ++cdI; ++cdI; ++cdI; ++cdI; } for (unsigned f = 0; f < frequencies.ValueCount(); ++f) { SingleFrequencySingleBaselineData& curData = data[f][index1][index2][scan]; const casacore::Complex xxData = *cdI; ++cdI; ++cdI; ++cdI; const casacore::Complex yyData = *cdI; ++cdI; curData.data = xxData + yyData; bool flagging = *fI; ++fI; ++fI; ++fI; flagging = flagging || *fI; ++fI; curData.flag = flagging; curData.field = field; curData.time = time; curData.available = true; } } } stopwatch.Pause(); std::cout << "DONE in " << stopwatch.ToString() << " (" << (stopwatch.Seconds() / (antenna1Domain.ValueCount() * antenna1Domain.ValueCount())) << "s/antenna)" << std::endl; std::cout << "Imaging..." << std::flush; stopwatch.Reset(); stopwatch.Start(); for (unsigned f = 0; f < frequencies.ValueCount(); ++f) { for (unsigned a1 = 0; a1 < antenna1Domain.ValueCount(); ++a1) { for (unsigned a2 = 0; a2 < antenna2Domain.ValueCount(); ++a2) { Image(frequencies.GetValue(f), _antennas[antenna1Domain.GetValue(a1)], _antennas[antenna2Domain.GetValue(a2)], data[f][a1][a2]); } } } stopwatch.Pause(); std::cout << "DONE in " << stopwatch.ToString() << " (" << (stopwatch.Seconds() / (antenna1Domain.ValueCount() * antenna1Domain.ValueCount())) << "s/antenna)" << std::endl; // free data for (unsigned f = 0; f < frequencies.ValueCount(); ++f) { for (unsigned a1 = 0; a1 < antenna1Domain.ValueCount(); ++a1) { for (unsigned a2 = 0; a2 < antenna2Domain.ValueCount(); ++a2) { delete[] data[f][a1][a2]; } delete[] data[f][a1]; } delete[] data[f]; } delete[] data; } void UVImager::Image(unsigned frequencyIndex, AntennaInfo& antenna1, AntennaInfo& antenna2, SingleFrequencySingleBaselineData* data) { const num_t frequency = _band.channels[frequencyIndex].frequencyHz; const num_t speedOfLight = 299792458.0L; AntennaCache cache; cache.wavelength = speedOfLight / frequency; // dx, dy, dz is the baseline cache.dx = antenna1.position.x - antenna2.position.x; cache.dy = antenna1.position.y - antenna2.position.y; cache.dz = antenna1.position.z - antenna2.position.z; for (unsigned i = 0; i < _scanCount; ++i) { if (data[i].available) { switch (_imageKind) { case Homogeneous: if (!data[i].flag) { num_t u, v; GetUVPosition(u, v, data[i], cache); SetUVValue(u, v, data[i].data.real(), data[i].data.imag(), 1.0); SetUVValue(-u, -v, data[i].data.real(), -data[i].data.imag(), 1.0); // calcTimer.Pause(); } break; case Flagging: if ((data[i].flag && !_invertFlagging) || (!data[i].flag && _invertFlagging)) { num_t u, v; GetUVPosition(u, v, data[i], cache); SetUVValue(u, v, 1, 0, 1.0); SetUVValue(-u, -v, 1, 0, 1.0); } break; } } } } void UVImager::Image(const class TimeFrequencyData& data, class SpatialMatrixMetaData* metaData) { if (!_uvReal.Empty()) Empty(); Image2DCPtr real = data.GetRealPart(), imaginary = data.GetImaginaryPart(); const Mask2DCPtr flags = data.GetSingleMask(); for (unsigned a2 = 0; a2 < data.ImageHeight(); ++a2) { for (unsigned a1 = a2 + 1; a1 < data.ImageWidth(); ++a1) { num_t vr = real->Value(a1, a2), vi = imaginary->Value(a1, a2); if (std::isfinite(vr) && std::isfinite(vi)) { const UVW uvw = metaData->UVW(a1, a2); SetUVValue(uvw.u, uvw.v, vr, vi, 1.0); SetUVValue(-uvw.u, -uvw.v, vr, -vi, 1.0); } } } } void UVImager::Image(const TimeFrequencyData& data, TimeFrequencyMetaDataCPtr metaData, unsigned frequencyIndex) { if (!_uvReal.Empty()) Empty(); Image2DCPtr real = data.GetRealPart(), imaginary = data.GetImaginaryPart(); const Mask2DCPtr flags = data.GetSingleMask(); for (unsigned i = 0; i < data.ImageWidth(); ++i) { switch (_imageKind) { case Homogeneous: if (flags->Value(i, frequencyIndex) == 0.0L) { num_t vr = real->Value(i, frequencyIndex), vi = imaginary->Value(i, frequencyIndex); if (std::isfinite(vr) && std::isfinite(vi)) { num_t u, v; GetUVPosition(u, v, i, frequencyIndex, metaData); SetUVValue(u, v, vr, vi, 1.0); SetUVValue(-u, -v, vr, -vi, 1.0); } } break; case Flagging: if ((flags->Value(i, frequencyIndex) != 0.0L && !_invertFlagging) || (flags->Value(i, frequencyIndex) == 0.0L && _invertFlagging)) { num_t u, v; GetUVPosition(u, v, i, frequencyIndex, metaData); SetUVValue(u, v, 1, 0, 1.0); SetUVValue(-u, -v, 1, 0, 1.0); } break; } } } void UVImager::ApplyWeightsToUV() { const double normFactor = _uvWeights.Sum() / ((num_t)_uvReal.Height() * _uvReal.Width()); for (size_t y = 0; y < _uvReal.Height(); ++y) { for (size_t x = 0; x < _uvReal.Width(); ++x) { const num_t weight = _uvWeights.Value(x, y); if (weight != 0.0) { _uvReal.SetValue(x, y, _uvReal.Value(x, y) * normFactor / weight); _uvImaginary.SetValue(x, y, _uvImaginary.Value(x, y) * normFactor / weight); _uvWeights.SetValue(x, y, 1.0); } } } _uvFTReal = Image2D(); _uvFTImaginary = Image2D(); } void UVImager::SetUVValue(num_t u, num_t v, num_t r, num_t i, num_t weight) { // Nearest neighbour interpolation const long uPos = (long)floorn(u * _uvScaling * _xRes + 0.5) + (_xRes / 2); const long vPos = (long)floorn(v * _uvScaling * _yRes + 0.5) + (_yRes / 2); if (uPos >= 0 && uPos < (long)_xRes && vPos >= 0 && vPos < (long)_yRes) { _uvReal.AddValue(uPos, vPos, r); _uvImaginary.AddValue(uPos, vPos, i); _uvWeights.AddValue(uPos, vPos, weight); } else { if (!_ignoreBoundWarnings) { std::cout << "Warning! Baseline outside uv window (" << uPos << "," << vPos << ")." << "(subsequent out of bounds warnings will not be noted)" << std::endl; _ignoreBoundWarnings = true; } } // Linear interpolation /*long uPos = (long) floor(u*_uvScaling*_xRes+0.5L) + _xRes/2; long vPos = (long) floor(v*_uvScaling*_yRes+0.5L) + _yRes/2; if(uPos>=0 && uPos<(long) _xRes && vPos>=0 && vPos<(long) _yRes) { long double dx = (long double) uPos - (_xRes/2) - (u*_uvScaling*_xRes+0.5L); long double dy = (long double) vPos - (_yRes/2) - (v*_uvScaling*_yRes+0.5L); long double distance = sqrtn(dx*dx + dy*dy); if(distance > 1.0) distance = 1.0; weight *= distance; _uvReal.AddValue(uPos, vPos, r*weight); _uvImaginary.AddValue(uPos, vPos, i*weight); _uvWeights.AddValue(uPos, vPos, weight); } else { std::cout << "Warning! Baseline outside uv window (" << uPos << "," << vPos << ")." << std::endl; }*/ } void UVImager::SetUVFTValue(num_t u, num_t v, num_t r, num_t i, num_t weight) { for (size_t iy = 0; iy < _yResFT; ++iy) { for (size_t ix = 0; ix < _xResFT; ++ix) { const num_t x = ((num_t)ix - (_xResFT / 2)) / _uvScaling * _uvFTReal.Width(); const num_t y = ((num_t)iy - (_yResFT / 2)) / _uvScaling * _uvFTReal.Height(); // Calculate F(x,y) += f(u, v) e ^ {i 2 pi (x u + y v) } const num_t fftRotation = (u * x + v * y) * -2.0L * M_PIn; num_t fftCos = cosn(fftRotation), fftSin = sinn(fftRotation); _uvFTReal.AddValue(ix, iy, (fftCos * r - fftSin * i) * weight); _uvFTImaginary.AddValue(ix, iy, (fftSin * r + fftCos * i) * weight); } } } void UVImager::PerformFFT() { if (!_uvFTReal.Empty()) { _uvFTReal = Image2D::MakeZeroImage(_xRes, _yRes); _uvFTImaginary = Image2D::MakeZeroImage(_xRes, _yRes); } FFTTools::CreateFFTImage(_uvReal, _uvImaginary, _uvFTReal, _uvFTImaginary); } void UVImager::GetUVPosition(num_t& u, num_t& v, size_t timeIndex, size_t frequencyIndex, TimeFrequencyMetaDataCPtr metaData) { const num_t frequency = metaData->Band().channels[frequencyIndex].frequencyHz; u = metaData->UVW()[timeIndex].u * frequency / SpeedOfLight(); v = metaData->UVW()[timeIndex].v * frequency / SpeedOfLight(); } void UVImager::GetUVPosition(num_t& u, num_t& v, const SingleFrequencySingleBaselineData& data, const AntennaCache& cache) { const unsigned field = data.field; const num_t pointingLattitude = _fields[field].delayDirectionRA; const num_t pointingLongitude = _fields[field].delayDirectionDec; // calcTimer.Start(); const num_t earthLattitudeAngle = Date::JDToHourOfDay(Date::AipsMJDToJD(data.time)) * M_PIn / 12.0L; // long double pointingLongitude = _fields[field].delayDirectionDec; //not // used // Rotate baseline plane towards source, first rotate around z axis, then // around x axis const num_t raRotation = earthLattitudeAngle - pointingLattitude + M_PIn * 0.5L; num_t tmpCos = cosn(raRotation); num_t tmpSin = sinn(raRotation); const num_t dxProjected = tmpCos * cache.dx - tmpSin * cache.dy; const num_t tmpdy = tmpSin * cache.dx + tmpCos * cache.dy; tmpCos = cosn(-pointingLongitude); tmpSin = sinn(-pointingLongitude); const num_t dyProjected = tmpCos * tmpdy - tmpSin * cache.dz; // long double dzProjected = tmpSin*tmpdy + tmpCos*dzAnt; // we don't need it // Now, the newly projected positive z axis of the baseline points to the // field num_t baselineLength = sqrtn(dxProjected * dxProjected + dyProjected * dyProjected); num_t baselineAngle; if (baselineLength == 0.0L) { baselineAngle = 0.0L; } else { baselineLength /= cache.wavelength; if (dxProjected > 0.0L) baselineAngle = atann(dyProjected / dxProjected); else baselineAngle = M_PIn - atann(dyProjected / -dxProjected); } u = cosn(baselineAngle) * baselineLength; v = -sinn(baselineAngle) * baselineLength; } num_t UVImager::GetFringeStopFrequency(size_t timeIndex, const Baseline& /*baseline*/, num_t /*delayDirectionRA*/, num_t delayDirectionDec, num_t /*frequency*/, TimeFrequencyMetaDataCPtr metaData) { // earthspeed = rad / sec const num_t earthSpeed = 2.0L * M_PIn / (24.0L * 60.0L * 60.0L); // num_t earthLattitudeAngle = // Date::JDToHourOfDay(Date::AipsMJDToJD(metaData->ObservationTimes()[timeIndex]))*M_PIn/12.0L; // num_t raSin = sinn(-delayDirectionRA - earthLattitudeAngle); // num_t raCos = cosn(-delayDirectionRA - earthLattitudeAngle); // num_t dx = baseline.antenna2.x - baseline.antenna1.x; // num_t dy = baseline.antenna2.y - baseline.antenna1.y; // num_t wavelength = 299792458.0L / frequency; return -earthSpeed * metaData->UVW()[timeIndex].u * cosn(delayDirectionDec); } num_t UVImager::GetFringeCount(size_t timeIndexStart, size_t timeIndexEnd, unsigned channelIndex, const TimeFrequencyMetaDataCPtr metaData) { // For now, I've made this return the negative fringe count, because it does // not match with the fringe stop frequency returned above otherwise; probably // because of a mismatch in the signs of u,v,w somewhere... return -(metaData->UVW()[timeIndexEnd].w - metaData->UVW()[timeIndexStart].w) * metaData->Band().channels[channelIndex].frequencyHz / 299792458.0L; } void UVImager::InverseImage(MSMetaData& prototype, unsigned band, const Image2D& /*uvReal*/, const Image2D& /*uvImaginary*/, unsigned antenna1Index, unsigned antenna2Index) { _timeFreq = Image2D::MakeZeroImage(prototype.TimestepCount(), prototype.FrequencyCount(band)); AntennaInfo antenna1, antenna2; antenna1 = prototype.GetAntennaInfo(antenna1Index); antenna2 = prototype.GetAntennaInfo(antenna2Index); } aoflagger-v3.4.0/imaging/model.cpp0000644000175000017500000002631014507760372015555 0ustar olesoles#include "model.h" #include "../structures/image2d.h" #include "../structures/timefrequencydata.h" #include "observatorium.h" #include "../util/rng.h" #include "../util/logger.h" #include Model::Model() : _noiseSigma(1.0), _sourceSigma(0.0), _integrationTime(15.0) {} template void Model::SimulateObservation(struct OutputReceiver& receiver, Observatorium& observatorium, num_t delayDirectionDEC, num_t delayDirectionRA) { const size_t channelCount = observatorium.BandInfo().channels.size(); const double frequency = observatorium.BandInfo().channels[0].frequencyHz; for (size_t f = 0; f < channelCount; ++f) { const double channelFrequency = frequency + observatorium.ChannelWidthHz() * f; receiver.SetY(f); for (size_t i = 0; i < observatorium.AntennaCount(); ++i) { for (size_t j = i + 1; j < observatorium.AntennaCount(); ++j) { const AntennaInfo &antenna1 = observatorium.GetAntenna(i), &antenna2 = observatorium.GetAntenna(j); double dx = antenna1.position.x - antenna2.position.x, dy = antenna1.position.y - antenna2.position.y, dz = antenna1.position.z - antenna2.position.z; SimulateCorrelation(receiver, delayDirectionDEC, delayDirectionRA, dx, dy, dz, channelFrequency, observatorium.ChannelWidthHz(), 12 * 60 * 60, _integrationTime); } } } } template void Model::SimulateObservation( struct OutputReceiver& receiver, Observatorium& observatorium, num_t delayDirectionDEC, num_t delayDirectionRA); template void Model::SimulateObservation( struct OutputReceiver& receiver, Observatorium& observatorium, num_t delayDirectionDEC, num_t delayDirectionRA); std::pair Model::SimulateObservation(size_t nTimes, class Observatorium& observatorium, num_t delayDirectionDEC, num_t delayDirectionRA, size_t a1, size_t a2) { const size_t channelCount = observatorium.BandInfo().channels.size(); const double frequency = observatorium.BandInfo().channels[0].frequencyHz; OutputReceiver tfOutputter; tfOutputter._real = Image2D::CreateZeroImagePtr(nTimes, channelCount); tfOutputter._imaginary = Image2D::CreateZeroImagePtr(nTimes, channelCount); const TimeFrequencyMetaDataPtr metaData(new TimeFrequencyMetaData()); metaData->SetAntenna1(observatorium.GetAntenna(a1)); metaData->SetAntenna2(observatorium.GetAntenna(a2)); metaData->SetBand(observatorium.BandInfo()); double dx = metaData->Antenna1().position.x - metaData->Antenna2().position.x, dy = metaData->Antenna1().position.y - metaData->Antenna2().position.y, dz = metaData->Antenna1().position.z - metaData->Antenna2().position.z; for (size_t f = 0; f < channelCount; ++f) { const double channelFrequency = frequency + observatorium.ChannelWidthHz() * f; tfOutputter.SetY(f); SimulateCorrelation(tfOutputter, delayDirectionDEC, delayDirectionRA, dx, dy, dz, channelFrequency, observatorium.ChannelWidthHz(), nTimes, _integrationTime); } std::vector times; std::vector uvws; const num_t wavelength = 1.0L / frequency; for (size_t i = 0; i != nTimes; ++i) { const double t = _integrationTime * i; times.push_back(t); const num_t earthLattitudeApprox = t * M_PIn / (12.0 * 60.0 * 60.0); UVW uvw; GetUVPosition(uvw.u, uvw.v, earthLattitudeApprox, delayDirectionDEC, delayDirectionRA, dx, dy, dz, wavelength); uvw.u = uvw.u * (299792458.0L / frequency); uvw.v = uvw.v * (299792458.0L / frequency); uvw.w = GetWPosition(delayDirectionDEC, delayDirectionRA, frequency, earthLattitudeApprox, dx, dy) * (299792458.0L / frequency); uvws.push_back(uvw); } metaData->SetUVW(uvws); metaData->SetObservationTimes(times); FieldInfo field; field.fieldId = 0; field.delayDirectionDec = delayDirectionDEC; // field.delayDirectionDecNegCos = -cos(delayDirectionDEC); // field.delayDirectionDecNegSin = -sin(delayDirectionDEC); field.delayDirectionRA = delayDirectionRA; metaData->SetField(field); const TimeFrequencyData tfData(aocommon::Polarization::StokesI, tfOutputter._real, tfOutputter._imaginary); return std::pair(tfData, metaData); } template void Model::SimulateCorrelation(struct OutputReceiver& receiver, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t dz, num_t frequency, num_t channelWidth, size_t nTimes, double integrationTime) { const double sampleGain = integrationTime / (12.0 * 60.0 * 60.0) * channelWidth; const num_t wavelength = 1.0L / frequency; size_t index = 0; for (size_t ti = 0; ti != nTimes; ++ti) { const double t = ti * integrationTime; const double timeInDays = t / (12.0 * 60.0 * 60.0); const num_t earthLattitudeApprox = timeInDays * M_PIn; num_t u, v, r1, i1, r2, i2; GetUVPosition(u, v, earthLattitudeApprox, delayDirectionDEC, delayDirectionRA, dx, dy, dz, wavelength); SimulateAntenna(timeInDays, delayDirectionDEC, delayDirectionRA, 0, 0, frequency, earthLattitudeApprox, r1, i1); SimulateAntenna(timeInDays, delayDirectionDEC, delayDirectionRA, dx, dy, frequency, earthLattitudeApprox, r2, i2); num_t r = r1 * r2 - (i1 * -i2), i = r1 * -i2 + r2 * i1; receiver.SetUVValue(index, u, v, r * sampleGain, i * sampleGain, 1.0); ++index; } } template void Model::SimulateCorrelation( struct OutputReceiver& receiver, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t dz, num_t frequency, num_t channelWidth, size_t nTimes, double integrationTime); void Model::SimulateAntenna(double time, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t frequency, num_t earthLattitude, num_t& r, num_t& i) { r = 0.0; i = 0.0; const num_t delayW = GetWPosition(delayDirectionDEC, delayDirectionRA, frequency, earthLattitude, dx, dy); for (std::vector::const_iterator iter = _sources.begin(); iter != _sources.end(); ++iter) { const Source& source = **iter; const num_t w = GetWPosition(source.Dec(time), source.Ra(time), frequency, earthLattitude, dx, dy); const num_t fieldStrength = source.SqrtFluxIntensity(time) + RNG::Gaussian() * _sourceSigma; num_t noiser, noisei; RNG::ComplexGaussianAmplitude(noiser, noisei); r += fieldStrength * cosn((w - delayW) * M_PIn * 2.0) + noiser * _noiseSigma; i += fieldStrength * sinn((w - delayW) * M_PIn * 2.0) + noisei * _noiseSigma; } } void Model::SimulateUncoherentAntenna(double time, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t frequency, num_t earthLattitude, num_t& r, num_t& i, size_t index) { const num_t delayW = GetWPosition(delayDirectionDEC, delayDirectionRA, frequency, earthLattitude, dx, dy); // if(index%(_sources.size()+1) == _sources.size()) //{ num_t noiser, noisei; RNG::ComplexGaussianAmplitude(noiser, noisei); noiser *= _noiseSigma; noisei *= _noiseSigma; //} // else { const Source& source = *_sources[index % _sources.size()]; const num_t w = GetWPosition(source.Dec(time), source.Ra(time), frequency, earthLattitude, dx, dy); const num_t fieldStrength = source.SqrtFluxIntensity(time) + RNG::Gaussian() * _sourceSigma; r = fieldStrength * cosn((w - delayW) * M_PIn * 2.0) + noiser; i = fieldStrength * sinn((w - delayW) * M_PIn * 2.0) + noisei; //} } void Model::GetUVPosition(num_t& u, num_t& v, num_t earthLattitudeAngle, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t dz, num_t wavelength) { // Rotate baseline plane towards phase center, first rotate around z axis, // then around x axis const long double raRotation = -earthLattitudeAngle + delayDirectionRA + M_PIn * 0.5L; long double tmpCos = cosn(raRotation); long double tmpSin = sinn(raRotation); const long double dxProjected = tmpCos * dx - tmpSin * dy; const long double tmpdy = tmpSin * dx + tmpCos * dy; tmpCos = cosn(-delayDirectionDEC); tmpSin = sinn(-delayDirectionDEC); const long double dyProjected = tmpCos * tmpdy - tmpSin * dz; // Now, the newly projected positive z axis of the baseline points to the // phase center long double baselineLength = sqrtn(dxProjected * dxProjected + dyProjected * dyProjected); long double baselineAngle; if (baselineLength == 0.0) { baselineAngle = 0.0; } else { baselineLength /= 299792458.0L * wavelength; if (dxProjected > 0.0L) baselineAngle = atann(dyProjected / dxProjected); else baselineAngle = M_PIn - atann(dyProjected / -dxProjected); } u = cosn(baselineAngle) * baselineLength; v = -sinn(baselineAngle) * baselineLength; } void Model::loadUrsaMajor(double ra, double dec, double factor) { double s = 0.00005 * factor, // scale rs = 6.0 + 2.0 * factor; // stretch in dec const double fluxoffset = 0.0; AddSource(dec + s * rs * 40, ra + s * 72, 8.0 / 8.0 + fluxoffset); // Dubhe AddSource(dec + s * rs * -16, ra + s * 81, 4.0 / 8.0 + fluxoffset); // Beta AddSource(dec + s * rs * -45, ra + s * 2, 3.0 / 8.0 + fluxoffset); // Gamma AddSource(dec + s * rs * -6, ra + s * -27, 2.0 / 8.0 + fluxoffset); // Delta AddSource(dec + s * rs * -4, ra + s * -85, 6.0 / 8.0 + fluxoffset); // Alioth AddSource(dec + s * rs * 2, ra + s * -131, 5.0 / 8.0 + fluxoffset); // Zeta AddSource(dec + s * rs * -36, ra + s * -192, 7.0 / 8.0 + fluxoffset); // Alkaid // AddSource(cd, cr - M_PI, 4.0); } void Model::loadUrsaMajorDistortingSource(double ra, double dec, double factor, bool slightlyMiss) { if (slightlyMiss) { dec += 0.005; ra += 0.002; } AddSource(dec - 0.12800 * factor, ra + 0.015 + 0.015 * factor, 4.0); } void Model::loadUrsaMajorDistortingVariableSource(double ra, double dec, double factor, bool weak, bool slightlyMiss) { double flux = 4.0; dec = dec - 0.12800 * factor; ra = ra + 0.015 + 0.015 * factor; if (slightlyMiss) { dec += 0.005; ra += 0.002; } if (weak) { flux /= 100.0; } AddVariableSource(dec, ra, flux); } aoflagger-v3.4.0/imaging/observatorium.h0000644000175000017500000001202314507760372017017 0ustar olesoles#ifndef OBSERVATORIUM_H #define OBSERVATORIUM_H #include #include "../structures/antennainfo.h" class Observatorium { public: Observatorium() : _channelWidthHz(0.0) {} void AddAntenna(AntennaInfo& antenna) { _antennae.push_back(antenna); } size_t AntennaCount() const { return _antennae.size(); } const AntennaInfo& GetAntenna(size_t index) const { return _antennae[index]; } void SetChannelWidthHz(double channelWidthHz) { _channelWidthHz = channelWidthHz; } double ChannelWidthHz() const { return _channelWidthHz; } const class BandInfo& BandInfo() const { return _bandInfo; } protected: class BandInfo& GetBandInfo() { return _bandInfo; } private: std::vector _antennae; double _channelWidthHz; class BandInfo _bandInfo; }; struct WSRTObservatorium : public Observatorium { explicit WSRTObservatorium(size_t channelCount = 16 * 4, double bandwidthHz = 2500000.0 * 16.0) { AntennaInfo antennas[14]; for (unsigned i = 0; i < 14; ++i) { WSRTCommon(antennas[i]); WSRTn(i, antennas[i]); AddAntenna(antennas[i]); } SetChannelWidthHz(bandwidthHz / channelCount); initBand(channelCount); } explicit WSRTObservatorium(size_t antenna1, size_t antenna2, size_t channelCount = 16 * 4) { AntennaInfo antennas[2]; WSRTCommon(antennas[0]); WSRTCommon(antennas[1]); WSRTn(antenna1, antennas[0]); WSRTn(antenna2, antennas[1]); AddAntenna(antennas[0]); AddAntenna(antennas[1]); SetChannelWidthHz(10000.0 * 256.0 * 16.0 / channelCount); initBand(channelCount); } private: void WSRTCommon(AntennaInfo& antenna) { antenna.diameter = 25; antenna.mount = "equatorial"; antenna.station = "WSRT"; } void WSRTn(size_t antennaIndex, AntennaInfo& antenna) { switch (antennaIndex) { case 0: antenna.id = 0; antenna.name = "RT0"; antenna.position.x = 3.82876e+06; antenna.position.y = 442449; antenna.position.z = 5.06492e+06; break; case 1: antenna.id = 1; antenna.name = "RT1"; antenna.position.x = 3.82875e+06; antenna.position.y = 442592; antenna.position.z = 5.06492e+06; break; case 2: antenna.id = 2; antenna.name = "RT2"; antenna.position.x = 3.82873e+06; antenna.position.y = 442735; antenna.position.z = 5.06492e+06; break; case 3: antenna.id = 3; antenna.name = "RT3"; antenna.position.x = 3.82871e+06; antenna.position.y = 442878; antenna.position.z = 5.06492e+06; break; case 4: antenna.id = 4; antenna.name = "RT4"; antenna.position.x = 3.8287e+06; antenna.position.y = 443021; antenna.position.z = 5.06492e+06; break; case 5: antenna.id = 5; antenna.name = "RT5"; antenna.position.x = 3.82868e+06; antenna.position.y = 443164; antenna.position.z = 5.06492e+06; break; case 6: antenna.id = 6; antenna.name = "RT6"; antenna.position.x = 3.82866e+06; antenna.position.y = 443307; antenna.position.z = 5.06492e+06; break; case 7: antenna.id = 7; antenna.name = "RT7"; antenna.position.x = 3.82865e+06; antenna.position.y = 443450; antenna.position.z = 5.06492e+06; break; case 8: antenna.id = 8; antenna.name = "RT8"; antenna.position.x = 3.82863e+06; antenna.position.y = 443593; antenna.position.z = 5.06492e+06; break; case 9: antenna.id = 9; antenna.name = "RT9"; antenna.position.x = 3.82861e+06; antenna.position.y = 443736; antenna.position.z = 5.06492e+06; break; case 10: antenna.id = 10; antenna.name = "RTA"; antenna.position.x = 3.8286e+06; antenna.position.y = 443832; antenna.position.z = 5.06492e+06; break; case 11: antenna.id = 11; antenna.name = "RTB"; antenna.position.x = 3.82859e+06; antenna.position.y = 443903; antenna.position.z = 5.06492e+06; break; case 12: antenna.id = 12; antenna.name = "RTC"; antenna.position.x = 3.82845e+06; antenna.position.y = 445119; antenna.position.z = 5.06492e+06; break; case 13: antenna.id = 13; antenna.name = "RTD"; antenna.position.x = 3.82845e+06; antenna.position.y = 445191; antenna.position.z = 5.06492e+06; break; } } void initBand(size_t channelCount) { GetBandInfo().windowIndex = 0; for (size_t i = 0; i < channelCount; ++i) { ChannelInfo channel; channel.frequencyIndex = i; channel.channelWidthHz = ChannelWidthHz(); channel.frequencyHz = 147000000.0 - 20000000.0 + ChannelWidthHz() * i; GetBandInfo().channels.push_back(channel); } } }; #endif aoflagger-v3.4.0/imaging/model.h0000644000175000017500000001302114507760372015215 0ustar olesoles#ifndef MODEL_H #define MODEL_H #include #include #include #include "../structures/image2d.h" #include "../structures/types.h" #include "uvimager.h" template struct OutputReceiver { void SetY(size_t) {} }; template <> struct OutputReceiver { UVImager* _imager; void SetUVValue(size_t, double u, double v, double r, double i, double w) { _imager->SetUVValue(u, v, r, i, w); _imager->SetUVValue(-u, -v, r, -i, w); } void SetY(size_t) {} }; template <> struct OutputReceiver { Image2DPtr _real, _imaginary; size_t _y; void SetUVValue(size_t x, double, double, double r, double i, double) { _real->SetValue(x, _y, r); _imaginary->SetValue(x, _y, i); } void SetY(size_t y) { _y = y; } }; class Model { struct Source { virtual ~Source() {} virtual numl_t Dec(num_t t) const = 0; virtual numl_t Ra(num_t t) const = 0; virtual numl_t FluxIntensity(num_t t) const = 0; virtual numl_t SqrtFluxIntensity(num_t t) const { return sqrtnl(FluxIntensity(t)); } }; struct StablePointSource final : public Source { long double dec, ra, fluxIntensity, sqrtFluxIntensity; numl_t Dec(num_t) const override { return dec; } numl_t Ra(num_t) const override { return ra; } numl_t FluxIntensity(num_t) const override { return fluxIntensity; } numl_t SqrtFluxIntensity(num_t) const override { return sqrtFluxIntensity; } }; struct VariablePointSource final : public Source { long double dec, ra, fluxIntensity; double peakTime, oneOverSigmaSq; numl_t Dec(num_t) const override { return dec; } numl_t Ra(num_t) const override { return ra; } numl_t FluxIntensity(num_t t) const override { numl_t mu = fmodnl(fabsnl(t - peakTime), 1.0); if (mu > 0.5) mu = 1.0 - mu; return fluxIntensity * (1.0 + expnl(mu * mu * oneOverSigmaSq)) * (1.0 + fmod(t * 1007.0, 13.0) / 26.0); } }; public: Model(); void AddSource(long double dec, long double ra, long double fluxIntensity) { StablePointSource* source = new StablePointSource(); source->dec = dec; source->ra = ra; source->fluxIntensity = fluxIntensity; source->sqrtFluxIntensity = sqrt(fluxIntensity); _sources.push_back(source); } void AddVariableSource(long double dec, long double ra, long double fluxIntensity) { VariablePointSource* source = new VariablePointSource(); source->dec = dec; source->ra = ra; source->fluxIntensity = fluxIntensity; source->peakTime = 0.2; source->oneOverSigmaSq = 1.0 / (0.3 * 0.3); _sources.push_back(source); } void SimulateAntenna(double time, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t frequency, num_t earthLattitude, num_t& r, num_t& i); void SimulateUncoherentAntenna(double time, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t frequency, num_t earthLattitude, num_t& r, num_t& i, size_t index); template void SimulateCorrelation(struct OutputReceiver& receiver, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t dz, num_t frequency, num_t channelWidth, size_t nTimes, double integrationTime); void SimulateObservation(class UVImager& imager, class Observatorium& observatorium, num_t delayDirectionDEC, num_t delayDirectionRA) { srand(1); OutputReceiver imagerOutputter; imagerOutputter._imager = &imager; SimulateObservation(imagerOutputter, observatorium, delayDirectionDEC, delayDirectionRA); } std::pair SimulateObservation( size_t nTimes, class Observatorium& observatorium, num_t delayDirectionDEC, num_t delayDirectionRA, size_t a1, size_t a2); template void SimulateObservation(struct OutputReceiver& receiver, class Observatorium& observatorium, num_t delayDirectionDEC, num_t delayDirectionRA); static void GetUVPosition(num_t& u, num_t& v, num_t earthLattitudeAngle, num_t delayDirectionDEC, num_t delayDirectionRA, num_t dx, num_t dy, num_t dz, num_t waveLength); static num_t GetWPosition(num_t delayDirectionDec, num_t delayDirectionRA, num_t frequency, num_t earthLattitudeAngle, num_t dx, num_t dy) { return UVImager::GetWPosition(delayDirectionDec, delayDirectionRA, frequency, earthLattitudeAngle, dx, dy); } void loadUrsaMajor(double ra, double dec, double factor); void loadUrsaMajorDistortingSource(double ra, double dec, double factor, bool slightlyMiss = false); void loadUrsaMajorDistortingVariableSource(double ra, double dec, double factor, bool weak = false, bool slightlyMiss = false); double NoiseSigma() const { return _noiseSigma; } void SetNoiseSigma(double noiseSigma) { _noiseSigma = noiseSigma; } private: std::vector _sources; double _noiseSigma, _sourceSigma; double _integrationTime; }; #endif aoflagger-v3.4.0/aoluarunner/0000755000175000017500000000000014516225226014661 5ustar olesolesaoflagger-v3.4.0/aoluarunner/writethread.cpp0000644000175000017500000000617314507760372017724 0ustar olesoles#include "writethread.h" #include "../imagesets/multibandmsimageset.h" #include "../util/logger.h" WriteThread::WriteThread(imagesets::ImageSet& imageSet, size_t calcThreadCount, std::mutex* ioMutex) : _ioMutex(ioMutex), _isWriteFinishing(false), _maxWriteBufferItems(calcThreadCount * 5), _minWriteBufferItemsForWriting(calcThreadCount * 4) { FlushThread flushFunction; flushFunction._parent = this; if (dynamic_cast(&imageSet)) { // TODO Would this method also be safe for other writers? _flusher.reset(new std::thread(flushFunction, &imageSet)); } else { std::unique_lock iolock(*_ioMutex); std::unique_ptr localImageSet = imageSet.Clone(); iolock.unlock(); _flusher.reset(new std::thread(flushFunction, std::move(localImageSet))); } } WriteThread::~WriteThread() { std::unique_lock lock(_writeMutex); _isWriteFinishing = true; _writeBufferChange.notify_all(); lock.unlock(); Logger::Debug << "Finishing the flusher thread...\n"; _flusher->join(); } void WriteThread::SaveFlags(const TimeFrequencyData& data, imagesets::ImageSetIndex& imageSetIndex) { std::vector masks; if (data.MaskCount() <= 1) masks.emplace_back(data.GetSingleMask()); else for (size_t i = 0; i < data.MaskCount(); ++i) { masks.emplace_back(data.GetMask(i)); } const BufferItem newItem(masks, imageSetIndex); pushInWriteBuffer(newItem); } void WriteThread::pushInWriteBuffer(const BufferItem& newItem) { std::unique_lock lock(_writeMutex); while (_writeBuffer.size() >= _maxWriteBufferItems) _writeBufferChange.wait(lock); _writeBuffer.emplace(newItem); _writeBufferChange.notify_all(); } void WriteThread::FlushThread::operator()( std::unique_ptr imageSet) { operator()(imageSet.get()); } void WriteThread::FlushThread::operator()(imagesets::ImageSet* imageSet) { std::unique_lock lock(_parent->_writeMutex); do { while (_parent->_writeBuffer.size() < _parent->_minWriteBufferItemsForWriting && !_parent->_isWriteFinishing) _parent->_writeBufferChange.wait(lock); std::stack bufferCopy; while (!_parent->_writeBuffer.empty()) { const BufferItem item = _parent->_writeBuffer.top(); _parent->_writeBuffer.pop(); bufferCopy.push(item); } _parent->_writeBufferChange.notify_all(); if (bufferCopy.size() >= _parent->_minWriteBufferItemsForWriting) Logger::Debug << "Flag buffer has reached minimal writing size, flushing " "flags...\n"; else Logger::Debug << "Flushing flags...\n"; lock.unlock(); std::unique_lock ioLock(*_parent->_ioMutex); while (!bufferCopy.empty()) { BufferItem item = bufferCopy.top(); bufferCopy.pop(); imageSet->AddWriteFlagsTask(item._index, item._masks); } imageSet->PerformWriteFlagsTask(); ioLock.unlock(); lock.lock(); } while (!_parent->_isWriteFinishing || !_parent->_writeBuffer.empty()); } aoflagger-v3.4.0/aoluarunner/writethread.h0000644000175000017500000000230514507760372017362 0ustar olesoles#ifndef AOLUA_WRITE_THREAD_H #define AOLUA_WRITE_THREAD_H #include "../imagesets/imageset.h" #include #include #include #include #include class WriteThread { public: WriteThread(imagesets::ImageSet& imageSet, size_t calcThreadCount, std::mutex* ioMutex); ~WriteThread(); void SaveFlags(const TimeFrequencyData& data, imagesets::ImageSetIndex& imageSetIndex); private: struct FlushThread { WriteThread* _parent; void operator()(std::unique_ptr imageSet); void operator()(imagesets::ImageSet* imageSet); }; struct BufferItem { BufferItem(const std::vector& masks, const imagesets::ImageSetIndex& index) : _masks(masks), _index(index) {} std::vector _masks; imagesets::ImageSetIndex _index; }; void pushInWriteBuffer(const BufferItem& newItem); std::mutex _writeMutex, *_ioMutex; std::condition_variable _writeBufferChange; std::unique_ptr _flusher; bool _isWriteFinishing; size_t _maxWriteBufferItems; size_t _minWriteBufferItemsForWriting; std::stack _writeBuffer; }; #endif aoflagger-v3.4.0/aoluarunner/baselineiterator.cpp0000644000175000017500000002577214507760372020744 0ustar olesoles#include "baselineiterator.h" #include "../lua/luathreadgroup.h" #include "../lua/scriptdata.h" #include "../structures/antennainfo.h" #include "../util/logger.h" #include "../util/progress/dummyprogresslistener.h" #include "../util/stopwatch.h" #include "../imagesets/bhfitsimageset.h" #include "../imagesets/fitsimageset.h" #include "../imagesets/imageset.h" #include "../imagesets/msimageset.h" #include "../imagesets/filterbankset.h" #include "../imagesets/qualitystatimageset.h" #include "../imagesets/rfibaselineset.h" #include "writethread.h" #include #include #include BaselineIterator::BaselineIterator(std::mutex* ioMutex, const Options& options) : _options(options), _sequenceCount(0), _nextIndex(0), _threadCount(4), _loopIndex(), _ioMutex(ioMutex), _finishedBaselines(false), _exceptionOccured(false), _baselineProgress(0) {} BaselineIterator::~BaselineIterator() {} void BaselineIterator::Run(imagesets::ImageSet& imageSet, LuaThreadGroup& lua, ScriptData& scriptData) { _lua = &lua; _imageSet = &imageSet; _threadCount = _options.CalculateThreadCount(); _writeThread.reset(new WriteThread(imageSet, _threadCount, _ioMutex)); _globalScriptData = &scriptData; imagesets::MSImageSet* msImageSet = dynamic_cast(&imageSet); if (msImageSet) { // Check memory usage const imagesets::ImageSetIndex tempIndex = msImageSet->StartIndex(); const size_t timeStepCount = msImageSet->ObservationTimesVector(tempIndex).size(); const size_t channelCount = msImageSet->GetBandInfo(0).channels.size(); const double estMemorySizePerThread = 8.0 /*bp complex*/ * 4.0 /*polarizations*/ * double(timeStepCount) * double(channelCount) * 3.0 /* approx copies of the data that will be made in memory*/; Logger::Debug << "Estimate of memory each thread will use: " << memToStr(estMemorySizePerThread) << ".\n"; size_t compThreadCount = _threadCount; if (compThreadCount > 0) --compThreadCount; const int64_t memSize = aocommon::system::TotalMemory(); Logger::Debug << "Detected " << memToStr(memSize) << " of system memory.\n"; if (estMemorySizePerThread * double(compThreadCount) > memSize) { size_t maxThreads = size_t(memSize / estMemorySizePerThread); if (maxThreads < 1) maxThreads = 1; Logger::Warn << "This measurement set is TOO LARGE to be processed with " << _threadCount << " threads!\n" << _threadCount << " threads would require " << memToStr(estMemorySizePerThread * compThreadCount) << " of memory approximately.\n" "Number of threads that will actually be used: " << maxThreads << "\n" "This might hurt performance a lot!\n\n"; _threadCount = maxThreads; } } if (dynamic_cast(&imageSet) != nullptr && _threadCount != 1) { Logger::Info << "This is a Filterbank set -- disabling multi-threading\n"; _threadCount = 1; } if (!_options.antennaeToSkip.empty()) { Logger::Debug << "The following antennas will be skipped: "; for (const size_t a : _options.antennaeToSkip) Logger::Debug << a << ' '; Logger::Debug << '\n'; } if (!_options.antennaeToInclude.empty()) { Logger::Debug << "Only the following antennas will be included: "; for (const size_t a : _options.antennaeToInclude) Logger::Debug << a << ' '; Logger::Debug << '\n'; } _finishedBaselines = false; _sequenceCount = 0; _baselineProgress = 0; _nextIndex = 0; // Count the sequences that are to be processed imagesets::ImageSetIndex iteratorIndex = imageSet.StartIndex(); while (!iteratorIndex.HasWrapped()) { if (IsSequenceSelected(iteratorIndex)) ++_sequenceCount; iteratorIndex.Next(); } Logger::Debug << "Will process " << _sequenceCount << " sequences.\n"; // Initialize thread data and threads _loopIndex = imageSet.StartIndex(); std::vector threadGroup; const ReaderThread reader(*this); threadGroup.emplace_back(reader); for (unsigned i = 0; i < _threadCount; ++i) { const ProcessingThread function(*this, i); threadGroup.emplace_back(function); } for (std::thread& t : threadGroup) t.join(); _writeThread.reset(); if (_exceptionOccured) throw std::runtime_error( "An exception occured in the parallel (multi-threaded) processing of " "the baselines: the RFI strategy will not continue."); } bool BaselineIterator::IsSequenceSelected(imagesets::ImageSetIndex& index) { imagesets::IndexableSet* idImageSet = dynamic_cast(_imageSet); size_t a1id, a2id; if (idImageSet != nullptr) { a1id = idImageSet->GetAntenna1(index); a2id = idImageSet->GetAntenna2(index); if (!_options.bands.empty() && _options.bands.count(idImageSet->GetBand(index)) == 0) return false; if (!_options.fields.empty() && _options.fields.count(idImageSet->GetField(index)) == 0) return false; } else { a1id = 0; a2id = 0; } if (_options.antennaeToSkip.count(a1id) != 0 || _options.antennaeToSkip.count(a2id) != 0) return false; if (!_options.antennaeToInclude.empty() && (_options.antennaeToInclude.count(a1id) == 0 && _options.antennaeToInclude.count(a2id) == 0)) return false; // For SD/BHFits/QS/rfibl files, we want to select everything -- it's // confusing if the default option "only flag cross correlations" would also // hold for single-"baseline" files. if (!_imageSet->HasCrossCorrelations()) return true; switch (_options.baselineSelection.value_or( BaselineSelection::CrossCorrelations)) { case BaselineSelection::All: return true; case BaselineSelection::CrossCorrelations: { return a1id != a2id; } case BaselineSelection::AutoCorrelations: return a1id == a2id; case BaselineSelection::Current: case BaselineSelection::EqualToCurrent: case BaselineSelection::AutoCorrelationsOfCurrentAntennae: throw std::runtime_error("Not implemented"); } return false; } imagesets::ImageSetIndex BaselineIterator::GetNextIndex() { const std::lock_guard lock(_mutex); while (!_loopIndex.HasWrapped()) { if (IsSequenceSelected(_loopIndex)) { imagesets::ImageSetIndex newIndex(_loopIndex); _loopIndex.Next(); return newIndex; } _loopIndex.Next(); } return imagesets::ImageSetIndex(); } void BaselineIterator::SetExceptionOccured() { const std::lock_guard lock(_mutex); _exceptionOccured = true; _dataProcessed.notify_all(); _dataAvailable.notify_all(); } void BaselineIterator::SetFinishedBaselines() { const std::lock_guard lock(_mutex); _finishedBaselines = true; } void BaselineIterator::ProcessingThread::operator()() { ScriptData scriptData; const std::string executeFunctionName = _parent._options.executeFunctionName.empty() ? "execute" : _parent._options.executeFunctionName; try { std::unique_ptr baseline = _parent.GetNextBaseline(); while (baseline != nullptr) { /* TODO std::ostringstream progressStr; if(baseline->MetaData()->HasAntenna1() && baseline->MetaData()->HasAntenna2()) progressStr << "Processing baseline " << baseline->MetaData()->Antenna1().name << " x " << baseline->MetaData()->Antenna2().name; else progressStr << "Processing next baseline"; _parent.SetProgress(_progress, _parent.BaselineProgress(), _parent._baselineCount, progressStr.str(), _threadIndex); */ TimeFrequencyData data(baseline->Data()); _parent._lua->Execute(_threadIndex, data, baseline->MetaData(), scriptData, executeFunctionName); _parent._writeThread->SaveFlags(data, baseline->Index()); baseline = _parent.GetNextBaseline(); _parent.IncBaselineProgress(); } } catch (std::exception& e) { Logger::Error << e.what() << '\n'; _parent.SetExceptionOccured(); } { const std::unique_lock ioLock(*_parent._ioMutex); _parent._globalScriptData->Combine(std::move(scriptData)); } Logger::Debug << "Processing thread finished.\n"; } void BaselineIterator::ReaderThread::operator()() { Stopwatch watch(true); bool finished = false; const size_t threadCount = _parent._threadCount; size_t minRecommendedBufferSize, maxRecommendedBufferSize; imagesets::MSImageSet* msImageSet = dynamic_cast(_parent._imageSet); if (msImageSet != nullptr) { minRecommendedBufferSize = msImageSet->Reader()->GetMinRecommendedBufferSize(threadCount); maxRecommendedBufferSize = msImageSet->Reader()->GetMaxRecommendedBufferSize(threadCount) - _parent.GetBaselinesInBufferCount(); } else { minRecommendedBufferSize = 1; maxRecommendedBufferSize = 2; } do { watch.Pause(); _parent.WaitForReadBufferAvailable(minRecommendedBufferSize); if (!_parent._exceptionOccured) { const size_t wantedCount = maxRecommendedBufferSize - _parent.GetBaselinesInBufferCount(); size_t requestedCount = 0; std::unique_lock lock(*_parent._ioMutex); watch.Start(); for (size_t i = 0; i < wantedCount; ++i) { const imagesets::ImageSetIndex index = _parent.GetNextIndex(); if (!index.Empty()) { _parent._imageSet->AddReadRequest(index); ++requestedCount; } else { finished = true; break; } } if (requestedCount > 0) { DummyProgressListener dummy; _parent._imageSet->PerformReadRequests(dummy); watch.Pause(); for (size_t i = 0; i < requestedCount; ++i) { std::unique_ptr baseline = _parent._imageSet->GetNextRequested(); const std::lock_guard bufferLock(_parent._mutex); _parent._baselineBuffer.emplace(std::move(baseline)); } } lock.unlock(); _parent._dataAvailable.notify_all(); } watch.Start(); } while (!finished && !_parent._exceptionOccured); _parent.SetFinishedBaselines(); _parent._dataAvailable.notify_all(); watch.Pause(); Logger::Debug << "Time spent on reading: " << watch.ToString() << '\n'; } std::string BaselineIterator::memToStr(double memSize) { std::ostringstream str; if (memSize > 1024.0 * 1024.0 * 1024.0 * 1024.0) str << round(memSize * 10.0 / (1024.0 * 1024.0 * 1024.0 * 1024.0)) / 10.0 << " TB"; else if (memSize > 1024.0 * 1024.0 * 1024.0) str << round(memSize * 10.0 / (1024.0 * 1024.0 * 1024.0)) / 10.0 << " GB"; else if (memSize > 1024.0 * 1024.0) str << round(memSize * 10.0 / (1024.0 * 1024.0)) / 10.0 << " MB"; else if (memSize > 1024.0) str << round(memSize * 10.0 / (1024.0)) / 10.0 << " KB"; else str << memSize << " B"; return str.str(); } aoflagger-v3.4.0/aoluarunner/runner.cpp0000644000175000017500000003751714507760372016721 0ustar olesoles#include "runner.h" #include "baselineiterator.h" #include "../lua/luathreadgroup.h" #include "../lua/scriptdata.h" #include "../lua/optionsfunction.h" #include "../lua/telescopefile.h" #include "../quality/statisticscollection.h" #include "../structures/msmetadata.h" #include "../imagesets/h5imageset.h" #include "../imagesets/joinedspwset.h" #include "../imagesets/msimageset.h" #include "../imagesets/msoptions.h" #include "../imagesets/multibandmsimageset.h" #include "../util/logger.h" #include #include #include #include using imagesets::H5ImageSet; using imagesets::ImageSet; using imagesets::JoinedSPWSet; using imagesets::MSImageSet; // The order of initialization: // 1. If Lua strategy given, load Lua strategy // 2. Determine options // 3. For each run and each file: // a) If no Lua strategy was given, open file and load corresponding Lua // strategy b) Run strategy void Runner::Run() { std::map optionsForAllRuns; { LuaThreadGroup lua(1); loadStrategy(lua, _cmdLineOptions, std::unique_ptr()); Logger::Debug << "Loading options from strategy...\n"; optionsForAllRuns = OptionsFunction::GetOptions(lua.GetThread(0).State(), _cmdLineOptions); } // Let threadgroup go out of scope if (optionsForAllRuns.empty()) optionsForAllRuns.emplace("main", _cmdLineOptions); for (const std::pair& singleRunOptions : optionsForAllRuns) { Logger::Debug << "Starting run '" + singleRunOptions.first + "'...\n"; run(singleRunOptions.second); } } void Runner::loadStrategy( LuaThreadGroup& lua, const Options& options, const std::unique_ptr& imageSet) { if (!options.preamble.empty()) { Logger::Debug << "Running preample...\n"; lua.RunPreamble(options.preamble); } std::string executeFilename; // Execute filename override strategy filename, so that the options() function // can be in a different file than the execute functions. if (!options.executeFilename.empty()) executeFilename = options.executeFilename; if (!options.strategyFilename.empty()) executeFilename = options.strategyFilename; if (executeFilename.empty() && imageSet) { const std::string telescopeName = imageSet->TelescopeName(); const TelescopeFile::TelescopeId telescopeId = TelescopeFile::TelescopeIdFromName(telescopeName); if (telescopeId == TelescopeFile::GENERIC_TELESCOPE) { Logger::Warn << "**\n" "** Measurement set specified the following telescope name: '" << telescopeName << "'\n" "** No good strategy is known for this telescope!\n" "** A generic strategy will be used which might not be optimal.\n" "**\n"; } else { Logger::Info << "\nUsing a stock strategy that was optimized for the " "following telescope:\n" << "- " << TelescopeFile::TelescopeDescription(telescopeId) << "\n" << "Stock strategies might not perform well. It is " "recommended to make your own strategy\n" << "using the rfigui and specify it with the '-strategy " "...' parameter.\n\n"; } executeFilename = TelescopeFile::FindStrategy(telescopeId); if (executeFilename.empty()) { throw std::runtime_error("Could not find a strategy for telescope " + TelescopeFile::TelescopeName(telescopeId) + ".\n" "This strategy should have been installed when " "running 'make install'. Make sure\n" "aoflagger is properly installed."); } } if (!executeFilename.empty()) { try { Logger::Debug << "Opening strategy file '" << executeFilename << "'\n"; lua.LoadFile(executeFilename.c_str()); Logger::Debug << "Strategy parsed succesfully.\n"; } catch (std::exception& e) { throw std::runtime_error("ERROR: Reading strategy file \"" + executeFilename + "\" failed!\n" "\nThe thrown exception was:\n" + e.what() + "\n"); } } } static std::vector FilterProcessedFiles( const std::vector& ms_names) { std::vector result; std::copy_if(ms_names.begin(), ms_names.end(), std::back_inserter(result), [](const std::string& ms_name) { MSMetaData ms(ms_name); if (!ms.HasAOFlaggerHistory()) { return true; } Logger::Info << "Skipping " << ms_name << ",\n" "because the set contains AOFlagger history and " "-skip-flagged was given.\n"; return false; }); return result; } void Runner::run(const Options& options) { Logger::SetVerbosity(options.logVerbosity.value_or(Logger::NormalVerbosity)); const size_t threadCount = options.CalculateThreadCount(); Logger::Debug << "Number of threads: " << options.threadCount << "\n"; const std::vector& ms_files = options.skipFlagged ? FilterProcessedFiles(_cmdLineOptions.filenames) : _cmdLineOptions.filenames; if (_cmdLineOptions.concatenateFrequency && ms_files.size() > 1) { // Only use the multi-band image set when there at least 2 files. // Else just use the simpler code. processFrequencyConcatenatedFiles(options, ms_files, threadCount); } else { for (const std::string& filename : ms_files) { processFile(options, filename, threadCount); } } } std::unique_ptr Runner::initializeImageSet(const Options& options, FileOptions& fileOptions) { MSOptions msOptions; msOptions.ioMode = options.readMode.value_or(BaselineIOMode::AutoReadMode); msOptions.baselineIntegration = options.baselineIntegration; std::unique_ptr imageSet(ImageSet::Create( std::vector{fileOptions.filename}, msOptions)); if (H5ImageSet* h5ImageSet = dynamic_cast(imageSet.get()); h5ImageSet) { h5ImageSet->SetInterval(fileOptions.intervalStart, fileOptions.intervalEnd); } else if (MSImageSet* msImageSet = dynamic_cast(imageSet.get()); msImageSet) { if (options.dataColumn.empty()) msImageSet->SetDataColumnName("DATA"); else msImageSet->SetDataColumnName(options.dataColumn); msImageSet->SetReadUVW(options.readUVW.value_or(false)); // during the first iteration, the nr of intervals hasn't been calculated // yet. Do that now. if (fileOptions.intervalIndex == 0) { if (options.chunkSize != 0) { msImageSet->SetInterval(fileOptions.intervalStart, fileOptions.intervalEnd); const size_t obsTimesSize = msImageSet->MetaData().GetObservationTimes().size(); fileOptions.nIntervals = (obsTimesSize + options.chunkSize - 1) / options.chunkSize; Logger::Info << "Maximum interval size of " << options.chunkSize << " timesteps for total of " << obsTimesSize << " timesteps results in " << fileOptions.nIntervals << " intervals.\n"; if (options.startTimestep) fileOptions.resolvedIntStart = *options.startTimestep; else fileOptions.resolvedIntStart = 0; if (options.endTimestep) fileOptions.resolvedIntEnd = *options.endTimestep; else fileOptions.resolvedIntEnd = obsTimesSize + fileOptions.resolvedIntStart; } else { fileOptions.nIntervals = 1; } } if (fileOptions.nIntervals == 1) { msImageSet->SetInterval(fileOptions.intervalStart, fileOptions.intervalEnd); } else { const size_t nTimes = fileOptions.resolvedIntEnd - fileOptions.resolvedIntStart; size_t start = fileOptions.resolvedIntStart + fileOptions.intervalIndex * nTimes / fileOptions.nIntervals; size_t end = fileOptions.resolvedIntStart + (fileOptions.intervalIndex + 1) * nTimes / fileOptions.nIntervals; Logger::Info << "Starting flagging of interval " << fileOptions.intervalIndex << ", timesteps " << start << " - " << end << '\n'; msImageSet->SetInterval(start, end); } if (options.combineSPWs) { msImageSet->Initialize(); imageSet.release(); std::unique_ptr msImageSetPtr(msImageSet); imageSet.reset(new JoinedSPWSet(std::move(msImageSetPtr))); } } imageSet->Initialize(); return imageSet; } void Runner::processFile(const Options& options, const std::string& filename, size_t threadCount) { Logger::Info << "Starting strategy on " << to_simple_string( boost::posix_time::microsec_clock::local_time()) << '\n'; ScriptData scriptData; FileOptions fileOptions; fileOptions.intervalStart = options.startTimestep; fileOptions.intervalEnd = options.endTimestep; fileOptions.filename = filename; bool isMS = false; while (fileOptions.intervalIndex < fileOptions.nIntervals) { std::unique_ptr imageSet = initializeImageSet(options, fileOptions); isMS = dynamic_cast(imageSet.get()) != nullptr; LuaThreadGroup lua(threadCount); loadStrategy(lua, options, imageSet); std::mutex ioMutex; BaselineIterator blIterator(&ioMutex, options); blIterator.Run(*imageSet, lua, scriptData); ++fileOptions.intervalIndex; } if (isMS) writeHistory(options, filename); finishStatistics(filename, scriptData, isMS); } struct ChunkInfo { size_t start_time_step; size_t end_time_step; size_t n_chunks; size_t chunk_size; }; static std::optional GetChunkInfo(const Options& options, const std::string& ms_name) { if (!options.chunkSize) return {}; assert(options.startTimestep.has_value() == options.endTimestep.has_value() && "These fields should either both be set or both be unset."); ChunkInfo result; if (options.startTimestep) { Logger::Info << "Interval " << *options.startTimestep << ", " << *options.endTimestep << "\n"; result.start_time_step = *options.startTimestep; result.end_time_step = *options.endTimestep; } else { MSMetaData MetaData{ms_name}; result.start_time_step = 0; result.end_time_step = MetaData.TimestepCount(); } const size_t time_step_count = result.end_time_step - result.start_time_step; result.n_chunks = (time_step_count + options.chunkSize - 1) / options.chunkSize; result.chunk_size = (time_step_count + result.n_chunks - 1) / result.n_chunks; Logger::Info << "Chunking settings result in " << time_step_count << " intervals with " << result.chunk_size << " timesteps.\n"; if (result.n_chunks == 1) return {}; return result; } void Runner::processFrequencyConcatenatedFiles( Options options, const std::vector& ms_names, size_t n_threads) { Logger::Info << "Starting strategy on " << to_simple_string( boost::posix_time::microsec_clock::local_time()) << '\n'; // Unlike processing threads increasing the number of IO threads isn't always // beneficial. At some point adding additional IO threads decreases the // performance. The optimal number of IO threads is system dependent. Testing // on different systems showed the optimum to be between 16 and 32 threads. // These tests were executed in February 2022. constexpr size_t kMaxIoThreads = 16; if (n_threads == 0) n_threads = aocommon::system::ProcessorCount(); const size_t n_io_threads = std::min({kMaxIoThreads, n_threads, ms_names.size()}); int remaining_chunks = 1; const std::optional chunk_info = GetChunkInfo(options, ms_names.front()); // When the -chunk-size argument is used and more than one chunk is used the // interval is adjusted. if (chunk_info) { remaining_chunks = chunk_info->n_chunks; options.startTimestep = chunk_info->start_time_step; options.endTimestep = *options.startTimestep + chunk_info->chunk_size; } // The number of chunks to process is greater than or equal to one. // After processing the next iteration is prepared. Therefore the termination // condition is in the middle of the loop. while (true) { if (chunk_info) Logger::Info << "Starting flagging of interval " << 1 + (chunk_info->n_chunks - remaining_chunks) << ", timesteps " << *options.startTimestep << " - " << *options.endTimestep << '\n'; ProcessFrequencyConcatenatedFilesChunk(options, ms_names, n_threads, n_io_threads, chunk_info); if (--remaining_chunks; remaining_chunks == 0) break; *options.startTimestep += chunk_info->chunk_size; options.endTimestep = remaining_chunks == 1 ? chunk_info->end_time_step : *options.startTimestep + chunk_info->chunk_size; } for (const std::string& ms_name : ms_names) { writeHistory(options, ms_name); } } void Runner::ProcessFrequencyConcatenatedFilesChunk( const Options& options, const std::vector& ms_names, size_t n_threads, size_t n_io_threads, const std::optional& chunk_info) { std::unique_ptr image_set = std::make_unique( ms_names, options.readMode.value_or(BaselineIOMode::AutoReadMode), options.startTimestep, options.endTimestep, n_io_threads); LuaThreadGroup thread_pool(n_threads); loadStrategy(thread_pool, options, image_set); std::mutex io_mutex; BaselineIterator baseline_iterator(&io_mutex, options); ScriptData script_data; baseline_iterator.Run(*image_set, thread_pool, script_data); static_cast(image_set.get()) ->WriteToMs(n_io_threads); if (script_data.GetStatistics()) Logger::Warn << "Statistics can't be written in multi-MS processing mode.\n" "Please remove collecting statistics from your Lua strategy.\n"; } void Runner::writeHistory(const Options& options, const std::string& filename) { MSMetaData ms(filename); Logger::Debug << "Adding strategy to history table of MS...\n"; try { std::string strategyFilename; if (!options.strategyFilename.empty()) { strategyFilename = options.strategyFilename; } // std::ifstream strategyFile(strategyFilename); // std::string content((std::istreambuf_iterator(strategyFile)), // (std::istreambuf_iterator()) ); ms.AddAOFlaggerHistory(strategyFilename, options.commandLine); } catch (std::exception& e) { Logger::Warn << "Failed to write history to MS: " << e.what() << '\n'; } } void Runner::finishStatistics(const std::string& filename, ScriptData& scriptData, bool isMS) { std::unique_ptr& statistics = scriptData.GetStatistics(); if (statistics) { if (isMS) { Logger::Debug << "Writing quality statistics to MS.\n"; QualityTablesFormatter qFormatter(filename); statistics->Save(qFormatter); } else { Logger::Warn << "Statistics can't be written when the input isn't a MS.\n" "Please remove collecting statistics from your Lua strategy.\n"; } } } aoflagger-v3.4.0/aoluarunner/options.h0000644000175000017500000001212414507760372016533 0ustar olesoles#ifndef OPTIONS_H #define OPTIONS_H #include "../structures/types.h" #include "../util/logger.h" #include #include #include #include enum class BaselineSelection { All, CrossCorrelations, AutoCorrelations, EqualToCurrent, AutoCorrelationsOfCurrentAntennae, Current }; struct BaselineIntegration { enum Mode { Count, Average, AverageAbs, Squared, Stddev }; enum Differencing { NoDifference, TimeDifference, FrequencyDifference }; std::optional enable, withAutos, withFlagged; std::optional mode; std::optional differencing; /** * All options that are set in @ref other will override the settings * in this. */ void Override(const BaselineIntegration& other) { if (other.enable) enable = other.enable; if (other.withAutos) withAutos = other.withAutos; if (other.withFlagged) withFlagged = other.withFlagged; if (other.mode) mode = other.mode; if (other.differencing) differencing = other.differencing; } bool operator==(const BaselineIntegration& other) const { return enable == other.enable && withAutos == other.withAutos && withFlagged == other.withFlagged && mode == other.mode && differencing == other.differencing; } }; struct Options { std::set antennaeToInclude, antennaeToSkip; std::set bands; std::optional baselineSelection; BaselineIntegration baselineIntegration; size_t chunkSize; std::optional combineSPWs; std::optional concatenateFrequency; std::string dataColumn; std::string executeFilename; std::string executeFunctionName; std::set fields; std::optional readMode; std::optional readUVW; std::string scriptVersion; std::optional skipFlagged; std::optional startTimestep, endTimestep; std::string strategyFilename; size_t threadCount; std::optional logVerbosity; std::vector preamble; std::string commandLine; std::vector filenames; Options() : chunkSize(0), threadCount(0) {} /** * All options that are set in @ref other will override the settings * in this. */ void Override(const Options& other) { if (!other.antennaeToInclude.empty()) antennaeToInclude = other.antennaeToInclude; if (!other.antennaeToSkip.empty()) antennaeToSkip = other.antennaeToSkip; if (!other.bands.empty()) bands = other.bands; baselineIntegration.Override(other.baselineIntegration); if (other.baselineSelection) baselineSelection = other.baselineSelection; if (other.chunkSize) chunkSize = other.chunkSize; if (other.combineSPWs) combineSPWs = other.combineSPWs; if (other.concatenateFrequency) concatenateFrequency = other.concatenateFrequency; if (!other.dataColumn.empty()) dataColumn = other.dataColumn; if (!other.executeFilename.empty()) executeFilename = other.executeFilename; if (!other.executeFunctionName.empty()) executeFunctionName = other.executeFunctionName; if (!other.fields.empty()) fields = other.fields; if (other.readMode) readMode = other.readMode; if (other.readUVW) readUVW = other.readUVW; if (!other.scriptVersion.empty()) scriptVersion = other.scriptVersion; if (other.skipFlagged) skipFlagged = other.skipFlagged; if (other.startTimestep) startTimestep = other.startTimestep; if (other.endTimestep) endTimestep = other.endTimestep; if (!other.strategyFilename.empty()) strategyFilename = other.strategyFilename; if (other.threadCount) threadCount = other.threadCount; if (other.logVerbosity) logVerbosity = other.logVerbosity; preamble.insert(preamble.begin(), other.preamble.begin(), other.preamble.end()); if (!other.commandLine.empty()) commandLine = other.commandLine; if (!other.filenames.empty()) filenames = other.filenames; } bool operator==(const Options& rhs) const { return antennaeToInclude == rhs.antennaeToInclude && antennaeToSkip == rhs.antennaeToSkip && bands == rhs.bands && baselineIntegration == rhs.baselineIntegration && baselineSelection == rhs.baselineSelection && chunkSize == rhs.chunkSize && combineSPWs == rhs.combineSPWs && concatenateFrequency == rhs.concatenateFrequency && dataColumn == rhs.dataColumn && executeFilename == rhs.executeFilename && executeFunctionName == rhs.executeFunctionName && fields == rhs.fields && readMode == rhs.readMode && readUVW == rhs.readUVW && scriptVersion == rhs.scriptVersion && skipFlagged == rhs.skipFlagged && startTimestep == rhs.startTimestep && endTimestep == rhs.endTimestep && strategyFilename == rhs.strategyFilename && threadCount == rhs.threadCount && logVerbosity == rhs.logVerbosity && preamble == rhs.preamble && commandLine == rhs.commandLine && filenames == rhs.filenames; } bool operator!=(const Options& rhs) const { return !(*this == rhs); } size_t CalculateThreadCount() const; }; #endif aoflagger-v3.4.0/aoluarunner/baselineiterator.h0000644000175000017500000000553014507760372020377 0ustar olesoles#ifndef RFISTRATEGYFOREACHBASELINEACTION_H #define RFISTRATEGYFOREACHBASELINEACTION_H #include "options.h" #include "../imagesets/imageset.h" #include #include #include #include #include #include #include #include class BaselineIterator { public: BaselineIterator(std::mutex* ioMutex, const Options& options); ~BaselineIterator(); void Run(imagesets::ImageSet& imageSet, class LuaThreadGroup& lua, class ScriptData& scriptData); private: bool IsSequenceSelected(imagesets::ImageSetIndex& index); imagesets::ImageSetIndex GetNextIndex(); static std::string memToStr(double memSize); void SetExceptionOccured(); void SetFinishedBaselines(); // void SetProgress(ProgressListener &progress, int no, int count, const // std::string& taskName, int threadId); size_t BaselineProgress() { std::lock_guard lock(_mutex); return _baselineProgress; } void IncBaselineProgress() { std::lock_guard lock(_mutex); ++_baselineProgress; } void WaitForReadBufferAvailable(size_t maxSize) { std::unique_lock lock(_mutex); while (_baselineBuffer.size() > maxSize && !_exceptionOccured) _dataProcessed.wait(lock); } std::unique_ptr GetNextBaseline() { std::unique_lock lock(_mutex); while (_baselineBuffer.size() == 0 && !_exceptionOccured && !_finishedBaselines) _dataAvailable.wait(lock); if ((_finishedBaselines && _baselineBuffer.size() == 0) || _exceptionOccured) { return nullptr; } else { std::unique_ptr next = std::move(_baselineBuffer.top()); _baselineBuffer.pop(); _dataProcessed.notify_one(); return next; } } size_t GetBaselinesInBufferCount() { std::lock_guard lock(_mutex); return _baselineBuffer.size(); } struct ProcessingThread { ProcessingThread(BaselineIterator& parent, size_t threadIndex) : _parent(parent), _threadIndex(threadIndex) {} BaselineIterator& _parent; size_t _threadIndex; void operator()(); }; struct ReaderThread { explicit ReaderThread(BaselineIterator& parent) : _parent(parent) {} void operator()(); BaselineIterator& _parent; }; const Options& _options; LuaThreadGroup* _lua; imagesets::ImageSet* _imageSet; size_t _sequenceCount, _nextIndex; size_t _threadCount; imagesets::ImageSetIndex _loopIndex; std::unique_ptr _writeThread; std::mutex _mutex, *_ioMutex; std::condition_variable _dataAvailable, _dataProcessed; std::stack> _baselineBuffer; bool _finishedBaselines; bool _exceptionOccured; size_t _baselineProgress; class ScriptData* _globalScriptData; }; #endif aoflagger-v3.4.0/aoluarunner/runner.h0000644000175000017500000000300114507760372016343 0ustar olesoles#ifndef RUNNER_H #define RUNNER_H #include "options.h" #include "../imagesets/imageset.h" #include #include #include #include struct ChunkInfo; class Runner { public: explicit Runner(const Options& cmdLineOptions) : _cmdLineOptions(cmdLineOptions) {} void Run(); private: struct FileOptions { std::string filename; size_t nIntervals = 1; size_t intervalIndex = 0; size_t resolvedIntStart = 0, resolvedIntEnd = 0; std::optional intervalStart, intervalEnd; }; void run(const Options& options); void loadStrategy(class LuaThreadGroup& lua, const Options& options, const std::unique_ptr& imageSet); void processFile(const Options& options, const std::string& filename, size_t threadCount); void processFrequencyConcatenatedFiles( Options options, const std::vector& filenames, size_t n_threads); void ProcessFrequencyConcatenatedFilesChunk( const Options& options, const std::vector& ms_names, size_t n_threads, size_t n_io_threads, const std::optional& chunk_info); std::unique_ptr initializeImageSet( const Options& options, FileOptions& fileOptions); void writeHistory(const Options& options, const std::string& filename); void finishStatistics(const std::string& filename, class ScriptData& scriptData, bool isMS); Options _cmdLineOptions; }; #endif aoflagger-v3.4.0/aoluarunner/options.cpp0000644000175000017500000000030614507760372017065 0ustar olesoles#include "options.h" #include size_t Options::CalculateThreadCount() const { if (threadCount) return threadCount; else return aocommon::system::ProcessorCount(); } aoflagger-v3.4.0/cmake/0000755000175000017500000000000014516225226013406 5ustar olesolesaoflagger-v3.4.0/cmake/FindCasacore.cmake0000644000175000017500000002431614507760372016745 0ustar olesoles# * Try to find Casacore include dirs and libraries Usage: find_package(Casacore # [REQUIRED] [COMPONENTS components...]) Valid components are: casa, # coordinates, derivedmscal, fits, images, lattices, meas, measures, mirlib, # ms, msfits, python, scimath, scimath_f, tables # # Note that most components are dependent on other (more basic) components. In # that case, it suffices to specify the "top-level" components; dependent # components will be searched for automatically. # # The dependency tree can be generated using the script get_casacore_deps.sh. # For this, you need to have a complete casacore installation, built with shared # libraries, at your disposal. # # The dependencies in this macro were generated against casacore release 1.7.0. # # Variables used by this module: CASACORE_ROOT_DIR - Casacore root # directory. # # Variables defined by this module: CASACORE_FOUND - System has # Casacore, which means that the include dir was found, as well as all libraries # specified (not cached) CASACORE_INCLUDE_DIR - Casacore include directory # (cached) CASACORE_INCLUDE_DIRS - Casacore include directories (not cached) # identical to CASACORE_INCLUDE_DIR CASACORE_LIBRARIES - The Casacore # libraries (not cached) CASA_${COMPONENT}_LIBRARY - The absolute path of # Casacore library "component" (cached) HAVE_AIPSPP - True if # system has Casacore (cached) for backward compatibility with AIPS++ # HAVE_CASACORE - True if system has Casacore (cached) identical to # CASACORE_FOUND TAQL_EXECUTABLE - The absolute path of the TaQL # executable (cached) # # ATTENTION: The component names need to be in lower case, just as the casacore # library names. However, the CMake variables use all upper case. # Copyright (C) 2009 ASTRON (Netherlands Institute for Radio Astronomy) P.O.Box # 2, 7990 AA Dwingeloo, The Netherlands # # This file is part of the LOFAR software suite. The LOFAR software suite is # free software: you can redistribute it and/or modify it under the terms of the # GNU General Public License as published by the Free Software Foundation, # either version 3 of the License, or (at your option) any later version. # # The LOFAR software suite is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # the LOFAR software suite. If not, see . # # $Id: FindCasacore.cmake 31487 2015-04-16 11:28:17Z dijkema $ # * casacore_resolve_dependencies(_result) # # Resolve the Casacore library dependencies for the given components. The list # of dependent libraries will be returned in the variable result. It is sorted # from least dependent to most dependent library, so it can be directly fed to # the linker. # # Usage: casacore_resolve_dependencies(result components...) # macro(casacore_resolve_dependencies _result) set(${_result} ${ARGN}) set(_index 0) # Do a breadth-first search through the dependency graph; append to the result # list the dependent components for each item in that list. Duplicates will be # removed later. while(1) list(LENGTH ${_result} _length) if(NOT _index LESS _length) break() endif(NOT _index LESS _length) list(GET ${_result} ${_index} item) list(APPEND ${_result} ${Casacore_${item}_DEPENDENCIES}) math(EXPR _index "${_index}+1") endwhile(1) # Remove all duplicates in the current result list, while retaining only the # last of each duplicate. list(REVERSE ${_result}) list(REMOVE_DUPLICATES ${_result}) list(REVERSE ${_result}) endmacro(casacore_resolve_dependencies _result) # * casacore_find_library(_name) # # Search for the library ${_name}. If library is found, add it to # CASACORE_LIBRARIES; if not, add ${_name} to CASACORE_MISSING_COMPONENTS and # set CASACORE_FOUND to false. # # Usage: casacore_find_library(name) # macro(casacore_find_library _name) string(TOUPPER ${_name} _NAME) find_library( ${_NAME}_LIBRARY ${_name} HINTS ${CASACORE_ROOT_DIR} PATH_SUFFIXES lib) mark_as_advanced(${_NAME}_LIBRARY) if(${_NAME}_LIBRARY) list(APPEND CASACORE_LIBRARIES ${${_NAME}_LIBRARY}) else(${_NAME}_LIBRARY) set(CASACORE_FOUND FALSE) list(APPEND CASACORE_MISSING_COMPONENTS ${_name}) endif(${_NAME}_LIBRARY) endmacro(casacore_find_library _name) # * casacore_find_package(_name) # # Search for the package ${_name}. If the package is found, add the contents of # ${_name}_INCLUDE_DIRS to CASACORE_INCLUDE_DIRS and ${_name}_LIBRARIES to # CASACORE_LIBRARIES. # # If Casacore itself is required, then, strictly speaking, the packages it # requires must be present. However, when linking against static libraries they # may not be needed. One can override the REQUIRED setting by switching # CASACORE_MAKE_REQUIRED_EXTERNALS_OPTIONAL to ON. Beware that this might cause # compile and/or link errors. # # Usage: casacore_find_package(name [REQUIRED]) # macro(casacore_find_package _name) if("${ARGN}" MATCHES "^REQUIRED$" AND Casacore_FIND_REQUIRED AND NOT CASACORE_MAKE_REQUIRED_EXTERNALS_OPTIONAL) find_package(${_name} REQUIRED) else() find_package(${_name}) endif() if(${_name}_FOUND) list(APPEND CASACORE_INCLUDE_DIRS ${${_name}_INCLUDE_DIRS}) list(APPEND CASACORE_LIBRARIES ${${_name}_LIBRARIES}) endif(${_name}_FOUND) endmacro(casacore_find_package _name) # Define the Casacore components. set(Casacore_components casa coordinates derivedmscal fits images lattices meas measures mirlib ms msfits python scimath scimath_f tables) # Define the Casacore components' inter-dependencies. set(Casacore_casa_DEPENDENCIES) set(Casacore_coordinates_DEPENDENCIES fits measures casa) set(Casacore_derivedmscal_DEPENDENCIES ms measures tables casa) set(Casacore_fits_DEPENDENCIES measures tables casa) set(Casacore_images_DEPENDENCIES mirlib lattices coordinates fits measures scimath tables casa) set(Casacore_lattices_DEPENDENCIES tables scimath casa) set(Casacore_meas_DEPENDENCIES measures tables casa) set(Casacore_measures_DEPENDENCIES tables casa) set(Casacore_mirlib_DEPENDENCIES) set(Casacore_ms_DEPENDENCIES measures scimath tables casa) set(Casacore_msfits_DEPENDENCIES ms fits measures tables casa) set(Casacore_python_DEPENDENCIES casa) set(Casacore_scimath_DEPENDENCIES scimath_f casa) set(Casacore_scimath_f_DEPENDENCIES) set(Casacore_tables_DEPENDENCIES casa) # Initialize variables. set(CASACORE_FOUND FALSE) set(CASACORE_DEFINITIONS) set(CASACORE_LIBRARIES) set(CASACORE_MISSING_COMPONENTS) # Search for the header file first. if(NOT CASACORE_INCLUDE_DIR) find_path( CASACORE_INCLUDE_DIR casacore/casa/aips.h HINTS ${CASACORE_ROOT_DIR} PATH_SUFFIXES include) mark_as_advanced(CASACORE_INCLUDE_DIR) endif(NOT CASACORE_INCLUDE_DIR) # Fallback for systems that have old casacore installed in directory not called # 'casacore' This fallback can be removed once we move to casacore 2.0 which # always puts headers in 'casacore' if(NOT CASACORE_INCLUDE_DIR) find_path( CASACORE_INCLUDE_DIR casa/aips.h HINTS ${CASACORE_ROOT_DIR} PATH_SUFFIXES include) mark_as_advanced(CASACORE_INCLUDE_DIR) endif(NOT CASACORE_INCLUDE_DIR) if(NOT CASACORE_INCLUDE_DIR) set(CASACORE_ERROR_MESSAGE "Casacore: unable to find the header file casa/aips.h.\nPlease set CASACORE_ROOT_DIR to the root directory containing Casacore." ) else(NOT CASACORE_INCLUDE_DIR) # We've found the header file; let's continue. set(CASACORE_FOUND TRUE) # Note that new Casacore uses #include, while LOFAR still # uses #include. Hence use both in -I path. set(CASACORE_INCLUDE_DIRS ${CASACORE_INCLUDE_DIR} ${CASACORE_INCLUDE_DIR}/casacore) # Search for some often used binaries. find_program(TAQL_EXECUTABLE taql HINTS ${CASACORE_ROOT_DIR}/bin) mark_as_advanced(TAQL_EXECUTABLE) # If the user specified components explicity, use that list; otherwise we'll # assume that the user wants to use all components. if(NOT Casacore_FIND_COMPONENTS) set(Casacore_FIND_COMPONENTS ${Casacore_components}) endif(NOT Casacore_FIND_COMPONENTS) # Get a list of all dependent Casacore libraries that need to be found. casacore_resolve_dependencies(_find_components ${Casacore_FIND_COMPONENTS}) # Find the library for each component, and handle external dependencies foreach(_comp ${_find_components}) casacore_find_library(casa_${_comp}) if(${_comp} STREQUAL casa) casacore_find_package(HDF5) casacore_find_library(m) list(APPEND CASACORE_LIBRARIES ${CMAKE_DL_LIBS}) elseif(${_comp} STREQUAL coordinates) casacore_find_package(WCSLIB REQUIRED) elseif(${_comp} STREQUAL fits) casacore_find_package(CFITSIO REQUIRED) elseif(${_comp} STREQUAL scimath_f) casacore_find_package(LAPACK REQUIRED) endif(${_comp} STREQUAL casa) endforeach(_comp ${_find_components}) endif(NOT CASACORE_INCLUDE_DIR) # Set HAVE_CASACORE; and HAVE_AIPSPP (for backward compatibility with AIPS++). if(CASACORE_FOUND) set(HAVE_CASACORE TRUE CACHE INTERNAL "Define if Casacore is installed") set(HAVE_AIPSPP TRUE CACHE INTERNAL "Define if AIPS++/Casacore is installed") endif(CASACORE_FOUND) # Compose diagnostic message if not all necessary components were found. if(CASACORE_MISSING_COMPONENTS) set(CASACORE_ERROR_MESSAGE "Casacore: the following components could not be found:\n ${CASACORE_MISSING_COMPONENTS}" ) endif(CASACORE_MISSING_COMPONENTS) # Print diagnostics. if(CASACORE_FOUND) if(NOT Casacore_FIND_QUIETLY) message(STATUS "Found the following Casacore components: ") foreach(_comp ${_find_components}) string(TOUPPER casa_${_comp} _COMP) message(STATUS " ${_comp}: ${${_COMP}_LIBRARY}") endforeach(_comp ${_find_components}) endif(NOT Casacore_FIND_QUIETLY) else(CASACORE_FOUND) if(Casacore_FIND_REQUIRED) message(FATAL_ERROR "${CASACORE_ERROR_MESSAGE}") else(Casacore_FIND_REQUIRED) message(STATUS "${CASACORE_ERROR_MESSAGE}") endif(Casacore_FIND_REQUIRED) endif(CASACORE_FOUND) aoflagger-v3.4.0/cmake/config/0000755000175000017500000000000014516225226014653 5ustar olesolesaoflagger-v3.4.0/cmake/config/aoflagger-config.cmake.in0000644000175000017500000000226014507760372021462 0ustar olesoles# This is the cmake config script for AOFlagger. # # It sets the following variables: # - AOFLAGGER_INCLUDE_DIR # - AOFLAGGER_LIB # - AOFLAGGER_LIB_PATH # - AOFLAGGER_VERSION[_MAJOR/_MINOR] # - AOFLAGGER_FOUND # - AOFLAGGER_ROOT_DIR # Compute path get_filename_component(_AOFLAGGER_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(_AOFLAGGER_CMAKE_DIR_ABS "${_AOFLAGGER_CMAKE_DIR}" ABSOLUTE) get_filename_component(_AOFLAGGER_ROOT_DIR "${_AOFLAGGER_CMAKE_DIR_ABS}/../../.." ABSOLUTE) set(AOFLAGGER_ROOT_DIR "${_AOFLAGGER_ROOT_DIR}" CACHE PATH "AOFlagger root (prefix) directory") set(AOFLAGGER_INCLUDE_DIR "${AOFLAGGER_ROOT_DIR}/include" CACHE PATH "AOFlagger include directory") set(AOFLAGGER_LIB_PATH "${AOFLAGGER_ROOT_DIR}/lib" CACHE PATH "AOFlagger library directory") find_library(AOFLAGGER_LIB aoflagger PATH ${AOFLAGGER_LIB_PATH} NO_DEFAULT_PATH DOC "AOFlagger library directory") message(STATUS "Found AOFlagger @AOFLAGGER_VERSION@.") message(STATUS " AOFlagger include dir: ${AOFLAGGER_INCLUDE_DIR}") message(STATUS " AOFlagger lib: ${AOFLAGGER_LIB}") unset(_AOFLAGGER_ROOT_DIR) unset(_AOFLAGGER_CMAKE_DIR) unset(_AOFLAGGER_CMAKE_DIR_ABS) aoflagger-v3.4.0/cmake/config/aoflagger-config-version.cmake.in0000644000175000017500000000141314507760372023144 0ustar olesolesset(PACKAGE_VERSION "@AOFLAGGER_VERSION@") # Versions are compatible if version found >= necessary AND the major # version number matches. Hence, requiring aoflagger 2.10 would not # be compatible with a found version of 3.0. if("@AOFLAGGER_VERSION@" VERSION_LESS PACKAGE_FIND_VERSION OR NOT "@AOFLAGGER_VERSION_MAJOR@" VERSION_EQUAL PACKAGE_FIND_VERSION_MAJOR) message(STATUS "Found an incompatible version of AOFlagger: found @AOFLAGGER_VERSION@, need ${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) set(PACKAGE_VERSION_EXACT FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if("@AOFLAGGER_VERSION@" VERSION_EQUAL PACKAGE_FIND_VERSION) set(PACKAGE_VERSION_EXACT TRUE) else() set(PACKAGE_VERSION_EXACT FALSE) endif() endif() aoflagger-v3.4.0/cmake/FindCFITSIO.cmake0000644000175000017500000000377214507760372016330 0ustar olesoles# * Try to find CFITSIO. Variables used by this module: CFITSIO_ROOT_DIR - # CFITSIO root directory Variables defined by this module: CFITSIO_FOUND - # system has CFITSIO CFITSIO_INCLUDE_DIR - the CFITSIO include directory # (cached) CFITSIO_INCLUDE_DIRS - the CFITSIO include directories (identical # to CFITSIO_INCLUDE_DIR) CFITSIO_LIBRARY - the CFITSIO library (cached) # CFITSIO_LIBRARIES - the CFITSIO libraries (identical to CFITSIO_LIBRARY) # Copyright (C) 2009 ASTRON (Netherlands Institute for Radio Astronomy) P.O.Box # 2, 7990 AA Dwingeloo, The Netherlands # # This file is part of the LOFAR software suite. The LOFAR software suite is # free software: you can redistribute it and/or modify it under the terms of the # GNU General Public License as published by the Free Software Foundation, # either version 3 of the License, or (at your option) any later version. # # The LOFAR software suite is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # the LOFAR software suite. If not, see . # # $Id: FindCFITSIO.cmake 22498 2012-10-23 10:51:12Z loose $ if(NOT CFITSIO_FOUND) find_path( CFITSIO_INCLUDE_DIR fitsio.h HINTS ${CFITSIO_ROOT_DIR} PATH_SUFFIXES include include/cfitsio include/libcfitsio0) find_library( CFITSIO_LIBRARY cfitsio HINTS ${CFITSIO_ROOT_DIR} PATH_SUFFIXES lib) find_library(M_LIBRARY m) mark_as_advanced(CFITSIO_INCLUDE_DIR CFITSIO_LIBRARY M_LIBRARY) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(CFITSIO DEFAULT_MSG CFITSIO_LIBRARY M_LIBRARY CFITSIO_INCLUDE_DIR) set(CFITSIO_INCLUDE_DIRS ${CFITSIO_INCLUDE_DIR}) set(CFITSIO_LIBRARIES ${CFITSIO_LIBRARY} ${M_LIBRARY}) endif(NOT CFITSIO_FOUND) aoflagger-v3.4.0/cpack/0000755000175000017500000000000014516225226013407 5ustar olesolesaoflagger-v3.4.0/cpack/CMakeLists.txt0000644000175000017500000000205614507760372016160 0ustar olesoles# Copyright (C) 2020 A. R. Offringa. SPDX-License-Identifier: GPL-3.0-or-later set(CPACK_PACKAGE_NAME "AOFlagger") set(CPACK_PACKAGE_VENDOR "ASTRON") set(CPACK_PACKAGE_VERSION_MAJOR "${AOFLAGGER_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${AOFLAGGER_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${AOFLAGGER_VERSION_SUBMINOR}") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}" ) set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Find RFI in radio astronomical observations") set(CPACK_PACKAGE_HOMEPAGE_URL "https://gitlab.com/aroffringa/aoflagger/") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING") set(CPACK_GENERATOR "DEB") set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) set(CPACK_DEBIAN_PACKAGE_MAINTAINER "deb-packages@astron.nl") set(CPACK_DEBIAN_PACKAGE_SECTION "science") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) include(CPack) aoflagger-v3.4.0/interface/0000755000175000017500000000000014516225226014266 5ustar olesolesaoflagger-v3.4.0/interface/qualitystatistics.cpp0000644000175000017500000001031014507760372020576 0ustar olesoles#ifndef QUALITY_STATISTICS_DATA_H #define QUALITY_STATISTICS_DATA_H #include "aoflagger.h" #include "structures.h" namespace aoflagger { QualityStatistics::QualityStatistics() : _data(nullptr) {} QualityStatistics::QualityStatistics(const double* scanTimes, size_t nScans, const double* channelFrequencies, size_t nChannels, size_t nPolarizations, bool computeHistograms) : _data(new QualityStatisticsData(scanTimes, nScans, nPolarizations, computeHistograms)) { _data->_implementation->statistics.InitializeBand(0, channelFrequencies, nChannels); } QualityStatistics::QualityStatistics(const QualityStatistics& sourceQS) : _data(sourceQS._data == nullptr ? nullptr : new QualityStatisticsData(sourceQS._data->_implementation)) {} QualityStatistics::QualityStatistics(QualityStatistics&& sourceQS) : _data(std::move(sourceQS._data)) { sourceQS._data = nullptr; } QualityStatistics::~QualityStatistics() {} QualityStatistics& QualityStatistics::operator=( const QualityStatistics& sourceQS) { if (_data == nullptr) { if (sourceQS._data != nullptr) _data.reset(new QualityStatisticsData(sourceQS._data->_implementation)); } else { if (sourceQS._data != nullptr) { _data->_implementation = sourceQS._data->_implementation; } else { _data.reset(); } } return *this; } QualityStatistics& QualityStatistics::operator=(QualityStatistics&& sourceQS) { if (_data == nullptr || sourceQS._data == nullptr) { std::swap(_data, sourceQS._data); } else { _data->_implementation = std::move(sourceQS._data->_implementation); } return *this; } QualityStatistics& QualityStatistics::operator+=(const QualityStatistics& rhs) { _data->_implementation->statistics.Add( rhs._data->_implementation->statistics); _data->_implementation->histograms.Add( rhs._data->_implementation->histograms); return *this; } void QualityStatistics::CollectStatistics(const ImageSet& imageSet, const FlagMask& rfiFlags, const FlagMask& correlatorFlags, size_t antenna1, size_t antenna2) { StatisticsCollection& stats(_data->_implementation->statistics); HistogramCollection& histograms(_data->_implementation->histograms); const std::vector& times(_data->_implementation->scanTimes); if (imageSet.ImageCount() == 1) { stats.AddImage(antenna1, antenna2, ×[0], 0, 0, imageSet._data->images[0], imageSet._data->images[0], rfiFlags._data->mask, correlatorFlags._data->mask); if (_data->_implementation->computeHistograms) { histograms.Add(antenna1, antenna2, 0, imageSet._data->images[0], rfiFlags._data->mask, correlatorFlags._data->mask); } } else { const size_t polarizationCount = imageSet.ImageCount() / 2; for (size_t polarization = 0; polarization != polarizationCount; ++polarization) { stats.AddImage(antenna1, antenna2, ×[0], 0, polarization, imageSet._data->images[polarization * 2], imageSet._data->images[polarization * 2 + 1], rfiFlags._data->mask, correlatorFlags._data->mask); if (_data->_implementation->computeHistograms) { histograms.Add(antenna1, antenna2, polarization, imageSet._data->images[polarization * 2], imageSet._data->images[polarization * 2 + 1], rfiFlags._data->mask, correlatorFlags._data->mask); } } } } void QualityStatistics::WriteStatistics( const std::string& measurementSetPath) const { QualityTablesFormatter qFormatter(measurementSetPath); _data->_implementation->statistics.Save(qFormatter); HistogramCollection& histograms(_data->_implementation->histograms); if (!histograms.Empty()) { HistogramTablesFormatter hFormatter(measurementSetPath); histograms.Save(hFormatter); } } } // end of namespace aoflagger #endif aoflagger-v3.4.0/interface/aoflagger.cpp0000644000175000017500000000255314507760372016734 0ustar olesoles#include "aoflagger.h" #include "../lua/telescopefile.h" #include namespace aoflagger { std::string AOFlagger::FindStrategyFile(enum TelescopeId telescopeId, const std::string& scenario) { return TelescopeFile::FindStrategy( static_cast(telescopeId), scenario); } QualityStatistics AOFlagger::MakeQualityStatistics( const double* scanTimes, size_t nScans, const double* channelFrequencies, size_t nChannels, size_t nPolarizations) { return QualityStatistics(scanTimes, nScans, channelFrequencies, nChannels, nPolarizations, false); } QualityStatistics AOFlagger::MakeQualityStatistics( const double* scanTimes, size_t nScans, const double* channelFrequencies, size_t nChannels, size_t nPolarizations, bool computeHistograms) { return QualityStatistics(scanTimes, nScans, channelFrequencies, nChannels, nPolarizations, computeHistograms); } std::string AOFlagger::GetVersionString() { return AOFLAGGER_VERSION_STR; } void AOFlagger::GetVersion(short& major, short& minor, short& subMinor) { major = AOFLAGGER_VERSION_MAJOR; minor = AOFLAGGER_VERSION_MINOR; subMinor = AOFLAGGER_VERSION_SUBMINOR; } std::string AOFlagger::GetVersionDate() { return AOFLAGGER_VERSION_DATE_STR; } } // end of namespace aoflagger aoflagger-v3.4.0/interface/interface.dox0000644000175000017500000000165014507760372016752 0ustar olesoles/** \mainpage AOFlagger public interface API * * ### About the API * * These pages describe the C++ API of the public interface. This interface can * be used to integrate the flagger into an observatory pipeline in an easy * way, without having to know the internals of the flagger. If this flagger * is to be integrated in a pipeline, the best place to start is to * read the class description of class @ref aoflagger::AOFlagger. * This interface has also been wrapped in a Python interface. * * To use libaoflagger, add an "#include " to your C++ * program and link with "-laoflagger". For installation instructions, check * the website. * * The official webpage of the full documentation is http://aoflagger.readthedocs.io/ . * Additionally, the * * LOFAR imaging cookbook contains a lot of general info about running the * flagger. */ aoflagger-v3.4.0/interface/flagmask.cpp0000644000175000017500000000275714507760372016600 0ustar olesoles#include "aoflagger.h" #include "structures.h" namespace aoflagger { FlagMask::FlagMask() : _data(nullptr) {} FlagMask::FlagMask(size_t width, size_t height) : _data(new FlagMaskData(Mask2D::CreateUnsetMaskPtr(width, height))) {} FlagMask::FlagMask(size_t width, size_t height, bool initialValue) : _data(new FlagMaskData(Mask2D::CreateUnsetMaskPtr(width, height))) { if (initialValue) _data->mask->SetAll(); else _data->mask->SetAll(); } FlagMask::FlagMask(const FlagMask& sourceMask) : _data(sourceMask._data == nullptr ? nullptr : new FlagMaskData(*sourceMask._data)) { } FlagMask::FlagMask(FlagMask&& sourceMask) : _data(std::move(sourceMask._data)) {} FlagMask& FlagMask::operator=(const FlagMask& flagMask) { if (flagMask._data == nullptr) { _data.reset(); } else if (_data == nullptr) { _data.reset(new FlagMaskData(*flagMask._data)); } else { *_data = *flagMask._data; } return *this; } FlagMask& FlagMask::operator=(FlagMask&& flagMask) { std::swap(_data, flagMask._data); return *this; } FlagMask::~FlagMask() {} size_t FlagMask::Width() const { return _data->mask->Width(); } size_t FlagMask::Height() const { return _data->mask->Height(); } size_t FlagMask::HorizontalStride() const { return _data->mask->Stride(); } bool* FlagMask::Buffer() { return _data->mask->ValuePtr(0, 0); } const bool* FlagMask::Buffer() const { return _data->mask->ValuePtr(0, 0); } } // namespace aoflagger aoflagger-v3.4.0/interface/strategy.cpp0000644000175000017500000001474614507760372016656 0ustar olesoles#include "aoflagger.h" #include "structures.h" #include "../lua/luastrategy.h" #include "../lua/scriptdata.h" #include "../util/progress/progresslistener.h" #include "../structures/timefrequencydata.h" #include namespace aoflagger { class ErrorListener final : public ProgressListener { void OnStartTask(const std::string&) override {} void OnProgress(size_t, size_t) override {} void OnFinish() override {} void OnException(std::exception& e) override { std::cerr << "*** EXCEPTION OCCURED IN THE AOFLAGGER ***\n" "The AOFlagger encountered a bug or the given strategy was " "invalid!\n" "The reported exception " << typeid(e).name() << " is:\n" << e.what(); } }; class ForwardingListener final : public ProgressListener { public: explicit ForwardingListener(StatusListener* destination) : _destination(destination) {} void OnStartTask(const std::string& description) override { _destination->OnStartTask(description); } void OnProgress(size_t progress, size_t maxProgress) override { _destination->OnProgress(progress, maxProgress); } void OnFinish() override { _destination->OnFinish(); } void OnException(std::exception& thrownException) override { _destination->OnException(thrownException); } private: StatusListener* _destination; }; class StrategyData { public: [[no_unique_address]] LuaStrategy _lua; }; Strategy::Strategy() : _data(), _aoflagger(nullptr) {} Strategy::Strategy(const std::string& filename, AOFlagger* aoflagger) : _data(new StrategyData()), _aoflagger(aoflagger) { _data->_lua.Initialize(); _data->_lua.LoadFile(filename.c_str()); } Strategy::Strategy(Strategy&& sourceStrategy) : _data(sourceStrategy._data ? new StrategyData(std::move(*sourceStrategy._data)) : nullptr), _aoflagger(sourceStrategy._aoflagger) {} Strategy::~Strategy() {} Strategy Strategy::makeFromString(const std::string& script, AOFlagger* aoflagger) { Strategy strategy; strategy._data.reset(new StrategyData()); strategy._aoflagger = aoflagger; strategy._data->_lua.Initialize(); strategy._data->_lua.LoadText(script); return strategy; } Strategy& Strategy::operator=(Strategy&& sourceStrategy) { if (sourceStrategy._data) _data = std::move(sourceStrategy._data); else _data = nullptr; _aoflagger = sourceStrategy._aoflagger; return *this; } inline static AntennaInfo ConvertAntenna(Antenna& antenna) { AntennaInfo antennaInfo; antennaInfo.diameter = antenna.diameter; antennaInfo.id = antenna.id; antennaInfo.mount = antenna.mount; antennaInfo.name = antenna.name; antennaInfo.station = antenna.station; antennaInfo.position.x = antenna.x; antennaInfo.position.y = antenna.y; antennaInfo.position.z = antenna.z; return antennaInfo; } inline static BandInfo ConvertBand(Band& band) { BandInfo bandInfo; bandInfo.windowIndex = band.id; bandInfo.channels.resize(band.channels.size()); for (size_t i = 0; i != band.channels.size(); ++i) { bandInfo.channels[i].frequencyIndex = i; bandInfo.channels[i].frequencyHz = band.channels[i].frequency; bandInfo.channels[i].channelWidthHz = band.channels[i].width; bandInfo.channels[i].effectiveBandWidthHz = band.channels[i].width; bandInfo.channels[i].resolutionHz = band.channels[i].width; } return bandInfo; } FlagMask Strategy::Run(const ImageSet& input, const FlagMask& preExistingFlags) { return run(input, &preExistingFlags); } FlagMask Strategy::Run(const ImageSet& input) { return run(input, nullptr); } FlagMask Strategy::run(const ImageSet& input, const FlagMask* preExistingFlags) { std::unique_ptr listener; if (_aoflagger->_statusListener == nullptr) listener.reset(new ErrorListener()); else listener.reset(new ForwardingListener(_aoflagger->_statusListener)); Mask2DCPtr inputMask; if (preExistingFlags == nullptr) inputMask = Mask2D::CreateSetMaskPtr(input.Width(), input.Height()); else inputMask = preExistingFlags->_data->mask; TimeFrequencyData inputData; const Image2DPtr zeroImage = Image2D::CreateZeroImagePtr(input.Width(), input.Height()); switch (input.ImageCount()) { case 1: inputData = TimeFrequencyData(TimeFrequencyData::AmplitudePart, aocommon::Polarization::StokesI, input._data->images[0]); inputData.SetGlobalMask(inputMask); break; case 2: inputData = TimeFrequencyData(aocommon::Polarization::StokesI, input._data->images[0], input._data->images[1]); inputData.SetGlobalMask(inputMask); break; case 4: inputData = TimeFrequencyData(aocommon::Polarization::XX, input._data->images[0], input._data->images[1], aocommon::Polarization::YY, input._data->images[2], input._data->images[3]); inputData.SetIndividualPolarizationMasks(inputMask, inputMask); break; case 8: inputData = TimeFrequencyData::FromLinear( input._data->images[0], input._data->images[1], input._data->images[2], input._data->images[3], input._data->images[4], input._data->images[5], input._data->images[6], input._data->images[7]); inputData.SetIndividualPolarizationMasks(inputMask, inputMask, inputMask, inputMask); break; } const TimeFrequencyMetaDataPtr metaData(new TimeFrequencyMetaData()); if (input.HasAntennas() && !_aoflagger->_antennas.empty()) { metaData->SetAntenna1( ConvertAntenna(_aoflagger->_antennas[input.Antenna1()])); metaData->SetAntenna2( ConvertAntenna(_aoflagger->_antennas[input.Antenna2()])); } if (input.HasBand() && !_aoflagger->_bands.empty()) { metaData->SetBand(ConvertBand(_aoflagger->_bands[input.Band()])); } if (input.HasInterval() && !_aoflagger->_intervals.empty()) { metaData->SetObservationTimes( _aoflagger->_intervals[input.Interval()].times); } ScriptData scriptData; scriptData.SetProgressListener(*listener); _data->_lua.Execute(inputData, metaData, scriptData, "execute"); listener.reset(); inputMask.reset(); FlagMask flagMask; flagMask._data.reset( new FlagMaskData(Mask2DPtr(new Mask2D(*inputData.GetSingleMask())))); return flagMask; } } // namespace aoflagger aoflagger-v3.4.0/interface/structures.h0000644000175000017500000000351414507760372016673 0ustar olesoles#ifndef AOFLAGGER_STRUCTURES_H #define AOFLAGGER_STRUCTURES_H #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../structures/timefrequencymetadata.h" #include "../quality/histogramcollection.h" #include "../quality/statisticscollection.h" #include #include namespace aoflagger { class FlagMaskData { public: explicit FlagMaskData(Mask2DPtr theMask) : mask(theMask) {} Mask2DPtr mask; }; class ImageSetData { public: explicit ImageSetData(size_t initialSize) : images(initialSize), hasAntennas(false), hasInterval(false), hasBand(false), antenna1(0), antenna2(0), interval(0), band(0) {} std::vector images; bool hasAntennas, hasInterval, hasBand; size_t antenna1, antenna2, interval, band; }; class QualityStatisticsDataImp { public: QualityStatisticsDataImp(const double* _scanTimes, size_t nScans, size_t nPolarizations, bool _computeHistograms) : scanTimes(_scanTimes, _scanTimes + nScans), statistics(nPolarizations), histograms(nPolarizations), computeHistograms(_computeHistograms) {} std::vector scanTimes; StatisticsCollection statistics; HistogramCollection histograms; bool computeHistograms; }; class QualityStatisticsData { public: QualityStatisticsData(const double* _scanTimes, size_t nScans, size_t nPolarizations, bool computeHistograms) : _implementation(new QualityStatisticsDataImp( _scanTimes, nScans, nPolarizations, computeHistograms)) {} explicit QualityStatisticsData( std::shared_ptr implementation) : _implementation(implementation) {} std::shared_ptr _implementation; }; } // namespace aoflagger #endif aoflagger-v3.4.0/interface/aoflagger.h0000644000175000017500000010075314507760372016402 0ustar olesoles/** @file aoflagger.h @brief Main AOFlagger header file. * @author André Offringa offringa@gmail.com * @copyright by A.R. Offringa under the GPL version 3 */ #ifndef AOFLAGGER_INTERFACE_H #define AOFLAGGER_INTERFACE_H #include #include #include #include #include /** @brief Contains all the public types used by the AOFlagger. * * See the @ref AOFlagger class description for details. * @author André Offringa offringa@gmail.com */ namespace aoflagger { /** @brief Strategy identifier for the supported telescopes. * * If you have an optimized strategy for an unlisted telescope, please * contact me. * @sa AOFlagger::FindStrategyFile(). * @since Version 3.0 */ enum class TelescopeId { /** @brief Most generic strategy. */ GENERIC_TELESCOPE, /** @brief The AARTFAAC telescope, correlating the superterp antennas of LOFAR. */ AARTFAAC_TELESCOPE, /** @brief The WSRT telescope with the Apertif focal plane array receiver system. */ APERTIF_TELESCOPE, /** @brief Arecibo radio telescope, the 305 m telescope in Puerto Rico. */ ARECIBO_TELESCOPE, /** @brief Australian Telescope Compact Array in Australia. */ ATCA_TELESCOPE, /** @brief Bighorns, instrument aimed at achieving an averaged all-sky measurement of the Epoch of Reionisation signal. */ BIGHORNS_TELESCOPE, /** @brief JVLA, the Jansky Very Large Array in New Mexico. */ JVLA_TELESCOPE, /** @brief LOFAR. the Low-Frequency Array in Europe. */ LOFAR_TELESCOPE, /** @brief MWA, the Murchison Widefield Array in Western Australia. */ MWA_TELESCOPE, /** @brief NenuFAR, the New Extension in Nançay upgrading LOFAR. */ NENUFAR_TELESCOPE, /** @brief Parkes, the single dish telescope in New South Wales. */ PARKES_TELESCOPE, /** @brief WSRT, the Westerbork Synthesis Radio Telescope in the Netherlands. */ WSRT_TELESCOPE }; /** * @brief Description of a single antenna. */ struct Antenna { /** @brief A unique identifying number for this antenna. */ size_t id; /** @brief ITRF position of the antenna. May be zero if unknown. */ double x, y, z; /** @brief Name of the antenna, e.g. "RT5". May be empty if unknown. */ std::string name; /** @brief Diameter of the antenna in meters. May be zero if unknown. */ double diameter; /** @brief Type of mount, e.g. "FIXED". May be empty if unknown. */ std::string mount; /** @brief Station to which this antenna belongs. May be empty if unknown. */ std::string station; }; /** * @brief A single channel. */ struct Channel { /** @brief Central frequency of this channel. */ double frequency; /** @brief Width of this channel. */ double width; }; /** * @brief Description of a single band. */ struct Band { /** @brief A unique identifying number for this band. */ size_t id; /** @brief List of channels in this band. */ std::vector channels; }; /** @brief A list of time value for a consecutive interval. */ struct Interval { size_t id; /** @brief Time values (MJD). */ std::vector times; }; /** @brief A set of time-frequency 'images' which together contain data for one * correlated baseline or dish. * * The class either holds 1, 2, 4 or 8 images. These images have time on the * x-axis (most rapidly changing index) and frequency on the y-axis. The * cells specify flux levels, which do not need to have been calibrated. * * If the set contains only one image, it specifies amplitudes of a single * polarization. If it contains two images, it specifies the real and imaginary * parts of a single polarization. With four images, it contains the real * and imaginary values of two polarizations (ordered real pol A, imag pol A, * real pol B, imag pol B). With eight images, it contains complex values for * four correlated polarizations (ordered real pol A, imag pol A, real pol B, * ... etc). * * @note When accesses the image data, note that there might be more items on * one row than the width of the image. The rows are padded to align them e.g. * for SSE instructions. Use @ref HorizontalStride() to get the actual number of * floats per row. */ class ImageSet { public: friend class AOFlagger; friend class QualityStatistics; friend class Strategy; /** @brief Construct an empty ImageSet. * * The only operations allowed on an empty ImageSet are to assign to it. Use * AOFlagger::MakeImageSet() to construct a non-empty ImageSet. */ ImageSet(); /** @brief Copy the image set. Only references to images are copied. */ ImageSet(const ImageSet& sourceImageSet); /** @brief Move from the image set. * @since Version 2.10 */ ImageSet(ImageSet&& sourceImageSet); /** @brief Destruct image set. Destroys its images if no longer referenced. */ ~ImageSet(); /** @brief Assign to this image set. Only references to images are copied. */ ImageSet& operator=(const ImageSet& sourceImageSet); /** @brief Move assign to this image set. * @since Version 2.10 */ ImageSet& operator=(ImageSet&& sourceImageSet); /** @brief Get access to the data buffer of an image. * @param imageIndex Index of image. See class description for ordering. * \note Rows are padded, see @ref HorizontalStride(). */ float* ImageBuffer(size_t imageIndex); /** @brief Get constant access to the data buffer of an image. * @param imageIndex Index of image. See class description for ordering. * \note Rows are padded, see @ref HorizontalStride(). */ const float* ImageBuffer(size_t imageIndex) const; /** @brief Get width (number of time steps) of images. */ size_t Width() const; /** @brief Get height (number of frequency channels) of images. */ size_t Height() const; /** @brief Get number of images, see class description for details. */ size_t ImageCount() const; /** @brief Get total number of floats in one row. * * Row might have been padded to allow for * SSE instructions and other optimizations. Therefore, one should * add the horizontal stride to a data pointer to get the float in the next * row (channel). * * Example: * @code{.cpp} *(ImageSet::ImageBuffer(imageIndex) + x + y * ImageSet::HorizontalStride()) * @endcode * will return the value at position x,y. */ size_t HorizontalStride() const; /** @brief Set all samples to the specified value. * @param newValue The new value for all values of all images in the set. * @since 2.5 */ void Set(float newValue); /** @brief Resize the image without reallocating new memory. * * This function allows to quickly change the dimension of the images in the * imageset. The new width has to fit in the image capacity as specified * during creation. When flagging many images of "almost" the same size, using * this method to change the size of images is drastically faster compared * to freeing and then allocating new images. It was added after rather * severe memory fragmentation problems in the Cotter MWA pipeline. * @param newWidth The new width of the images. Should satisfy newWidth <= * HorizontalStride(). * @since 2.5 */ void ResizeWithoutReallocation(size_t newWidth) const; void SetAntennas(size_t antenna1Index, size_t antenna2Index); bool HasAntennas() const; size_t Antenna1() const; size_t Antenna2() const; void SetInterval(size_t index); bool HasInterval() const; size_t Interval() const; void SetBand(size_t index); bool HasBand() const; size_t Band() const; private: ImageSet(size_t width, size_t height, size_t count); ImageSet(size_t width, size_t height, size_t count, float initialValue); ImageSet(size_t width, size_t height, size_t count, size_t widthCapacity); ImageSet(size_t width, size_t height, size_t count, float initialValue, size_t widthCapacity); static void assertValidCount(size_t count); std::unique_ptr _data; }; /** @brief A two-dimensional flag mask. * * The flag mask specifies which values in an @ref ImageSet are flagged. * A value @c true means a value is flagged, i.e., contains RFI and should * not be used in further data processing (calibration, imaging, etc.). * A flag denotes that the value at that time-frequency position should * be ignored for all polarizations. This normally makes sense, because if one * polarization is contaminated by RFI, all polarizations are probably * affected. Also, solving for Stokes matrices during calibration might * not work well when the polarizations are not flagged equally. * * If polarization-specific flags are needed, one could run the flagger on * each polarization individually. However, note that some algorithms, like * the morphological scale-invariant rank operator (SIR operator), work best * when seeing the flags from all polarizations. * * @note When accesses the flag data, note that there might be more items on one * row than the width of the mask. The rows are padded to align them e.g. for * SSE instructions. Use @ref HorizontalStride() to get the actual number of * bools per row. */ class FlagMask { public: friend class AOFlagger; friend class QualityStatistics; friend class Strategy; /** @brief Construct an empty FlagMask. * The properties of an empty FlagMask can not be accessed. */ FlagMask(); /** @brief Copy a flag mask. Only copies a reference, not the data. */ FlagMask(const FlagMask& sourceMask); /** @brief Move construct a flag mask. * @since Version 2.10 */ FlagMask(FlagMask&& sourceMask); /** @brief Copy assignment. * @since Version 2.10 */ FlagMask& operator=(const FlagMask& source); /** @brief Move assignment. * @since Version 2.10 */ FlagMask& operator=(FlagMask&& source); /** @brief Destroy a flag mask. Destroys mask data if no longer references. */ ~FlagMask(); /** @brief Get the width of the mask. */ size_t Width() const; /** @brief Get the height of the mask. */ size_t Height() const; /** @brief Get total number of bools in one row. * * Row might have been padded to allow for * SSE instructions and other optimizations. Therefore, one should * add the horizontal stride to a data pointer to get the flags in * the next row (channel). * * Example: * @code{.cpp} *(FlagMask::Buffer() + x + y * Buffer::HorizontalStride()) * @endcode * will return the flag value at position x,y. */ size_t HorizontalStride() const; /** @brief Get access to the data buffer. * @note The buffer is padded, see @ref HorizontalStride(). */ bool* Buffer(); /** @brief Get constant access to the data buffer. * @note The buffer is padded, see @ref HorizontalStride(). */ const bool* Buffer() const; private: FlagMask(size_t width, size_t height); FlagMask(size_t width, size_t height, bool initialValue); std::unique_ptr _data; }; /** @brief Holds a flagging strategy. * * Default "stock" strategies can be found with * @ref AOFlagger::FindStrategyFile(), and these or custom Lua files can * be loaded from disc with @ref AOFlagger::LoadStrategyFile(). * A user can create strategies with the @c rfigui tool that is part * of the aoflagger package. * * When flagging a large number of baselines it is recommended to use multiple * threads. This class is itself not thread save, but it is safe to use * different Strategy objects from different thread contexts. */ class Strategy { public: friend class AOFlagger; /** @brief Construct an empty strategy. * * The only operations allowed on an empty Strategy are to assign to it. Use * e.g. AOFlagger::LoadStrategyFile() to construct a non-empty Strategy. * @since Version 3 */ Strategy(); /** @brief Move construct a strategy. * @since Version 2.10 */ Strategy(Strategy&& sourceStrategy); /** @brief Destruct strategy. */ ~Strategy(); /** @brief Move assign to strategy. * @since Version 2.10 */ Strategy& operator=(Strategy&& sourceStrategy); /** @brief Run the flagging strategy on the given data. * * The Lua strategy is executed single-threaded. This function is not * thread safe: To flag multiple imagesets simultaneously from different * threads, it is necessary to create a Strategy object for each thread. * * @param input The data to run the flagger on. * @return The flags identifying bad (RFI contaminated) data. * @since 3.0 */ FlagMask Run(const ImageSet& input); /** @brief Run the flagging strategy on the given data with existing flags. * * This method is similar to @ref Run(const ImageSet&), except * that it will pass existing flags (e.g. as set by the correlator) * to the flagging strategy, which in the case of bad data can do a better * job of finding RFI in the good data. * @p input parameter. The @p strategy parameter can be the * same for different threads. * @param input The data to run the flagger on. * @param existingFlags Flags that indicate what data are bad. * @return A flag mask that identifies bad (RFI contaminated) data. * @since 3.0 */ FlagMask Run(const ImageSet& input, const FlagMask& existingFlags); private: Strategy(const std::string& filename, class AOFlagger* aoflagger); Strategy(const Strategy& sourceStrategy) = delete; Strategy& operator=(const Strategy& sourceStrategy) = delete; static Strategy makeFromString(const std::string& script, class AOFlagger* aoflagger); FlagMask run(const ImageSet& input, const FlagMask* existingFlags); std::unique_ptr _data; class AOFlagger* _aoflagger; }; /** @brief Statistics that can be collected online and saved to a measurement * set. * * It is useful to collect some statistics during flagging, because all data * goes through memory at highest resolution. This class contains the collected * statistics and some meta data required for collecting. It can be created with * @ref AOFlagger::MakeQualityStatistics(). Statistics can be added to it with * @ref CollectStatistics(), and saved to disk with * @ref WriteStatistics(). * * This class does not allow viewing or modifying statistics, it only contains * the most basic form to collect statistics during flagging and writing them in * the (well-defined) quality statistic tables format. These statistics can be * viewed interactively with the @c aoqplot tool. * * Collecting statistics is not as expensive as flagging, but still takes some * time, so it is recommended to use multiple threads for collecting as well. * This class is however not thread save, but it is okay to use different * QualityStatistics objects from different thread contexts. During * finalization, the different objects can be combined with the operator+=() * method, and then in full written to the measurement set. */ class QualityStatistics { public: friend class AOFlagger; /** Construct a QualityStatistics with null state. * * An object created by this constructor can only be assigned to. * @since Version 2.13 */ QualityStatistics(); /** @brief Copy the object. This is fast; only references are copied. */ QualityStatistics(const QualityStatistics& sourceQS); /** @brief Move construct the object. * @since Version 2.10 */ QualityStatistics(QualityStatistics&& sourceQS); /** @brief Destruct the object. Data is destroyed if no more references exist. */ ~QualityStatistics(); /** @brief Assign to this object. This is fast; only references are copied. */ QualityStatistics& operator=(const QualityStatistics& sourceQS); /** @brief Move-assign this object. This is fast; only references are moved. * @since Version 2.10 */ QualityStatistics& operator=(QualityStatistics&& sourceQS); /** @brief Combine the statistics from the given object with the statistics in * this object. * * This is a relative expensive operation, so should only be used scarsely. It * can be used to combine the results of different threads, as explained in * the class description. * * It is safe to combine quality statistics with different meta data (scan * time count, channel count, etc.). When using this object again during * collecting (see @ref CollectStatistics()), after combining it with another * object, it will still use the meta data it was initialized with. */ QualityStatistics& operator+=(const QualityStatistics& rhs); /** @brief Collect statistics from time-frequency images and masks. * * This will update the statistics in this object so that it * represents the combination of previous collected data and the newly * given data. * * This function can be called from different thread context, as long as each * thread uses its own QualityStatistics object. * See the @ref QualityStatistics class documentation for further * multithreading info. * @param imageSet Data to collect statistics from * @param rfiFlags Flags set by the automatic RFI detector * @param correlatorFlags Flags that were set prior to RFI detector, e.g. * because of a broken antenna or correlator hickup. * @param antenna1 Index of the first antenna involved in this baseline. * @param antenna2 Index of the second antenna involved in this baseline. * @since 3.0 */ void CollectStatistics(const ImageSet& imageSet, const FlagMask& rfiFlags, const FlagMask& correlatorFlags, size_t antenna1, size_t antenna2); /** @brief Write collected statistics in standard tables to a measurement set. * @param measurementSetPath Path to measurement set to which the statistics * will be written. * @since 3.0 */ void WriteStatistics(const std::string& measurementSetPath) const; private: QualityStatistics(const double* scanTimes, size_t nScans, const double* channelFrequencies, size_t nChannels, size_t nPolarizations, bool computeHistograms); std::unique_ptr _data; }; /** * @brief A base class which callers can inherit from to be able to receive * progress updates and error messages. * * A status listener should be thread safe when the Run() method is called in * parallel with the same StatusListener object. */ class StatusListener { public: /** * @brief Virtual destructor. */ virtual ~StatusListener() {} /** * @brief This virtual method is called when a new task is started. * * Typically, a client could display a message saying that the given task * 'description' is started. * @param description Description of the task, e.g. "SumThreshold". * @since 3.0 */ virtual void OnStartTask(const std::string& description) {} /** * @brief Called to update current progress. * * This can be used to display a progress bar if the strategy would take a lot * of time. * @param progress Current progress * @param maxProgress Progress that is required to finish the current task. */ virtual void OnProgress(size_t progress, size_t maxProgress) {} /** * @brief Called when detection has completely finished. * * This function will always be called exactly once on success. It is not * called when an exception occurred. @ref OnException() is called in that * case. */ virtual void OnFinish() {} /** * @brief Called when an exception occurs during execution of the strategy. * * This can occur when the Lua script throws an error. * @param thrownException The exception that was thrown. */ virtual void OnException(std::exception& thrownException) = 0; }; /** @brief Main class for access to the flagger functionality. * * Software using the flagger should first create an instance of the @ref * AOFlagger class, from which other actions can be initiated. * * ### Overview * * To flag a data set: * - Create the AOFlagger instance * - To use a stock strategy, call FindStrategyFile() * - Load and parse the strategy with LoadStrategyFile(), once for each thread * that will run. * - Create data buffers with MakeImageSet() * - For each correlated baseline or dish: * - - Fill the images with data from this correlated baseline or dish * - - Call Strategy::Run() with the created Strategy and ImageSet * - - Process the data that was returned in the FlagMask. * * Optionally, it is possible to assemble quality statistics that can be written * to the measurement set in the standard format that e.g. the @c aoqplot tool * can read. To do this: * - Create (once) a quality statistics object with MakeQualityStatistics(). * - After flagging a baseline, add it to the statistics object with * QualityStatistics::CollectStatistics(). * A "correlator mask" can be specified that describes which flags are not due * to RFI but caused by different things. * - When a full set is processed, store the statistics with WriteStatistics(). * * To flag multiple baselines, the Strategy and/or ImageSet objects can be * reused. * * ### Thread safety * * Each Strategy object runs in its own context, and will not perform any * unsynchronised writes to global variables. It is therefore safe to call * Strategy::Run() from different threads, as long as each thread uses its own * Strategy and ImageSet instances. QualityStatistics::CollectStatistics() is * also thread safe, as long as different QualityStatistics instances are * passed. For multi-threading, each thread should collect into its own * QualityStatistics object. When finished, these can be combined with * QualityStatistics::operator+=(). * * It is safe to create multiple AOFlagger instances, but not recommended. * * ### Data order * * A common problem for integrating the flagger, is that data are stored in a * different order: the time dimension * is often the direction with the slowest increasing indices. Because the * flagger needs one baseline at a time, this requires reordering the data. As * long as the data fits in memory, this reordering is quite straightforward. * When this is not the case, the data could be split into sub-bands and/or time * windows. Next, these parts can be passed to the flagger and recombined later * (if desired). * * To decide how to split, keep in mind that the flagger * works best when both a lot of channels and a lot of * timesteps are available. As an example: LOFAR splits into subbands of ~64 * channels, and the default processing with NDPPP loads as many timesteps as * possible in memory for flagging. Typically, this means at least a few hundred * of timesteps are processed at a time (with 1-3s per timestep), and this seems * to work well. * * The 'aoflagger' executable flags by default on the full measurement set. * For sets that are larger than memory, a mode is used in * which the data is reordered to disk before the actual flagging starts. It * turns out that this is much faster than reading each baseline directly from * the set, and it simultaneously produces the best flagging accuracy, so if * enough processing power is available to do so, this is another approach. */ class AOFlagger { public: /** @brief Create and initialize the flagger main class. */ AOFlagger() : _statusListener(nullptr) {} /** @brief Destructor. */ ~AOFlagger() {} /** @brief Create a new uninitialized @ref ImageSet with specified specs. * * The float values will not be initialized. * @param width Number of time steps in images * @param height Number of frequency channels in images * @param count Number of images in set (see class description * of @ref ImageSet for image order). * @return A new ImageSet. */ ImageSet MakeImageSet(size_t width, size_t height, size_t count) { return ImageSet(width, height, count); } /** @brief Create a new uninitialized @ref ImageSet with specified specs. * * The float values will not be initialized. * @param width Number of time steps in images * @param height Number of frequency channels in images * @param count Number of images in set (see class description * of @ref ImageSet for image order). * @param widthCapacity Allow for enlarging image to this size, @sa * ImageSet::ResizeWithoutReallocation() * @return A new ImageSet. * @since 2.6 */ ImageSet MakeImageSet(size_t width, size_t height, size_t count, size_t widthCapacity) { return ImageSet(width, height, count, widthCapacity); } /** @brief Create a new initialized @ref ImageSet with specified specs. * @param width Number of time steps in images * @param height Number of frequency channels in images * @param count Number of images in set (see class description * of @ref ImageSet for image order). * @param initialValue Initialize all pixels with this value. * @return A new ImageSet. */ ImageSet MakeImageSet(size_t width, size_t height, size_t count, float initialValue) { return ImageSet(width, height, count, initialValue); } /** @brief Create a new initialized @ref ImageSet with specified specs. * @param width Number of time steps in images * @param height Number of frequency channels in images * @param count Number of images in set (see class description * of @ref ImageSet for image order). * @param initialValue Initialize all pixels with this value. * @param widthCapacity Allow for enlarging image to this size, @sa * ImageSet::ResizeWithoutReallocation() * @return A new ImageSet. * @since 2.6 */ ImageSet MakeImageSet(size_t width, size_t height, size_t count, float initialValue, size_t widthCapacity) { return ImageSet(width, height, count, initialValue, widthCapacity); } /** @brief Create a new uninitialized @ref FlagMask with specified dimensions. * @param width Width of mask (number of timesteps) * @param height Height of mask (number of frequency channels) * @return A new FlagMask. */ FlagMask MakeFlagMask(size_t width, size_t height) { return FlagMask(width, height); } /** @brief Create a new initialized @ref FlagMask with specified dimensions. * @param width Width of mask (number of timesteps) * @param height Height of mask (number of frequency channels) * @param initialValue Value to initialize the mask to. * @return A new FlagMask. */ FlagMask MakeFlagMask(size_t width, size_t height, bool initialValue) { return FlagMask(width, height, initialValue); } /** @brief Find a Lua strategy for a specific telescope. * * The scenario name can be used to * distinguish different strategies for the same telescope, for example * to distinguish between different bands, different processing stages (e.g. * before or after averaging), different antennas (LOFAR HBA vs LBA), etc. * * This will search the data directory of the installation path of * aoflagger for a file named <Telescope_Name>-<scenario>.lua, or * <Telescope_Name>-default.lua in case scenario is empty. * * @param telescopeId Identifies the telescope to optimize the strategy for. * @param scenario A scenario name that should be searched for. * @returns Filename of strategy, or empty string if none found. * @since Version 3.0 */ std::string FindStrategyFile( enum TelescopeId telescopeId = TelescopeId::GENERIC_TELESCOPE, const std::string& scenario = ""); /** @brief Load a strategy from disk. * * The best way to create strategies is to use the @c rfigui tool. In case you * have optimized strategies for an unlisted telescope or for new scenarios, * please consider providing the file so I can add them to the repository. * * @param filename Full pathname to .lua strategy file. * @return The new @ref Strategy. * @since Version 3.0 */ Strategy LoadStrategyFile(const std::string& filename) { return Strategy(filename, this); } /** @brief Load a strategy from a string containing a Lua script. * * Similar to @ref LoadStrategyFile(). * * @param script String containing full Lua script. * @return The new @ref Strategy. * @since Version 3.1 */ Strategy LoadStrategyString(const std::string& script) { return Strategy::makeFromString(script, this); } /** * @brief Create a new object for collecting statistics. * @param scanTimes Array with times. The number of elements should match the * dimension of the time axis in calls to * QualityStatistics::CollectStatistics(). Each time is a MJD time in seconds. * @param nScans Number of elements in the @c scanTimes array. * @param channelFrequencies Frequency in Hz of each channel. The number of * elements should match the frequency axis in calls to * QualityStatistics::CollectStatistics(). * @param nChannels Number of elements in the @c channelFrequencies array. * @param nPolarizations Number of polarizations in the set (1, 2 or 4). * * See the QualityStatistics class description for info on multithreading * and/or combining statistics with different meta data. The meta data that is * passed to this method will be used for all calls to * QualityStatistics::CollectStatistics(). No histograms will be computed. */ QualityStatistics MakeQualityStatistics(const double* scanTimes, size_t nScans, const double* channelFrequencies, size_t nChannels, size_t nPolarizations); /** @brief Create a new object for collecting statistics, possibly with * histograms. * * See other overload of MakeQualityStatistics() for info. * @since Version 2.6 */ QualityStatistics MakeQualityStatistics( const double* scanTimes, size_t nScans, const double* channelFrequencies, size_t nChannels, size_t nPolarizations, bool computeHistograms); /** @brief Get the AOFlagger version number as a string. * @returns The version number, formatted like '1.2.3-subtitle', e.g. * '3.0-alpha'. * @since Version 2.6 */ static std::string GetVersionString(); /** @brief Get the AOFlagger version number separated in major, minor and * subminor fields. * @param major Most significant number of the version, e.g. '1' for version * '1.2.3'. This number is only incremented in major changes of the flagger. * @param minor Minor number of the version, e.g. '2' for version '1.2.3'. * This number is incremented for every public release. * @param subMinor Subminor number of the version, e.g. '3' for version * '1.2.3', or zero if the current version has no subminor number. This number * is incremented for internal releases or small bug fixes. * @since Version 2.6 */ static void GetVersion(short& major, short& minor, short& subMinor); /** @brief Get the date this version was released as a string. * @returns The version date formatted like "1982-05-08". * @since Version 2.6 */ static std::string GetVersionDate(); /** * @brief Set a handler for progress updates and exceptions. * * By default, exceptions will be reported to stderr and progress updates * will be ignored. If an application needs to handle either of these * themselves, they can override a @ref StatusListener that handles these * events and call this method to enable receiving the events. * This method is not thread safe. * @param statusListener The handler that will receive the status updates. * @since Version 2.7 */ void SetStatusListener(StatusListener* statusListener) { _statusListener = statusListener; } /** * Provide information about the antennas used in the data set. * This information is propagated to the Lua environment, * such that scripts can make choices based on the antenna. * It is not required to set this before flagging. */ void SetAntennaList(std::vector&& antennas) { _antennas = std::move(antennas); } const std::vector& AntennaList() const { return _antennas; } /** * Provide frequency information for the data set. * This information is propagated to the Lua environment, * such that scripts can make choices based on the antenna. * It is not required to set this before flagging. */ void SetBandList(std::vector&& bands) { _bands = std::move(bands); } const std::vector& BandList() const { return _bands; } void SetIntervalList(std::vector&& intervals) { _intervals = std::move(intervals); } const std::vector& IntervalList() const { return _intervals; } private: friend class Strategy; /** @brief It is not allowed to copy this class */ AOFlagger(const AOFlagger&) = delete; /** @brief It is not allowed to assign to this class */ void operator=(const AOFlagger&) = delete; StatusListener* _statusListener; std::vector _antennas; std::vector _bands; std::vector _intervals; }; } // namespace aoflagger #endif aoflagger-v3.4.0/interface/imageset.cpp0000644000175000017500000000751414507760372016605 0ustar olesoles#include "aoflagger.h" #include "structures.h" #include "../structures/image2d.h" #include namespace aoflagger { ImageSet::ImageSet() : _data(nullptr) {} ImageSet::ImageSet(size_t width, size_t height, size_t count) : _data(new ImageSetData(count)) { assertValidCount(count); for (size_t i = 0; i != count; ++i) _data->images[i] = Image2D::CreateUnsetImagePtr(width, height); } ImageSet::ImageSet(size_t width, size_t height, size_t count, float initialValue) : _data(new ImageSetData(count)) { assertValidCount(count); for (size_t i = 0; i != count; ++i) _data->images[i] = Image2D::CreateSetImagePtr(width, height, initialValue); } ImageSet::ImageSet(size_t width, size_t height, size_t count, size_t widthCapacity) : _data(new ImageSetData(count)) { assertValidCount(count); for (size_t i = 0; i != count; ++i) _data->images[i] = Image2D::CreateUnsetImagePtr(width, height, widthCapacity); } ImageSet::ImageSet(size_t width, size_t height, size_t count, float initialValue, size_t widthCapacity) : _data(new ImageSetData(count)) { assertValidCount(count); for (size_t i = 0; i != count; ++i) _data->images[i] = Image2D::CreateSetImagePtr(width, height, initialValue, widthCapacity); } ImageSet::ImageSet(const ImageSet& sourceImageSet) : _data(sourceImageSet._data != nullptr ? new ImageSetData(*sourceImageSet._data) : nullptr) {} ImageSet::ImageSet::ImageSet(aoflagger::ImageSet&& sourceImageSet) : _data(std::move(sourceImageSet._data)) {} ImageSet::~ImageSet() {} ImageSet& ImageSet::operator=(const ImageSet& sourceImageSet) { if (sourceImageSet._data == nullptr) { _data.reset(); } else if (_data == nullptr) { _data.reset(new ImageSetData(*sourceImageSet._data)); } else { *_data = *sourceImageSet._data; } return *this; } ImageSet& ImageSet::operator=(ImageSet&& sourceImageSet) { std::swap(_data, sourceImageSet._data); return *this; } void ImageSet::assertValidCount(size_t count) { if (count != 1 && count != 2 && count != 4 && count != 8) throw std::runtime_error( "Invalid count specified when creating image set for aoflagger; should " "be 1, 2, 4 or 8."); } float* ImageSet::ImageBuffer(size_t imageIndex) { return _data->images[imageIndex]->Data(); } const float* ImageSet::ImageBuffer(size_t imageIndex) const { return _data->images[imageIndex]->Data(); } size_t ImageSet::Width() const { return _data->images[0]->Width(); } size_t ImageSet::Height() const { return _data->images[0]->Height(); } size_t ImageSet::ImageCount() const { return _data->images.size(); } size_t ImageSet::HorizontalStride() const { return _data->images[0]->Stride(); } void ImageSet::Set(float newValue) { for (const Image2DPtr& image : _data->images) { image->SetAll(newValue); } } void ImageSet::ResizeWithoutReallocation(size_t newWidth) const { for (const Image2DPtr& image : _data->images) { image->ResizeWithoutReallocation(newWidth); } } void ImageSet::SetAntennas(size_t antenna1, size_t antenna2) { _data->hasAntennas = true; _data->antenna1 = antenna1; _data->antenna2 = antenna2; } bool ImageSet::HasAntennas() const { return _data->hasAntennas; } size_t ImageSet::Antenna1() const { return _data->antenna1; } size_t ImageSet::Antenna2() const { return _data->antenna2; } void ImageSet::SetInterval(size_t index) { _data->interval = index; _data->hasInterval = true; } bool ImageSet::HasInterval() const { return _data->hasInterval; } size_t ImageSet::Interval() const { return _data->interval; } void ImageSet::SetBand(size_t index) { _data->band = index; _data->hasBand = true; } bool ImageSet::HasBand() const { return _data->hasBand; } size_t ImageSet::Band() const { return _data->band; } } // namespace aoflagger aoflagger-v3.4.0/ref/0000755000175000017500000000000014516225226013102 5ustar olesolesaoflagger-v3.4.0/ref/reffileexception.h0000644000175000017500000000056314507760372016620 0ustar olesoles#ifndef AO_REFFILEEXCEPTION_H #define AO_REFFILEEXCEPTION_H #include namespace AOTools { class RefFileException : public std::runtime_error { public: RefFileException() : std::runtime_error("Exception in reference file") {} explicit RefFileException(const std::string& message) : std::runtime_error(message) {} }; } // namespace AOTools #endif aoflagger-v3.4.0/ref/reffile.h0000644000175000017500000000244514507760372014702 0ustar olesoles#ifndef AO_REFFILE_H #define AO_REFFILE_H #include #include #include #include "reffileentry.h" #include "reffileexception.h" namespace AOTools { class RefFile { public: typedef std::vector::const_iterator const_iterator; RefFile() {} explicit RefFile(const std::string& refFilePath) { Read(refFilePath); } void Read(const std::string& refFilePath) { _entries.clear(); _refFilePath = refFilePath; std::ifstream file(_refFilePath.c_str()); RefFileEntry entry; while (entry.read(file)) { _entries.push_back(entry); } } void Write(std::ostream& destination) const { for (const_iterator i = begin(); i != end(); ++i) i->write(destination); } size_t Count() const { return _entries.size(); } const RefFileEntry& operator[](const size_t index) const { return _entries[index]; } void Add(const RefFileEntry& entry) { _entries.push_back(entry); } const_iterator begin() const { return _entries.begin(); } const_iterator end() const { return _entries.end(); } private: RefFile(const RefFile&) // don't allow copy {} void operator=(const RefFile&) // don't allow assignment {} std::vector _entries; std::string _refFilePath; }; } // namespace AOTools #endif // AO_REFFILE_H aoflagger-v3.4.0/ref/reffileentry.h0000644000175000017500000000542614507760372015766 0ustar olesoles#ifndef AO_REFFILEENTRY_H #define AO_REFFILEENTRY_H #include #include #include #include "reffileexception.h" namespace AOTools { class RefFileEntry { public: friend class RefFile; RefFileEntry() : _size(0) {} RefFileEntry(const RefFileEntry& source) : _path(source._path), _frequency(source._frequency), _size(source._size), _node(source._node) {} RefFileEntry& operator=(const RefFileEntry& source) { _path = source._path; _frequency = source._frequency; _size = source._size; _node = source._node; return *this; } const std::string& Path() const { return _path; } const std::string& Frequency() const { return _frequency; } unsigned Size() const { return _size; } const std::string& Node() const { return _node; } void SetPath(const std::string& path) { _path = path; } private: std::string _path; std::string _frequency; unsigned _size; std::string _node; bool read(std::istream& stream) { std::string line; do { if (!stream.good()) return false; std::getline(stream, line); if (stream.fail()) return false; if (stream.bad()) throw RefFileException("Error in IO"); } while (ignoreLine(line)); assignFromString(line); return true; } void write(std::ostream& stream) const { stream << _path << ' ' << _frequency << ' ' << _size << ' ' << _node << "\n"; } void assignFromString(const std::string& line) { std::string::const_iterator i = line.begin(); if (!getNextToken(_path, i, line.end())) throw RefFileException("Expecting a path"); if (!getNextToken(_frequency, i, line.end())) throw RefFileException("Expecting frequency description"); std::string sizeString; if (!getNextToken(sizeString, i, line.end())) throw RefFileException("Expecting a size"); _size = atoi(sizeString.c_str()); if (!getNextToken(_node, i, line.end())) throw RefFileException("Expecting a node"); } static bool ignoreLine(const std::string& line) { for (std::string::const_iterator i = line.begin(); i != line.end(); ++i) { if (*i == '#') return true; if (!ignorable(*i)) return false; } return true; } static bool ignorable(std::string::value_type ch) { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'; } static bool getNextToken(std::string& dest, std::string::const_iterator& ptr, const std::string::const_iterator end) { std::ostringstream token; while (ptr != end && ignorable(*ptr)) ++ptr; if (ptr == end) return false; while (ptr != end && !ignorable(*ptr)) { token << *ptr; ++ptr; } dest = token.str(); return dest.size() != 0; } }; } // namespace AOTools #endif // AO_REFFILEENTRY_H aoflagger-v3.4.0/CMakeVersionInfo.txt0000644000175000017500000000042414507760372016237 0ustar olesolesset(AOFLAGGER_VERSION_STR 3.4) set(AOFLAGGER_VERSION_MAJOR 3) set(AOFLAGGER_VERSION_MINOR 4) set(AOFLAGGER_VERSION_SUBMINOR 0) set(AOFLAGGER_VERSION_DATE_STR 2023-10-06) # SOVERSION stored in the library -- increase # when making ABI changes set(AOFLAGGER_VERSION_SO 2) aoflagger-v3.4.0/aoqplot/0000755000175000017500000000000014516225226014005 5ustar olesolesaoflagger-v3.4.0/aoqplot/summarypage.h0000644000175000017500000001416114507760372016521 0ustar olesoles#ifndef GUI_QUALITY__SUMMARYPAGE_H #define GUI_QUALITY__SUMMARYPAGE_H #include #include #include #include #include #include #include "../quality/statisticscollection.h" #include "../quality/statisticsderivator.h" #include "plotsheet.h" #include #ifndef HAVE_EXP10 #define exp10(x) exp((2.3025850929940456840179914546844) * (x)) #endif class SummaryPageController : public AOQPageController { public: void Attach(class SummaryPage* page) { _page = page; } void SetStatistics(const StatisticsCollection* statCollection, const std::vector&) final override; void CloseStatistics() final override; bool HasStatistics() const { return _statCollection != nullptr; } private: void updateText(); void addText(std::ostringstream& str, DefaultStatistics& statistics) { unsigned long totalRFICount = 0; unsigned long totalCount = 0; const unsigned polarizationCount = statistics.PolarizationCount(); std::vector stdDev(polarizationCount), dStdDev(polarizationCount), variance(polarizationCount), dVariance(polarizationCount); for (unsigned p = 0; p < polarizationCount; ++p) { totalRFICount += statistics.rfiCount[p]; totalCount += statistics.rfiCount[p] + statistics.count[p]; variance[p] = StatisticsDerivator::VarianceAmplitude( statistics.count[p], statistics.sum[p], statistics.sumP2[p]); dVariance[p] = StatisticsDerivator::VarianceAmplitude( statistics.dCount[p], statistics.dSum[p], statistics.dSumP2[p]); stdDev[p] = StatisticsDerivator::StandardDeviationAmplitude( statistics.count[p], statistics.sum[p], statistics.sumP2[p]); dStdDev[p] = StatisticsDerivator::StandardDeviationAmplitude( statistics.dCount[p], statistics.dSum[p], statistics.dSumP2[p]); } double rfiRatioValue = round(((double)totalRFICount * 10000.0 / (double)totalCount)) * 0.01; double countExp = floor(log10(totalCount)); double countMantissa = totalCount / exp10(countExp); str << "Sample count = " << round(countMantissa * 100.0) * 0.01 << " x 10^" << countExp << "\n"; str << "Total RFI ratio = " << rfiRatioValue << "%\n"; str << "Standard deviation amplitude = "; addValues(&stdDev[0], polarizationCount, str); str << " Jy\nDifferential stddev amplitude = "; addValues(&dStdDev[0], polarizationCount, str); str << " Jy\nVariance amplitude = "; addValues(&variance[0], polarizationCount, str); str << " Jy\nDifferential variance amplitude = "; addValues(&dVariance[0], polarizationCount, str); str << " Jy\n"; } void addBaselineAverages(std::ostringstream& str) { const BaselineStatisticsMap& map = _statCollection->BaselineStatistics(); std::vector> list = map.BaselineList(); std::vector totalStdDev(map.PolarizationCount()), totalSNR(map.PolarizationCount()); std::vector count(map.PolarizationCount()); for (size_t p = 0; p < map.PolarizationCount(); ++p) { totalStdDev[p] = 0.0; totalSNR[p] = 0.0; count[p] = 0; } for (std::vector>::const_iterator i = list.begin(); i != list.end(); ++i) { unsigned a1 = i->first, a2 = i->second; if (a1 != a2) { const DefaultStatistics& stat = map.GetStatistics(a1, a2); for (size_t p = 0; p < map.PolarizationCount(); ++p) { const double thisStdDev = StatisticsDerivator::GetStatisticAmplitude( QualityTablesFormatter::StandardDeviationStatistic, stat, p), thisSNR = StatisticsDerivator::GetStatisticAmplitude( QualityTablesFormatter::SignalToNoiseStatistic, stat, p); if (std::isfinite(thisStdDev) && std::isfinite(thisSNR)) { totalStdDev[p] += thisStdDev; totalSNR[p] += thisSNR; ++count[p]; } } } } for (size_t p = 0; p < map.PolarizationCount(); ++p) { totalStdDev[p] /= (double)count[p]; totalSNR[p] /= (double)count[p]; } str << "Average standard deviation = "; addValues(&totalStdDev[0], map.PolarizationCount(), str); str << " Jy\nAverage signal to noise ratio = "; addValues(&totalSNR[0], map.PolarizationCount(), str); str << " Jy\n(calculated with BaselineMean/BaselineDStdDev)\n"; } void addValues(const double* values, unsigned polarizationCount, std::ostringstream& s) { s << '[' << values[0]; for (unsigned p = 1; p < polarizationCount; ++p) { s << ", " << values[p]; } s << ']'; } const StatisticsCollection* _statCollection; class SummaryPage* _page; }; class SummaryPage : public PlotSheet { public: explicit SummaryPage(SummaryPageController* controller) : _controller(controller) { add(_textView); _textView.show(); _controller->Attach(this); } void SetText(const std::string& str) { Glib::RefPtr buffer = _textView.get_buffer(); buffer->set_text(str); } private: Gtk::TextView _textView; SummaryPageController* _controller; }; inline void SummaryPageController::SetStatistics( const StatisticsCollection* statCollection, const std::vector&) { _statCollection = statCollection; updateText(); } inline void SummaryPageController::CloseStatistics() { _statCollection = nullptr; _page->SetText("No open measurement set"); } inline void SummaryPageController::updateText() { DefaultStatistics statistics(_statCollection->PolarizationCount()); std::ostringstream str; _statCollection->GetGlobalCrossBaselineStatistics(statistics); str << "Statistics of cross-correlated baselines\n"; addText(str, statistics); str << "\nAverages over cross-correlated baselines\n"; addBaselineAverages(str); _statCollection->GetGlobalAutoBaselineStatistics(statistics); str << "\nStatistics of auto-correlated baselines\n"; addText(str, statistics); _page->SetText(str.str()); } #endif aoflagger-v3.4.0/aoqplot/histogrampage.cpp0000644000175000017500000002460014507760372017353 0ustar olesoles#include "histogrampage.h" #include #include "controllers/histogrampagecontroller.h" #include "../plot/plotpropertieswindow.h" #include "datawindow.h" HistogramPage::HistogramPage(HistogramPageController* controller) : _controller(controller), _expander("Side bar"), _histogramTypeFrame("Histogram"), _totalHistogramButton("Total"), _rfiHistogramButton("RFI"), _notRFIHistogramButton("Not RFI"), _xxPolarizationButton("XX"), _xyPolarizationButton("XY"), _yxPolarizationButton("YX"), _yyPolarizationButton("YY"), _sumPolarizationButton("Sum"), _fitFrame("Fitting"), _fitButton("Fit"), _subtractFitButton("Subtract"), _fitLogarithmicButton("Log fit"), _fitAutoRangeButton("Auto range"), _functionFrame("Function"), _nsButton("N(S)"), _dndsButton("dN(S)/dS"), _deltaSEntry(), _staircaseFunctionButton("Staircase"), _normalizeButton("Normalize"), _plotPropertiesButton("Properties"), _dataExportButton("Data"), _slopeFrame("Slope"), _drawSlopeButton("Draw"), _drawSlope2Button("Draw2"), _slopeAutoRangeButton("Auto range"), _plotPropertiesWindow(nullptr) { _histogramTypeBox.pack_start(_totalHistogramButton, Gtk::PACK_SHRINK); _totalHistogramButton.set_active(true); _totalHistogramButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _histogramTypeBox.pack_start(_rfiHistogramButton, Gtk::PACK_SHRINK); _rfiHistogramButton.set_active(false); _rfiHistogramButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _histogramTypeBox.pack_start(_notRFIHistogramButton, Gtk::PACK_SHRINK); _notRFIHistogramButton.set_active(false); _notRFIHistogramButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _histogramTypeFrame.add(_histogramTypeBox); _sideBox.pack_start(_histogramTypeFrame, Gtk::PACK_SHRINK); _polarizationBox.pack_start(_xxPolarizationButton, Gtk::PACK_SHRINK); _xxPolarizationButton.set_active(false); _xxPolarizationButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _polarizationBox.pack_start(_xyPolarizationButton, Gtk::PACK_SHRINK); _xyPolarizationButton.set_active(false); _xyPolarizationButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _polarizationBox.pack_start(_yxPolarizationButton, Gtk::PACK_SHRINK); _yxPolarizationButton.set_active(false); _yxPolarizationButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _polarizationBox.pack_start(_yyPolarizationButton, Gtk::PACK_SHRINK); _yyPolarizationButton.set_active(false); _yyPolarizationButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _polarizationBox.pack_start(_sumPolarizationButton, Gtk::PACK_SHRINK); _sumPolarizationButton.set_active(true); _sumPolarizationButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _polarizationFrame.add(_polarizationBox); _sideBox.pack_start(_polarizationFrame, Gtk::PACK_SHRINK); _fitBox.pack_start(_fitButton, Gtk::PACK_SHRINK); _fitButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _fitBox.pack_start(_subtractFitButton, Gtk::PACK_SHRINK); _subtractFitButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _fitBox.pack_start(_fitLogarithmicButton, Gtk::PACK_SHRINK); _fitLogarithmicButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _fitBox.pack_start(_fitAutoRangeButton, Gtk::PACK_SHRINK); _fitAutoRangeButton.set_active(true); _fitAutoRangeButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::onAutoRangeClicked)); _fitBox.pack_start(_fitStartEntry, Gtk::PACK_SHRINK); _fitStartEntry.set_sensitive(false); _fitStartEntry.signal_activate().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _fitBox.pack_start(_fitEndEntry, Gtk::PACK_SHRINK); _fitEndEntry.set_sensitive(false); _fitEndEntry.signal_activate().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _fitBox.pack_start(_fitTextView, Gtk::PACK_SHRINK); _fitFrame.add(_fitBox); _sideBox.pack_start(_fitFrame, Gtk::PACK_SHRINK); Gtk::RadioButtonGroup group; _functionBox.pack_start(_nsButton, Gtk::PACK_SHRINK); _nsButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _nsButton.set_group(group); _functionBox.pack_start(_dndsButton, Gtk::PACK_SHRINK); _dndsButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _dndsButton.set_group(group); _nsButton.set_active(true); _functionBox.pack_start(_deltaSEntry, Gtk::PACK_SHRINK); _deltaSEntry.set_text("2"); _deltaSEntry.signal_activate().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _functionBox.pack_start(_staircaseFunctionButton, Gtk::PACK_SHRINK); _staircaseFunctionButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _functionBox.pack_start(_normalizeButton, Gtk::PACK_SHRINK); _normalizeButton.set_active(true); _normalizeButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _functionFrame.add(_functionBox); _sideBox.pack_start(_functionFrame, Gtk::PACK_SHRINK); _plotPropertiesButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::onPlotPropertiesClicked)); _sideBox.pack_start(_plotPropertiesButton, Gtk::PACK_SHRINK); _dataExportButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::onDataExportClicked)); _sideBox.pack_start(_dataExportButton, Gtk::PACK_SHRINK); _slopeBox.pack_start(_slopeTextView, Gtk::PACK_SHRINK); _drawSlopeButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _slopeBox.pack_start(_drawSlopeButton, Gtk::PACK_SHRINK); _drawSlope2Button.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _slopeBox.pack_start(_drawSlope2Button, Gtk::PACK_SHRINK); _slopeBox.pack_start(_slopeAutoRangeButton, Gtk::PACK_SHRINK); _slopeAutoRangeButton.set_active(true); _slopeAutoRangeButton.signal_clicked().connect( sigc::mem_fun(*this, &HistogramPage::onSlopeAutoRangeClicked)); _slopeBox.pack_start(_slopeStartEntry, Gtk::PACK_SHRINK); _slopeStartEntry.set_sensitive(false); _slopeStartEntry.signal_activate().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _slopeBox.pack_start(_slopeEndEntry, Gtk::PACK_SHRINK); _slopeEndEntry.set_sensitive(false); _slopeEndEntry.signal_activate().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _slopeBox.pack_start(_slopeRFIRatio, Gtk::PACK_SHRINK); _slopeRFIRatio.set_text("1.0"); _slopeRFIRatio.signal_activate().connect( sigc::mem_fun(*this, &HistogramPage::updatePlot)); _slopeFrame.add(_slopeBox); _sideBox.pack_start(_slopeFrame, Gtk::PACK_SHRINK); _expander.add(_sideBox); pack_start(_expander, Gtk::PACK_SHRINK); _plotWidget.SetPlot(_controller->Plot()); pack_start(_plotWidget, Gtk::PACK_EXPAND_WIDGET); show_all_children(); _dataWindow = new DataWindow(); _controller->Attach(this); } HistogramPage::~HistogramPage() { delete _plotPropertiesWindow; delete _dataWindow; } void HistogramPage::updatePlot() { _controller->SetDrawXX(_xxPolarizationButton.get_active()); _controller->SetDrawXY(_xyPolarizationButton.get_active()); _controller->SetDrawYX(_yxPolarizationButton.get_active()); _controller->SetDrawYY(_yyPolarizationButton.get_active()); _controller->SetDrawSum(_sumPolarizationButton.get_active()); _controller->SetAutomaticFitRange(_fitAutoRangeButton.get_active()); _controller->SetFitStart(atof(_fitStartEntry.get_text().c_str())); _controller->SetFitEnd(atof(_fitEndEntry.get_text().c_str())); _controller->SetFitLogarithmic(_fitLogarithmicButton.get_active()); _controller->SetAutomaticSlopeRange(_slopeAutoRangeButton.get_active()); _controller->SetSlopeStart(atof(_slopeStartEntry.get_text().c_str())); _controller->SetSlopeEnd(atof(_slopeEndEntry.get_text().c_str())); _controller->SetSlopeRFIRatio(atof(_slopeRFIRatio.get_text().c_str())); double deltaS = atof(_deltaSEntry.get_text().c_str()); if (deltaS <= 1.0001) deltaS = 1.0001; _controller->SetDeltaS(deltaS); _controller->SetDrawTotal(_totalHistogramButton.get_active()); _controller->SetDrawFit(_fitButton.get_active()); _controller->SetDrawSubtractedFit(_subtractFitButton.get_active()); _controller->SetDrawSlope(_drawSlopeButton.get_active()); _controller->SetDrawSlope2(_drawSlope2Button.get_active()); _controller->SetDrawRFI(_rfiHistogramButton.get_active()); _controller->SetDrawNonRFI(_notRFIHistogramButton.get_active()); _controller->SetDerivative(_dndsButton.get_active()); _controller->SetStaircase(_staircaseFunctionButton.get_active()); _controller->SetNormalize(_normalizeButton.get_active()); _controller->SetDeltaS(atof(_deltaSEntry.get_text().c_str())); } void HistogramPage::onPlotPropertiesClicked() { if (_plotPropertiesWindow == nullptr) { _plotPropertiesWindow = new PlotPropertiesWindow(_controller->Plot(), "Plot properties"); _plotPropertiesWindow->OnChangesApplied = std::bind(&HistogramPage::Redraw, this); } _plotPropertiesWindow->show(); _plotPropertiesWindow->raise(); } void HistogramPage::onDataExportClicked() { _dataWindow->show(); _dataWindow->raise(); updateDataWindow(); } void HistogramPage::SetSlopeFrame(const std::string& str) { _slopeTextView.get_buffer()->set_text(str); if (_slopeAutoRangeButton.get_active()) { double minRange = _controller->SlopeStart(), maxRange = _controller->SlopeEnd(); std::stringstream minRangeStr, maxRangeStr; minRangeStr << minRange; maxRangeStr << maxRange; _slopeStartEntry.set_text(minRangeStr.str()); _slopeEndEntry.set_text(maxRangeStr.str()); } if (_fitAutoRangeButton.get_active()) { std::stringstream minRangeStr, maxRangeStr; minRangeStr << _controller->FitStart(); maxRangeStr << _controller->FitEnd(); _fitStartEntry.set_text(minRangeStr.str()); _fitEndEntry.set_text(maxRangeStr.str()); } } void HistogramPage::updateDataWindow() { if (_dataWindow->get_visible()) _dataWindow->SetData(_controller->Plot()); } aoflagger-v3.4.0/aoqplot/aoqplotwindow.cpp0000644000175000017500000001545214507760372017435 0ustar olesoles#include "aoqplotwindow.h" #include "controllers/antennapagecontroller.h" #include "controllers/aoqplotcontroller.h" #include "controllers/baselinepagecontroller.h" #include "controllers/blengthpagecontroller.h" #include "controllers/frequencypagecontroller.h" #include "controllers/histogrampagecontroller.h" #include "controllers/tfpagecontroller.h" #include "controllers/timepagecontroller.h" #include #include #include #include "../structures/msmetadata.h" #include "../quality/histogramtablesformatter.h" #include "../quality/histogramcollection.h" #include "../quality/statisticscollection.h" #include "baselineplotpage.h" #include "blengthplotpage.h" #include "frequencyplotpage.h" #include "histogrampage.h" #include "summarypage.h" #include "timefrequencyplotpage.h" AOQPlotWindow::AOQPlotWindow(AOQPlotController* controller) : _controller(controller), _activeSheetIndex(-1), _pageMenuButton("Sheet"), _baselineMI(_pageGroup, "Baselines"), _antennaeMI(_pageGroup, "Antennae"), _bLengthMI(_pageGroup, "Baseline lengths"), _timeMI(_pageGroup, "Time"), _frequencyMI(_pageGroup, "Frequency"), _timeFrequencyMI(_pageGroup, "Time-frequency"), _summaryMI(_pageGroup, "Summary"), _histogramMI(_pageGroup, "Histograms") { set_default_icon_name("aoqplot"); _toolbar.append(_pageMenuButton); _pageMenuButton.set_menu(_pageMenu); _pageMenu.append(_baselineMI); _baselineMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.append(_antennaeMI); _antennaeMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.append(_bLengthMI); _bLengthMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.append(_timeMI); _timeMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.append(_frequencyMI); _frequencyMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.append(_timeFrequencyMI); _timeFrequencyMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.append(_summaryMI); _summaryMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.append(_histogramMI); _histogramMI.signal_toggled().connect( sigc::mem_fun(*this, &AOQPlotWindow::onChangeSheet)); _pageMenu.show_all_children(); _vBox.pack_start(_toolbar, Gtk::PACK_SHRINK); _vBox.pack_end(_statusBar, Gtk::PACK_SHRINK); _statusBar.push( "Quality plot util is ready. Author: André Offringa " "(offringa@gmail.com)"); add(_vBox); _openOptionsWindow.SignalOpen().connect( sigc::mem_fun(*this, &AOQPlotWindow::onOpenOptionsSelected)); signal_hide().connect(sigc::mem_fun(*this, &AOQPlotWindow::onHide)); _controller->Attach(this); } void AOQPlotWindow::Open(const std::vector& files) { show_all(); _openOptionsWindow.ShowForFile(files); } void AOQPlotWindow::onOpenOptionsSelected(const std::vector& files, bool downsampleTime, bool downsampleFreq, size_t timeCount, size_t freqCount, bool correctHistograms) { _controller->ReadStatistics(files, downsampleTime, downsampleFreq, timeCount, freqCount, correctHistograms); _activeSheetIndex = -1; onChangeSheet(); show(); } void AOQPlotWindow::onStatusChange(const std::string& newStatus) { _statusBar.pop(); _statusBar.push(newStatus); } void AOQPlotWindow::onChangeSheet() { int selectedSheet = -1; if (_baselineMI.get_active()) selectedSheet = 0; else if (_antennaeMI.get_active()) selectedSheet = 1; else if (_bLengthMI.get_active()) selectedSheet = 2; else if (_timeMI.get_active()) selectedSheet = 3; else if (_frequencyMI.get_active()) selectedSheet = 4; else if (_timeFrequencyMI.get_active()) selectedSheet = 5; else if (_summaryMI.get_active()) selectedSheet = 6; else if (_histogramMI.get_active()) selectedSheet = 7; if (selectedSheet != _activeSheetIndex) { switch (selectedSheet) { case 0: _pageController.reset(new BaselinePageController()); _activeSheet.reset(new BaselinePlotPage( static_cast(_pageController.get()))); SetStatus("Baseline statistics"); break; case 1: _pageController.reset(new AntennaePageController()); _activeSheet.reset(new TwoDimensionalPlotPage( static_cast(_pageController.get()))); SetStatus("Antennae statistics"); break; case 2: _pageController.reset(new BLengthPageController()); _activeSheet.reset(new BLengthPlotPage( static_cast(_pageController.get()))); SetStatus("Baseline length statistics"); break; case 3: _pageController.reset(new TimePageController()); _activeSheet.reset(new TwoDimensionalPlotPage( static_cast(_pageController.get()))); SetStatus("Time statistics"); break; case 4: _pageController.reset(new FrequencyPageController()); _activeSheet.reset(new FrequencyPlotPage( static_cast(_pageController.get()))); SetStatus("Frequency statistics"); break; case 5: _pageController.reset(new TFPageController()); _activeSheet.reset(new TimeFrequencyPlotPage( static_cast(_pageController.get()))); SetStatus("Time-frequency statistics"); break; case 6: _pageController.reset(new SummaryPageController()); _activeSheet.reset(new SummaryPage( static_cast(_pageController.get()))); SetStatus("Summary"); break; case 7: _pageController.reset(new HistogramPageController()); _activeSheet.reset(new HistogramPage( static_cast(_pageController.get()))); SetStatus("Histograms"); break; } _activeSheetIndex = selectedSheet; _controller->Initialize(_pageController.get(), selectedSheet != 5); _activeSheet->SignalStatusChange().connect( sigc::mem_fun(*this, &AOQPlotWindow::onStatusChange)); _activeSheet->InitializeToolbar(_toolbar); _toolbar.show_all(); _vBox.pack_start(*_activeSheet); _activeSheet->show_all(); } } void AOQPlotWindow::ShowError(const std::string& message) { Gtk::MessageDialog dialog(*this, message, false, Gtk::MESSAGE_ERROR); dialog.run(); } aoflagger-v3.4.0/aoqplot/timefrequencyplotpage.h0000644000175000017500000000050214507760372020575 0ustar olesoles#ifndef GUI_QUALITY__TIMEFREQUENCYPLOTPAGE_H #define GUI_QUALITY__TIMEFREQUENCYPLOTPAGE_H #include "grayscaleplotpage.h" class TimeFrequencyPlotPage : public GrayScalePlotPage { public: explicit TimeFrequencyPlotPage(class TFPageController* controller); private: void onMouseMoved(double x, double y); }; #endif aoflagger-v3.4.0/aoqplot/baselineplotpage.cpp0000644000175000017500000000254114507760372020037 0ustar olesoles#include #include "baselineplotpage.h" #include "controllers/baselinepagecontroller.h" BaselinePlotPage::BaselinePlotPage(BaselinePageController* controller) : GrayScalePlotPage(controller), _controller(controller) { grayScaleWidget().OnMouseMovedEvent().connect( sigc::mem_fun(*this, &BaselinePlotPage::onMouseMoved)); } BaselinePlotPage::~BaselinePlotPage() {} void BaselinePlotPage::onMouseMoved(double x, double y) { const MaskedHeatMap& map = static_cast(grayScaleWidget().Plot()); size_t image_x; size_t image_y; if (map.UnitToImage(x, y, image_x, image_y)) { const std::string antenna1Name = _controller->AntennaName(x); const std::string antenna2Name = _controller->AntennaName(y); const QualityTablesFormatter::StatisticKind kind = getSelectedStatisticKind(); const std::string& kindName = QualityTablesFormatter::KindToName(kind); std::stringstream text; const size_t stride = static_cast(grayScaleWidget().Plot()).Image().Stride(); text << "Correlation " << antenna1Name << " (" << image_x << ") x " << antenna2Name << " (" << image_y << "), " << kindName << " = " << static_cast(grayScaleWidget().Plot()) .Image() .Data()[image_y * stride + image_x]; _signalStatusChange(text.str()); } } aoflagger-v3.4.0/aoqplot/grayscaleplotpage.h0000644000175000017500000000733014507760372017675 0ustar olesoles#ifndef GUI_QUALITY__GRAYSCALEPLOTPAGE_H #define GUI_QUALITY__GRAYSCALEPLOTPAGE_H #include #include #include #include #include "../plot/plotwidget.h" #include "../quality/qualitytablesformatter.h" #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "plotsheet.h" class GrayScalePlotPage : public PlotSheet { public: explicit GrayScalePlotPage(class HeatMapPageController* controller); virtual ~GrayScalePlotPage(); void InitializeToolbar(Gtk::Toolbar& toolbar) override final; bool NormalizeXAxis() const { return _normalizeXAxisButton.get_active(); } bool NormalizeYAxis() const { return _normalizeYAxisButton.get_active(); } void Redraw(); protected: QualityTablesFormatter::StatisticKind getSelectedStatisticKind() const { return _selectStatisticKind; } void updateImage(); PlotWidget& grayScaleWidget() { return _imageWidget; } private: void initStatisticKinds(Gtk::Toolbar& toolbar); void initPolarizations(Gtk::Toolbar& toolbar); void initPhaseButtons(Gtk::Toolbar& toolbar); void initPlotOptions(Gtk::Toolbar& toolbar); aocommon::PolarizationEnum getSelectedPolarization() const; enum TimeFrequencyData::ComplexRepresentation getSelectedPhase() const; void onSelectCount() { _selectStatisticKind = QualityTablesFormatter::CountStatistic; updateImage(); } void onSelectMean() { _selectStatisticKind = QualityTablesFormatter::MeanStatistic; updateImage(); } void onSelectStdDev() { _selectStatisticKind = QualityTablesFormatter::StandardDeviationStatistic; updateImage(); } void onSelectDCount() { _selectStatisticKind = QualityTablesFormatter::DCountStatistic; updateImage(); } void onSelectDMean() { _selectStatisticKind = QualityTablesFormatter::DMeanStatistic; updateImage(); } void onSelectDStdDev() { _selectStatisticKind = QualityTablesFormatter::DStandardDeviationStatistic; updateImage(); } void onSelectRFIPercentage() { _selectStatisticKind = QualityTablesFormatter::RFIPercentageStatistic; updateImage(); } void onSelectSNR() { _selectStatisticKind = QualityTablesFormatter::SignalToNoiseStatistic; updateImage(); } void onPropertiesClicked(); void onSelectMinMaxRange(); void onSelectWinsorizedRange(); void onSelectSpecifiedRange(); void onLogarithmicScaleClicked(); void onNormalizeAxesButtonClicked() { updateImage(); } void onChangeNormMethod() { if (_normalizeYAxisButton.get_active()) updateImage(); } class HeatMapPageController* _controller; Gtk::SeparatorToolItem _separator1, _separator2, _separator3, _separator4, _separator5, _separator6; Gtk::RadioButtonGroup _statisticGroup; Gtk::RadioToolButton _countButton, _meanButton, _stdDevButton, _dMeanButton, _dStdDevButton, _rfiPercentageButton; Gtk::RadioButtonGroup _polGroup; Gtk::RadioToolButton _polPPButton, _polPQButton, _polQPButton, _polQQButton, _polIButton; Gtk::RadioButtonGroup _phaseGroup; Gtk::RadioToolButton _amplitudePhaseButton, _phasePhaseButton, _realPhaseButton, _imaginaryPhaseButton; Gtk::RadioButtonGroup _rangeGroup; Gtk::RadioToolButton _rangeMinMaxButton, _rangeWinsorizedButton, _rangeSpecified; Gtk::ToggleToolButton _logarithmicScaleButton, _normalizeXAxisButton, _normalizeYAxisButton; Gtk::RadioButtonGroup _rangeTypeGroup; Gtk::RadioToolButton _meanNormButton, _winsorNormButton, _medianNormButton; Gtk::ToolButton _plotPropertiesButton; QualityTablesFormatter::StatisticKind _selectStatisticKind; PlotWidget _imageWidget; class ImagePropertiesWindow* _imagePropertiesWindow; }; #endif aoflagger-v3.4.0/aoqplot/twodimensionalplotpage.cpp0000644000175000017500000002454214507760372021316 0ustar olesoles#include #include #include "datawindow.h" #include "twodimensionalplotpage.h" #include "../quality/statisticscollection.h" #include "../quality/statisticsderivator.h" #include "../plot/plotpropertieswindow.h" #include TwoDimensionalPlotPage::TwoDimensionalPlotPage( AOQPlotPageController* controller) : _controller(controller), _countButton("#"), _meanButton("μ"), _stdDevButton("σ"), _varianceButton("σ²"), _dCountButton("Δ#"), _dMeanButton("Δμ"), _dStdDevButton("Δσ"), _rfiPercentageButton("%"), _polPPButton("pp"), _polPQButton("pq"), _polQPButton("qp"), _polQQButton("qq"), _polIButton("I"), _amplitudeButton("A"), _phaseButton("Ï•"), _realButton("r"), _imaginaryButton("i"), _logarithmicButton("Log"), _zeroAxisButton("0"), _plotPropertiesButton("P"), _dataExportButton("D"), _plotPropertiesWindow(nullptr), _dataWindow(new DataWindow()), _customButtonsCreated(false) { _plotWidget.SetPlot(_controller->Plot()); pack_start(_plotWidget, Gtk::PACK_EXPAND_WIDGET); show_all_children(); _controller->Attach(this); } TwoDimensionalPlotPage::~TwoDimensionalPlotPage() {} void TwoDimensionalPlotPage::updatePlotConfig() { _controller->Plot().SetIncludeZeroYAxis(_zeroAxisButton.get_active()); _controller->Plot().YAxis().SetLogarithmic(_logarithmicButton.get_active()); _plotWidget.Update(); } std::vector TwoDimensionalPlotPage::GetSelectedKinds() const { std::vector kinds; if (_countButton.get_active()) kinds.emplace_back(QualityTablesFormatter::CountStatistic); if (_meanButton.get_active()) kinds.emplace_back(QualityTablesFormatter::MeanStatistic); if (_stdDevButton.get_active()) kinds.emplace_back(QualityTablesFormatter::StandardDeviationStatistic); if (_varianceButton.get_active()) kinds.emplace_back(QualityTablesFormatter::VarianceStatistic); if (_dCountButton.get_active()) kinds.emplace_back(QualityTablesFormatter::DCountStatistic); if (_dMeanButton.get_active()) kinds.emplace_back(QualityTablesFormatter::DMeanStatistic); if (_dStdDevButton.get_active()) kinds.emplace_back(QualityTablesFormatter::DStandardDeviationStatistic); if (_rfiPercentageButton.get_active()) kinds.emplace_back(QualityTablesFormatter::RFIPercentageStatistic); return kinds; } std::set TwoDimensionalPlotPage::GetSelectedPolarizations() const { std::set pols; if (_polPPButton.get_active()) pols.insert(AOQPlotPageController::PolPP); if (_polPQButton.get_active()) pols.insert(AOQPlotPageController::PolPQ); if (_polQPButton.get_active()) pols.insert(AOQPlotPageController::PolQP); if (_polQQButton.get_active()) pols.insert(AOQPlotPageController::PolQQ); if (_polIButton.get_active()) pols.insert(AOQPlotPageController::PolI); return pols; } std::set TwoDimensionalPlotPage::GetSelectedPhases() const { std::set phases; if (_amplitudeButton.get_active()) phases.insert(AOQPlotPageController::AmplitudePhaseType); if (_phaseButton.get_active()) phases.insert(AOQPlotPageController::PhasePhaseType); if (_realButton.get_active()) phases.insert(AOQPlotPageController::RealPhaseType); if (_imaginaryButton.get_active()) phases.insert(AOQPlotPageController::ImaginaryPhaseType); return phases; } void TwoDimensionalPlotPage::InitializeToolbar(Gtk::Toolbar& toolbar) { if (Gtk::IconTheme::get_default()->has_icon("aoflagger")) { toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS); toolbar.set_icon_size(Gtk::ICON_SIZE_LARGE_TOOLBAR); } else { toolbar.set_toolbar_style(Gtk::TOOLBAR_TEXT); toolbar.set_icon_size(Gtk::ICON_SIZE_SMALL_TOOLBAR); } initStatisticKindButtons(toolbar); initPolarizationButtons(toolbar); initPhaseButtons(toolbar); initPlotButtons(toolbar); if (!_customButtonsCreated) { addCustomPlotButtons(toolbar); _customButtonsCreated = true; } } void TwoDimensionalPlotPage::initStatisticKindButtons(Gtk::Toolbar& toolbar) { toolbar.append(_separator1); _countButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _countButton.set_tooltip_text("Visibility count"); toolbar.append(_countButton); _meanButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _meanButton.set_tooltip_text("Mean value"); toolbar.append(_meanButton); _stdDevButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _stdDevButton.set_active(true); _stdDevButton.set_tooltip_text("Standard deviation"); toolbar.append(_stdDevButton); _varianceButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); toolbar.append(_varianceButton); //_dCountButton.signal_clicked().connect(sigc::mem_fun(*_controller, //&AOQPlotPageController::UpdatePlot)); toolbar.append(_dCountButton); _dMeanButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _dMeanButton.set_tooltip_text( "Frequency-differential (difference between channels) mean value"); toolbar.append(_dMeanButton); _dStdDevButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _dStdDevButton.set_tooltip_text( "Frequency-differential (difference between channels) standard " "deviation"); toolbar.append(_dStdDevButton); _rfiPercentageButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _rfiPercentageButton.set_tooltip_text("Flagged percentage"); toolbar.append(_rfiPercentageButton); } void TwoDimensionalPlotPage::initPolarizationButtons(Gtk::Toolbar& toolbar) { toolbar.append(_separator2); _polPPButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _polPPButton.set_active(false); _polPPButton.set_icon_name("showpp"); _polPPButton.set_tooltip_text( "Display statistics for the PP polarization. Depending on the " "polarization configuration of the measurement set, this will show XX or " "RR."); toolbar.append(_polPPButton); _polPQButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _polPQButton.set_active(false); _polPQButton.set_icon_name("showpq"); _polPQButton.set_tooltip_text( "Display statistics for the PQ polarization. Depending on the " "polarization configuration of the measurement set, this will show XY or " "RL."); toolbar.append(_polPQButton); _polQPButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _polQPButton.set_active(false); _polQPButton.set_icon_name("showqp"); _polPQButton.set_tooltip_text( "Display statistics for the QP polarization. Depending on the " "polarization configuration of the measurement set, this will show YX or " "LR."); toolbar.append(_polQPButton); _polQQButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _polQQButton.set_active(false); _polQQButton.set_icon_name("showqq"); _polQQButton.set_tooltip_text( "Display statistics for the QQ polarization. Depending on the " "polarization configuration of the measurement set, this will show YY or " "LL."); toolbar.append(_polQQButton); _polIButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _polIButton.set_active(true); _polIButton.set_tooltip_text("Display statistics for QQ + PP."); toolbar.append(_polIButton); } void TwoDimensionalPlotPage::initPhaseButtons(Gtk::Toolbar& toolbar) { toolbar.append(_separator3); _amplitudeButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _amplitudeButton.set_active(true); _amplitudeButton.set_tooltip_text("Amplitude"); toolbar.append(_amplitudeButton); _phaseButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _phaseButton.set_tooltip_text("Phase"); toolbar.append(_phaseButton); _realButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _realButton.set_tooltip_text("Real value"); toolbar.append(_realButton); _imaginaryButton.signal_clicked().connect( sigc::mem_fun(*_controller, &AOQPlotPageController::UpdatePlot)); _imaginaryButton.set_tooltip_text("Imaginary value"); toolbar.append(_imaginaryButton); } void TwoDimensionalPlotPage::initPlotButtons(Gtk::Toolbar& toolbar) { toolbar.append(_separator4); _logarithmicButton.signal_clicked().connect( sigc::mem_fun(*this, &TwoDimensionalPlotPage::onLogarithmicClicked)); toolbar.append(_logarithmicButton); _zeroAxisButton.signal_clicked().connect( sigc::mem_fun(*this, &TwoDimensionalPlotPage::updatePlotConfig)); _zeroAxisButton.set_active(true); toolbar.append(_zeroAxisButton); _controller->Plot().SetIncludeZeroYAxis(true); _plotPropertiesButton.signal_clicked().connect( sigc::mem_fun(*this, &TwoDimensionalPlotPage::onPlotPropertiesClicked)); toolbar.append(_plotPropertiesButton); _dataExportButton.signal_clicked().connect( sigc::mem_fun(*this, &TwoDimensionalPlotPage::onDataExportClicked)); toolbar.append(_dataExportButton); } void TwoDimensionalPlotPage::onPlotPropertiesClicked() { if (_plotPropertiesWindow == nullptr) { _plotPropertiesWindow.reset( new PlotPropertiesWindow(_controller->Plot(), "Plot properties")); _plotPropertiesWindow->OnChangesApplied = std::bind(&AOQPlotPageController::UpdatePlot, _controller); } _plotPropertiesWindow->show(); _plotPropertiesWindow->raise(); } void TwoDimensionalPlotPage::updateDataWindow() { if (_dataWindow->get_visible()) _dataWindow->SetData(_controller->Plot()); } void TwoDimensionalPlotPage::onDataExportClicked() { _dataWindow->show(); _dataWindow->raise(); updateDataWindow(); } void TwoDimensionalPlotPage::Redraw() { _plotWidget.Update(); if (_dataWindow->get_visible()) { updateDataWindow(); } } aoflagger-v3.4.0/aoqplot/datawindow.cpp0000644000175000017500000000312714507760372016663 0ustar olesoles#include "datawindow.h" #include "../plot/xyplot.h" #include #include void DataWindow::SetData(const XYPlot& plot) { _plot = &plot; int selectedIndex = _comboBox.get_active_row_number(); if (selectedIndex < 0) selectedIndex = 0; _comboListStore->clear(); for (size_t i = 0; i < plot.PointSetCount(); ++i) { std::stringstream str; str << (i + 1) << ". " << plot.GetPointSet(i).Label(); const Gtk::TreeModel::Row row = *_comboListStore->append(); row[_comboColumnRecord._comboListNameColumn] = str.str(); } if (selectedIndex < (int)plot.PointSetCount()) _comboBox.set_active(selectedIndex); else if (plot.PointSetCount() > 0) _comboBox.set_active(0); onComboChange(); } void DataWindow::onComboChange() { const int active = _comboBox.get_active_row_number(); if (active >= 0) loadData(active); else loadData(_plot->PointSetCount()); } void DataWindow::loadData(size_t plotSetIndex) { std::stringstream _dataStream; _dataStream << std::setprecision(14); if (_plot->PointSetCount() > plotSetIndex) { const XYPointSet& pointSet = _plot->GetPointSet(plotSetIndex); const size_t valueCount = pointSet.Size(); for (size_t i = 0; i < valueCount; ++i) { const double x = pointSet.GetX(i), y = pointSet.GetY(i); if (_plot->XAxis().Type() == AxisType::kText) { const std::string& label = _plot->XAxis().TickLabels()[i].second; _dataStream << i << '\t' << label << '\t' << y << '\n'; } else { _dataStream << i << '\t' << x << '\t' << y << '\n'; } } } SetData(_dataStream.str()); } aoflagger-v3.4.0/aoqplot/frequencyplotpage.h0000644000175000017500000000167214507760372017727 0ustar olesoles#ifndef GUI_QUALITY__FREQUENCYPLOTPAGE_H #define GUI_QUALITY__FREQUENCYPLOTPAGE_H #include "twodimensionalplotpage.h" #include "controllers/frequencypagecontroller.h" #include "../quality/statisticscollection.h" #include "../quality/statisticsderivator.h" class FrequencyPlotPage : public TwoDimensionalPlotPage { public: explicit FrequencyPlotPage(FrequencyPageController* controller) : TwoDimensionalPlotPage(controller), _controller(controller), _ftButton("FT") {} void addCustomPlotButtons(Gtk::Toolbar& container) override final { _ftButton.signal_clicked().connect( sigc::mem_fun(*this, &FrequencyPlotPage::onFTButtonClicked)); container.append(_ftButton); _ftButton.show(); } private: void onFTButtonClicked() { _controller->SetPerformFT(_ftButton.get_active()); _controller->UpdatePlot(); } FrequencyPageController* _controller; Gtk::ToggleToolButton _ftButton; }; #endif aoflagger-v3.4.0/aoqplot/datawindow.h0000644000175000017500000000303414507760372016325 0ustar olesoles#ifndef GUI_QUALITY__DATA_WINDOW_H #define GUI_QUALITY__DATA_WINDOW_H #include #include #include #include #include #include #include class XYPlot; class DataWindow : public Gtk::Window { public: DataWindow() { _box.pack_start(_comboBox, Gtk::PACK_SHRINK); _comboListStore = Gtk::ListStore::create(_comboColumnRecord); _comboBox.set_model(_comboListStore); _comboBox.pack_start(_comboColumnRecord._comboListNameColumn); _comboBox.signal_changed().connect( sigc::mem_fun(*this, &DataWindow::onComboChange)); _comboBox.show(); _scrolledWindow.add(_textView); _textView.show(); _box.pack_end(_scrolledWindow); _scrolledWindow.show(); add(_box); _box.show(); set_default_size(300, 400); } ~DataWindow() {} void SetData(const std::string& data) { _textView.get_buffer()->set_text(data); } void SetData(const XYPlot& plot); private: DataWindow(const DataWindow& dataWindow) = delete; void onComboChange(); void loadData(size_t plotSetIndex); class ComboColumnRecord : public Gtk::TreeModel::ColumnRecord { public: ComboColumnRecord() { add(_comboListNameColumn); } Gtk::TreeModelColumn _comboListNameColumn; } _comboColumnRecord; Gtk::VBox _box; Gtk::ComboBox _comboBox; Glib::RefPtr _comboListStore; Gtk::ScrolledWindow _scrolledWindow; Gtk::TextView _textView; const XYPlot* _plot; }; #endif aoflagger-v3.4.0/aoqplot/plotsheet.h0000644000175000017500000000071714507760372016200 0ustar olesoles#ifndef PLOT_SHEET_H #define PLOT_SHEET_H #include "../structures/antennainfo.h" #include #include #include #include class PlotSheet : public Gtk::HBox { public: sigc::signal SignalStatusChange() { return _signalStatusChange; } virtual void InitializeToolbar(Gtk::Toolbar& toolbar) {} protected: sigc::signal _signalStatusChange; }; #endif aoflagger-v3.4.0/aoqplot/twodimensionalplotpage.h0000644000175000017500000000427114507760372020760 0ustar olesoles#ifndef GUI_QUALITY__2DPLOTPAGE_H #define GUI_QUALITY__2DPLOTPAGE_H #include #include "controllers/aoqplotpagecontroller.h" #include "../quality/qualitytablesformatter.h" #include "../plot/plotwidget.h" #include "../plot/xyplot.h" #include "plotsheet.h" #include #include #include #include #include class TwoDimensionalPlotPage : public PlotSheet { public: explicit TwoDimensionalPlotPage(AOQPlotPageController* _controller); virtual ~TwoDimensionalPlotPage(); void InitializeToolbar(Gtk::Toolbar& toolbar) override final; std::vector GetSelectedKinds() const; std::set GetSelectedPolarizations() const; std::set GetSelectedPhases() const; void Redraw(); protected: virtual void addCustomPlotButtons(Gtk::Toolbar& container) {} private: void updatePlotConfig(); void updateDataWindow(); void initStatisticKindButtons(Gtk::Toolbar& toolbar); void initPolarizationButtons(Gtk::Toolbar& toolbar); void initPhaseButtons(Gtk::Toolbar& toolbar); void initPlotButtons(Gtk::Toolbar& toolbar); void onLogarithmicClicked() { _zeroAxisButton.set_sensitive(!_logarithmicButton.get_active()); updatePlotConfig(); } void onPlotPropertiesClicked(); void onDataExportClicked(); AOQPlotPageController* _controller; Gtk::SeparatorToolItem _separator1, _separator2, _separator3, _separator4; Gtk::ToggleToolButton _countButton, _meanButton, _stdDevButton, _varianceButton, _dCountButton, _dMeanButton, _dStdDevButton, _rfiPercentageButton; Gtk::ToggleToolButton _polPPButton, _polPQButton, _polQPButton, _polQQButton, _polIButton; Gtk::ToggleToolButton _amplitudeButton, _phaseButton, _realButton, _imaginaryButton; Gtk::ToggleToolButton _logarithmicButton, _zeroAxisButton; Gtk::ToolButton _plotPropertiesButton, _dataExportButton; PlotWidget _plotWidget; std::unique_ptr _plotPropertiesWindow; std::unique_ptr _dataWindow; bool _customButtonsCreated; }; #endif aoflagger-v3.4.0/aoqplot/grayscaleplotpage.cpp0000644000175000017500000002474714507760372020243 0ustar olesoles#include #include #include "controllers/heatmappagecontroller.h" #include "grayscaleplotpage.h" #include "../rfigui/imagepropertieswindow.h" GrayScalePlotPage::GrayScalePlotPage(HeatMapPageController* controller) : _controller(controller), _countButton(_statisticGroup, "#"), _meanButton(_statisticGroup, "μ"), _stdDevButton(_statisticGroup, "σ"), _dMeanButton(_statisticGroup, "Δμ"), _dStdDevButton(_statisticGroup, "Δσ"), _rfiPercentageButton(_statisticGroup, "%"), _polPPButton(_polGroup, "pp"), _polPQButton(_polGroup, "pq"), _polQPButton(_polGroup, "qp"), _polQQButton(_polGroup, "qq"), _polIButton(_polGroup, "I"), _amplitudePhaseButton(_phaseGroup, "A"), _phasePhaseButton(_phaseGroup, "Ï•"), _realPhaseButton(_phaseGroup, "r"), _imaginaryPhaseButton(_phaseGroup, "i"), _rangeMinMaxButton(_rangeGroup, "Min to max"), _rangeWinsorizedButton(_rangeGroup, "Winsorized"), _rangeSpecified(_rangeGroup, "Specified"), _logarithmicScaleButton("Logarithmic"), _normalizeXAxisButton("Normalize X"), _normalizeYAxisButton("Normalize Y"), _meanNormButton(_rangeTypeGroup, "Mean"), _winsorNormButton(_rangeTypeGroup, "Winsor"), _medianNormButton(_rangeTypeGroup, "Median"), _plotPropertiesButton("Properties..."), _selectStatisticKind(QualityTablesFormatter::StandardDeviationStatistic), _imageWidget(), _imagePropertiesWindow(nullptr) { _imageWidget.SetPlot(controller->Plot()); _imageWidget.set_size_request(300, 300); pack_start(_imageWidget); controller->Attach(this); } GrayScalePlotPage::~GrayScalePlotPage() { delete _imagePropertiesWindow; } void GrayScalePlotPage::InitializeToolbar(Gtk::Toolbar& toolbar) { if (Gtk::IconTheme::get_default()->has_icon("aoflagger")) { toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS); toolbar.set_icon_size(Gtk::ICON_SIZE_LARGE_TOOLBAR); } else { toolbar.set_toolbar_style(Gtk::TOOLBAR_TEXT); toolbar.set_icon_size(Gtk::ICON_SIZE_SMALL_TOOLBAR); } initStatisticKinds(toolbar); initPolarizations(toolbar); initPhaseButtons(toolbar); initPlotOptions(toolbar); } void GrayScalePlotPage::initStatisticKinds(Gtk::Toolbar& toolbar) { toolbar.append(_separator1); _countButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectCount)); _countButton.set_tooltip_text("Visibility count"); toolbar.append(_countButton); _meanButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectMean)); _meanButton.set_tooltip_text("Mean value"); toolbar.append(_meanButton); _stdDevButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectStdDev)); _stdDevButton.set_tooltip_text("Standard deviation"); toolbar.append(_stdDevButton); _dMeanButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectDMean)); _dMeanButton.set_tooltip_text( "Frequency-differential (difference between channels) mean value"); toolbar.append(_dMeanButton); _dStdDevButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectDStdDev)); _dStdDevButton.set_tooltip_text( "Frequency-differential (difference between channels) standard " "deviation"); toolbar.append(_dStdDevButton); _rfiPercentageButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectRFIPercentage)); _rfiPercentageButton.set_tooltip_text("Flagged percentage"); toolbar.append(_rfiPercentageButton); _stdDevButton.set_active(); } void GrayScalePlotPage::initPolarizations(Gtk::Toolbar& toolbar) { toolbar.append(_separator2); _polPPButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _polPPButton.set_icon_name("showpp"); _polPPButton.set_tooltip_text( "Display statistics for the PP polarization. Depending on the " "polarization configuration of the measurement set, this will show XX or " "RR."); toolbar.append(_polPPButton); _polPQButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _polPQButton.set_icon_name("showpq"); _polPQButton.set_tooltip_text( "Display statistics for the PQ polarization. Depending on the " "polarization configuration of the measurement set, this will show XY or " "RL."); toolbar.append(_polPQButton); _polQPButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _polQPButton.set_icon_name("showqp"); _polQPButton.set_tooltip_text( "Display statistics for the QP polarization. Depending on the " "polarization configuration of the measurement set, this will show YX or " "LR."); toolbar.append(_polQPButton); _polQQButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _polQQButton.set_icon_name("showqq"); _polQQButton.set_tooltip_text( "Display statistics for the QQ polarization. Depending on the " "polarization configuration of the measurement set, this will show YY or " "LL."); toolbar.append(_polQQButton); _polIButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _polIButton.set_tooltip_text("Stokes I polarization"); toolbar.append(_polIButton); _polIButton.set_active(); } void GrayScalePlotPage::initPhaseButtons(Gtk::Toolbar& toolbar) { toolbar.append(_separator3); _amplitudePhaseButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _amplitudePhaseButton.set_tooltip_text("Amplitude"); toolbar.append(_amplitudePhaseButton); _phasePhaseButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _phasePhaseButton.set_tooltip_text("Phase"); toolbar.append(_phasePhaseButton); _realPhaseButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _realPhaseButton.set_tooltip_text("Real value"); toolbar.append(_realPhaseButton); _imaginaryPhaseButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::updateImage)); _imaginaryPhaseButton.set_tooltip_text("Imaginary value"); toolbar.append(_imaginaryPhaseButton); _amplitudePhaseButton.set_active(); } void GrayScalePlotPage::initPlotOptions(Gtk::Toolbar& toolbar) { toolbar.append(_separator4); _rangeMinMaxButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectMinMaxRange)); toolbar.append(_rangeMinMaxButton); _rangeWinsorizedButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectWinsorizedRange)); toolbar.append(_rangeWinsorizedButton); _rangeSpecified.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onSelectSpecifiedRange)); toolbar.append(_rangeSpecified); toolbar.append(_separator5); _logarithmicScaleButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onLogarithmicScaleClicked)); toolbar.append(_logarithmicScaleButton); _logarithmicScaleButton.set_active(true); _normalizeXAxisButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onNormalizeAxesButtonClicked)); toolbar.append(_normalizeXAxisButton); _normalizeYAxisButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onNormalizeAxesButtonClicked)); toolbar.append(_normalizeYAxisButton); toolbar.append(_separator6); _meanNormButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onChangeNormMethod)); toolbar.append(_meanNormButton); _winsorNormButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onChangeNormMethod)); toolbar.append(_winsorNormButton); _medianNormButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onChangeNormMethod)); toolbar.append(_medianNormButton); _plotPropertiesButton.signal_clicked().connect( sigc::mem_fun(*this, &GrayScalePlotPage::onPropertiesClicked)); toolbar.append(_plotPropertiesButton); } void GrayScalePlotPage::updateImage() { _controller->SetKind(getSelectedStatisticKind()); _controller->SetPolarization(getSelectedPolarization()); _controller->SetPhase(getSelectedPhase()); if (_meanNormButton.get_active()) _controller->SetNormalization(HeatMapPageController::Mean); else if (_winsorNormButton.get_active()) _controller->SetNormalization(HeatMapPageController::Winsorized); else // _medianNormButton _controller->SetNormalization(HeatMapPageController::Median); _controller->UpdateImage(); } aocommon::PolarizationEnum GrayScalePlotPage::getSelectedPolarization() const { if (_polPPButton.get_active()) return aocommon::Polarization::XX; else if (_polPQButton.get_active()) return aocommon::Polarization::XY; else if (_polQPButton.get_active()) return aocommon::Polarization::YX; else if (_polQQButton.get_active()) return aocommon::Polarization::YY; else return aocommon::Polarization::StokesI; } enum TimeFrequencyData::ComplexRepresentation GrayScalePlotPage::getSelectedPhase() const { if (_amplitudePhaseButton.get_active()) return TimeFrequencyData::AmplitudePart; else if (_phasePhaseButton.get_active()) return TimeFrequencyData::PhasePart; else if (_realPhaseButton.get_active()) return TimeFrequencyData::RealPart; else if (_imaginaryPhaseButton.get_active()) return TimeFrequencyData::ImaginaryPart; else return TimeFrequencyData::AmplitudePart; } void GrayScalePlotPage::onPropertiesClicked() { if (_imagePropertiesWindow == nullptr) _imagePropertiesWindow = new ImagePropertiesWindow(_imageWidget, "Plotting properties"); _imagePropertiesWindow->show(); _imagePropertiesWindow->raise(); } void GrayScalePlotPage::onSelectMinMaxRange() { _controller->Plot().SetZRange(FullRange()); _imageWidget.Update(); } void GrayScalePlotPage::onSelectWinsorizedRange() { _controller->Plot().SetZRange(WinsorizedRange()); _imageWidget.Update(); } void GrayScalePlotPage::onSelectSpecifiedRange() { RangeConfiguration range = _controller->Plot().ZRange(); range.minimum = RangeLimit::Extreme; range.maximum = RangeLimit::Extreme; _controller->Plot().SetZRange(range); _imageWidget.Update(); } void GrayScalePlotPage::onLogarithmicScaleClicked() { _controller->Plot().SetLogZScale(_logarithmicScaleButton.get_active()); _imageWidget.Update(); } void GrayScalePlotPage::Redraw() { _imageWidget.Update(); } aoflagger-v3.4.0/aoqplot/openoptionswindow.h0000644000175000017500000000514514507760372017776 0ustar olesoles#ifndef GUI_QUALITY__OPEN_OPTIONS_WINDOW_H #define GUI_QUALITY__OPEN_OPTIONS_WINDOW_H #include #include #include #include #include #include #include class OpenOptionsWindow : public Gtk::Window { public: OpenOptionsWindow() : _downsampleTimeButton("Lower time resolution (faster plots)"), _downsampleFreqButton("Lower frequency resolution (faster plots)"), _correctHistograms("Correct histograms for frequence response"), _cancelButton("_Cancel", true), _openButton("_Open", true) { _timeBox.pack_start(_downsampleTimeButton); _downsampleTimeButton.set_active(true); _timeBox.pack_start(_timeDownsampleEntry); _timeDownsampleEntry.set_text("1000"); _box.pack_start(_timeBox); _freqBox.pack_start(_downsampleFreqButton); _downsampleFreqButton.set_active(true); _freqBox.pack_start(_freqDownsampleEntry); _freqDownsampleEntry.set_text("1000"); _box.pack_start(_freqBox); _box.pack_start(_correctHistograms); _buttonBox.pack_start(_cancelButton); _buttonBox.pack_start(_openButton); _openButton.signal_clicked().connect( sigc::mem_fun(*this, &OpenOptionsWindow::onOpen)); _box.pack_start(_buttonBox); add(_box); _box.show_all(); } ~OpenOptionsWindow() {} void ShowForFile(const std::vector& files) { _files = files; present(); } void ShowForFile(const std::string& filename) { _files.clear(); _files.push_back(filename); present(); } sigc::signal&, bool, bool, size_t, size_t, bool>& SignalOpen() { return _signalOpen; } private: void onOpen() { hide(); size_t timeRes = atol(_timeDownsampleEntry.get_text().c_str()); size_t freqRes = atol(_freqDownsampleEntry.get_text().c_str()); _signalOpen.emit(_files, _downsampleTimeButton.get_active(), _downsampleFreqButton.get_active(), timeRes, freqRes, _correctHistograms.get_active()); _files.clear(); } Gtk::VBox _box; Gtk::HBox _timeBox; Gtk::CheckButton _downsampleTimeButton; Gtk::Entry _timeDownsampleEntry; Gtk::HBox _freqBox; Gtk::CheckButton _downsampleFreqButton; Gtk::Entry _freqDownsampleEntry; Gtk::CheckButton _correctHistograms; Gtk::ButtonBox _buttonBox; Gtk::Button _cancelButton, _openButton; sigc::signal&, bool, bool, size_t, size_t, bool> _signalOpen; std::vector _files; }; #endif aoflagger-v3.4.0/aoqplot/aoqplotwindow.h0000644000175000017500000000432114507760372017073 0ustar olesoles#ifndef AOQPLOT_WINDOW_H #define AOQPLOT_WINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../quality/qualitytablesformatter.h" #include "plotsheet.h" #include "openoptionswindow.h" #include "../structures/antennainfo.h" #include "controllers/aoqpagecontroller.h" class AOQPlotWindow : public Gtk::Window { public: explicit AOQPlotWindow(class AOQPlotController* controller); void Open(const std::vector& files); void Open(const std::string& file) { std::vector files(1); files[0] = file; Open(files); } void SetStatus(const std::string& newStatus) { onStatusChange(newStatus); } void ShowError(const std::string& message); void SetShowHistograms(bool show) { _histogramMI.set_sensitive(show); } private: void onOpenOptionsSelected(const std::vector& files, bool downsampleTime, bool downsampleFreq, size_t timeSize, size_t freqSize, bool correctHistograms); void close(); void readDistributedObservation(const std::string& filename, bool correctHistograms); void readMetaInfoFromMS(const std::string& filename); void readAndCombine(const std::string& filename); void onHide() { // Gtk::Application::quit(); } void onStatusChange(const std::string& newStatus); void onChangeSheet(); class AOQPlotController* _controller; int _activeSheetIndex; Gtk::Toolbar _toolbar; Gtk::MenuToolButton _pageMenuButton; Gtk::Menu _pageMenu; Gtk::RadioButtonGroup _pageGroup, _statisticsGroup; Gtk::RadioMenuItem _baselineMI, _antennaeMI, _bLengthMI, _timeMI, _frequencyMI, _timeFrequencyMI, _summaryMI, _histogramMI; Gtk::VBox _vBox; Gtk::Statusbar _statusBar; std::unique_ptr _pageController; std::unique_ptr _activeSheet; OpenOptionsWindow _openOptionsWindow; }; #endif aoflagger-v3.4.0/aoqplot/timefrequencyplotpage.cpp0000644000175000017500000000160714507760372021137 0ustar olesoles#include "timefrequencyplotpage.h" #include "controllers/tfpagecontroller.h" TimeFrequencyPlotPage::TimeFrequencyPlotPage(TFPageController* controller) : GrayScalePlotPage(controller) { grayScaleWidget().OnMouseMovedEvent().connect( sigc::mem_fun(*this, &TimeFrequencyPlotPage::onMouseMoved)); } void TimeFrequencyPlotPage::onMouseMoved(double x, double y) { std::stringstream text; const QualityTablesFormatter::StatisticKind kind = getSelectedStatisticKind(); const std::string& kindName = QualityTablesFormatter::KindToName(kind); const MaskedHeatMap& map = static_cast(grayScaleWidget().Plot()); size_t image_x; size_t image_y; if (map.UnitToImage(x, y, image_x, image_y)) { text << kindName << " = " << map.GetImage2D()->Value(image_x, image_y) << " (" << image_x << ", " << image_y << ")"; } _signalStatusChange(text.str()); } aoflagger-v3.4.0/aoqplot/histogrampage.h0000644000175000017500000000524314507760372017022 0ustar olesoles#ifndef GUI_QUALITY__HISTOGRAMPAGE_H #define GUI_QUALITY__HISTOGRAMPAGE_H #include #include #include #include #include #include #include #include #include #include "../plot/plotwidget.h" #include "plotsheet.h" class HistogramPage : public PlotSheet { public: explicit HistogramPage(class HistogramPageController* controller); ~HistogramPage(); void updatePlot(); void Redraw() { _plotWidget.Update(); } void SetSlopeFrame(const std::string& str); void SetFitText(const std::string& str) { _fitTextView.get_buffer()->set_text(str); } private: void onPlotPropertiesClicked(); void onDataExportClicked(); void updateSlopeFrame(const class LogHistogram& histogram); std::string SlopeText(std::stringstream& str, const LogHistogram& histogram, bool updateRange); void updateDataWindow(); void onAutoRangeClicked() { bool autoRange = _fitAutoRangeButton.get_active(); _fitStartEntry.set_sensitive(!autoRange); _fitEndEntry.set_sensitive(!autoRange); if (autoRange) updatePlot(); } void onSlopeAutoRangeClicked() { bool autoRange = _slopeAutoRangeButton.get_active(); _slopeStartEntry.set_sensitive(!autoRange); _slopeEndEntry.set_sensitive(!autoRange); if (autoRange) updatePlot(); } class HistogramPageController* _controller; Gtk::Expander _expander; Gtk::VBox _sideBox; Gtk::Frame _histogramTypeFrame; Gtk::VBox _histogramTypeBox; Gtk::CheckButton _totalHistogramButton, _rfiHistogramButton, _notRFIHistogramButton; Gtk::Frame _polarizationFrame; Gtk::VBox _polarizationBox; Gtk::CheckButton _xxPolarizationButton, _xyPolarizationButton, _yxPolarizationButton, _yyPolarizationButton, _sumPolarizationButton; Gtk::Frame _fitFrame; Gtk::VBox _fitBox; Gtk::CheckButton _fitButton, _subtractFitButton, _fitLogarithmicButton, _fitAutoRangeButton; Gtk::Entry _fitStartEntry, _fitEndEntry; Gtk::TextView _fitTextView; Gtk::Frame _functionFrame; Gtk::VBox _functionBox; Gtk::RadioButton _nsButton, _dndsButton; Gtk::Entry _deltaSEntry; Gtk::CheckButton _staircaseFunctionButton, _normalizeButton; Gtk::Button _plotPropertiesButton, _dataExportButton; Gtk::Frame _slopeFrame; Gtk::VBox _slopeBox; Gtk::TextView _slopeTextView; Gtk::CheckButton _drawSlopeButton, _drawSlope2Button; Gtk::CheckButton _slopeAutoRangeButton; Gtk::Entry _slopeStartEntry, _slopeEndEntry, _slopeRFIRatio; PlotWidget _plotWidget; class PlotPropertiesWindow* _plotPropertiesWindow; class DataWindow* _dataWindow; }; #endif aoflagger-v3.4.0/aoqplot/blengthplotpage.h0000644000175000017500000000206714507760372017350 0ustar olesoles#ifndef GUI_QUALITY__BLENGTHPLOTPAGE_H #define GUI_QUALITY__BLENGTHPLOTPAGE_H #include "twodimensionalplotpage.h" #include "../structures/msmetadata.h" #include "controllers/blengthpagecontroller.h" class BLengthPlotPage final : public TwoDimensionalPlotPage { public: explicit BLengthPlotPage(BLengthPageController* controller) : TwoDimensionalPlotPage(controller), _controller(controller), _includeAutoCorrelationsButton("Auto-correlations") {} protected: void addCustomPlotButtons(Gtk::Toolbar& container) override { _includeAutoCorrelationsButton.signal_clicked().connect( sigc::mem_fun(*this, &BLengthPlotPage::onAutoCorrelationsClicked)); container.append(_includeAutoCorrelationsButton); _includeAutoCorrelationsButton.show(); } private: void onAutoCorrelationsClicked() { _controller->SetIncludeAutoCorrelations( _includeAutoCorrelationsButton.get_active()); _controller->UpdatePlot(); } BLengthPageController* _controller; Gtk::ToggleToolButton _includeAutoCorrelationsButton; }; #endif aoflagger-v3.4.0/aoqplot/controllers/0000755000175000017500000000000014516225226016353 5ustar olesolesaoflagger-v3.4.0/aoqplot/controllers/polbuttonsetcontroller.h0000644000175000017500000000103614507760372023400 0ustar olesoles#ifndef POL_BUTTON_SET_CONTROLLER_H #define POL_BUTTON_SET_CONTROLLER_H class PolButtonSetController { public: PolButtonSetController() : _ppSelected(true), _pqSelected(false), _qpSelected(false), _qqSelected(true) {} bool IsPPSelected() const { return _ppSelected; } bool IsPQSelected() const { return _pqSelected; } bool IsQPSelected() const { return _qpSelected; } bool IsQQSelected() const { return _qqSelected; } private: bool _ppSelected, _pqSelected, _qpSelected, _qqSelected; }; #endif aoflagger-v3.4.0/aoqplot/controllers/aoqpagecontroller.h0000644000175000017500000000073214507760372022255 0ustar olesoles#ifndef AOQ_PAGE_CONTROLLER_H #define AOQ_PAGE_CONTROLLER_H #include "../../structures/antennainfo.h" #include class AOQPageController { public: virtual ~AOQPageController() {} virtual void SetStatistics(const class StatisticsCollection* statCollection, const std::vector& antennas) {} virtual void SetHistograms(const class HistogramCollection* histograms) {} virtual void CloseStatistics() = 0; }; #endif aoflagger-v3.4.0/aoqplot/controllers/heatmappagecontroller.h0000644000175000017500000000436414507760372023121 0ustar olesoles#ifndef HEATMAP_PAGE_CONTROLLER_H #define HEATMAP_PAGE_CONTROLLER_H #include #include #include "aoqplotpagecontroller.h" #include "../../rfigui/maskedheatmap.h" #include "../../structures/timefrequencydata.h" #include class HeatMapPageController : public AOQPageController { public: HeatMapPageController(); void Attach(class GrayScalePlotPage* page) { _page = page; } void SavePdf(const std::string& filename, QualityTablesFormatter::StatisticKind kind, unsigned width, unsigned height) { updateImageImpl(kind, aocommon::Polarization::StokesI, TimeFrequencyData::AmplitudePart); _heatMap.SavePdf(filename, width, height); } HeatMap& Plot() { return _heatMap; } void UpdateImage() { updateImageImpl(_statisticKind, _polarization, _phase); } void SetKind(QualityTablesFormatter::StatisticKind statisticKind) { _statisticKind = statisticKind; } void SetPolarization(aocommon::PolarizationEnum polarization) { _polarization = polarization; } void SetPhase(enum TimeFrequencyData::ComplexRepresentation phase) { _phase = phase; } enum Normalization { Mean, Winsorized, Median }; void SetNormalization(Normalization normalization) { _normalization = normalization; } protected: virtual std::pair constructImage(QualityTablesFormatter::StatisticKind kind) = 0; private: Image2D normalizeXAxis(const Image2D& input); Image2D normalizeYAxis(const Image2D& input); void updateImageImpl(QualityTablesFormatter::StatisticKind statisticKind, aocommon::PolarizationEnum polarisation, enum TimeFrequencyData::ComplexRepresentation phase); void setToPolarization(TimeFrequencyData& data, aocommon::PolarizationEnum polarisation); void setToPhase(TimeFrequencyData& data, enum TimeFrequencyData::ComplexRepresentation phase); MaskedHeatMap _heatMap; class GrayScalePlotPage* _page; QualityTablesFormatter::StatisticKind _statisticKind; aocommon::PolarizationEnum _polarization; enum TimeFrequencyData::ComplexRepresentation _phase; enum Normalization _normalization; }; #endif aoflagger-v3.4.0/aoqplot/controllers/antennapagecontroller.h0000644000175000017500000000422014507760372023115 0ustar olesoles#ifndef ANTENNAE_PAGE_CONTROLLER_H #define ANTENNAE_PAGE_CONTROLLER_H #include "aoqplotpagecontroller.h" #include #include #include #include #include "../../quality/statisticscollection.h" #include "../../structures/msmetadata.h" class AntennaePageController final : public AOQPlotPageController { protected: void processStatistics(const StatisticsCollection* statCollection, const std::vector& antennas) override { _antennas = antennas; const BaselineStatisticsMap& map = statCollection->BaselineStatistics(); std::vector> baselines = map.BaselineList(); for (std::vector>::const_iterator i = baselines.begin(); i != baselines.end(); ++i) { if (i->first != i->second) { const DefaultStatistics& stats = map.GetStatistics(i->first, i->second); addStatistic(i->first, stats); addStatistic(i->second, stats); } } } const std::map& getStatistics() const override { return _statistics; } void startLine(XYPlot& plot, const std::string& name, int lineIndex, const std::string& yAxisDesc, bool second_axis) override { XYPointSet& points = plot.StartLine(name, "Antenna index", yAxisDesc, XYPointSet::DrawColumns); points.SetUseSecondYAxis(second_axis); std::vector> labels; for (size_t i = 0; i != _antennas.size(); ++i) labels.emplace_back(static_cast(i), _antennas[i].name); plot.XAxis().SetTickLabels(std::move(labels)); plot.XAxis().SetRotateUnits(true); } void addStatistic(unsigned antIndex, const DefaultStatistics& stats) { std::map::iterator iter = _statistics.find(antIndex); if (iter == _statistics.end()) _statistics.insert(std::pair(antIndex, stats)); else iter->second += stats; } private: std::map _statistics; std::vector _antennas; }; #endif aoflagger-v3.4.0/aoqplot/controllers/tfpagecontroller.cpp0000644000175000017500000000206214507760372022437 0ustar olesoles#include "tfpagecontroller.h" #include "../../quality/statisticscollection.h" #include "../../quality/statisticsderivator.h" TFPageController::TFPageController() : _statCollection(nullptr) { HeatMap& map = Plot(); map.SetXAxisDescription("Time index"); map.SetXAxisType(AxisType::kTime); map.SetYAxisDescription("Frequency index"); } std::pair TFPageController::constructImage(QualityTablesFormatter::StatisticKind kind) { if (HasStatistics()) { StatisticsDerivator derivator(*_statCollection); std::pair data = derivator.CreateTFData(kind); if (data.second == nullptr) { Plot().SetXAxisDescription("Time index"); Plot().SetYAxisDescription("Frequency index"); } else { Plot().SetXAxisDescription("Time"); Plot().SetYAxisDescription("Frequency (MHz)"); } return data; } else { return std::pair( TimeFrequencyData(), TimeFrequencyMetaDataCPtr()); } } aoflagger-v3.4.0/aoqplot/controllers/frequencypagecontroller.h0000644000175000017500000000567614507760372023512 0ustar olesoles#ifndef FREQUENCY_PAGE_CONTROLLER_H #define FREQUENCY_PAGE_CONTROLLER_H #include #include #include #include #include "aoqplotpagecontroller.h" class FrequencyPageController final : public AOQPlotPageController { public: void SetPerformFT(bool performFT) { _performFT = performFT; } protected: void processStatistics(const StatisticsCollection* statCollection, const std::vector&) override { _statistics.clear(); const std::map& map = statCollection->FrequencyStatistics(); for (std::map::const_iterator i = map.begin(); i != map.end(); ++i) { _statistics.insert(std::pair( i->first / 1000000.0, i->second)); } } const std::map& getStatistics() const override { return _statistics; } void startLine(XYPlot& plot, const std::string& name, int lineIndex, const std::string& yAxisDesc, bool second_axis) override { XYPointSet* points; if (_performFT) points = &plot.StartLine(name, "Time (μs)", yAxisDesc); else points = &plot.StartLine(name, "Frequency (MHz)", yAxisDesc); points->SetUseSecondYAxis(second_axis); } void processPlot(XYPlot& plot) override { if (_performFT) { performFt(plot); } } void performFt(XYPlot& plot) { size_t count = plot.PointSetCount(); for (size_t line = 0; line < count; ++line) { XYPointSet& pointSet = plot.GetPointSet(line); std::vector>> output; const double min = pointSet.MinX(); const double width = pointSet.MaxX() - min; const double fStart = -2.0 * M_PI * (double)pointSet.Size() / width; const double fEnd = 2.0 * M_PI * (double)pointSet.Size() / width; const double fStep = (fEnd - fStart) / (double)pointSet.Size(); for (double f = fStart; f < fEnd; f += fStep) { std::pair> newElement( f / (2.0 * M_PI), std::complex(0.0, 0.0)); std::complex& nextStat = newElement.second; for (size_t i = 0; i != pointSet.Size(); ++i) { const double t_f = pointSet.GetX(i) * f; const double val = pointSet.GetY(i); if (std::isfinite(val)) nextStat += std::complex(val * cos(t_f), val * sin(t_f)); } output.push_back(newElement); } pointSet.Clear(); for (std::vector>>::const_iterator i = output.begin(); i != output.end(); ++i) { double real = i->second.real(), imag = i->second.imag(); pointSet.PushDataPoint(i->first, sqrt(real * real + imag * imag)); } } } private: std::map _statistics; bool _performFT = false; }; #endif aoflagger-v3.4.0/aoqplot/controllers/baselinepagecontroller.h0000644000175000017500000000242214507760372023255 0ustar olesoles#ifndef BASELINE_PAGE_CONTROLLER_H #define BASELINE_PAGE_CONTROLLER_H #include "heatmappagecontroller.h" #include #include #include class AntennaInfo; class BaselinePageController final : public HeatMapPageController { public: BaselinePageController() : _statCollection(nullptr), _antennas(nullptr) {} void SetStatistics(const StatisticsCollection* statCollection, const std::vector& antennas) override { _statCollection = statCollection; _antennas = &antennas; HeatMap& map = Plot(); map.SetXAxisDescription("Antenna 1 index"); map.SetXAxisMin(0); map.SetXAxisMax(antennas.size() - 1); map.SetYAxisDescription("Antenna 2 index"); map.SetYAxisMin(0); map.SetYAxisMax(antennas.size() - 1); UpdateImage(); } void CloseStatistics() override { _statCollection = nullptr; _antennas = nullptr; } bool HasStatistics() const { return _statCollection != nullptr; } std::string AntennaName(size_t index) const; protected: std::pair constructImage( QualityTablesFormatter::StatisticKind kind) override; private: const StatisticsCollection* _statCollection; const std::vector* _antennas; }; #endif aoflagger-v3.4.0/aoqplot/controllers/aoqplotcontroller.h0000644000175000017500000000254014507760372022316 0ustar olesoles#ifndef AOQPLOT_CONTROLLER_H #define AOQPLOT_CONTROLLER_H #include "../../structures/antennainfo.h" #include "../../quality/qualitytablesformatter.h" #include #include #include #include class AOQPlotController { public: AOQPlotController(); ~AOQPlotController(); void Attach(class AOQPlotWindow* window) { _window = window; } void ReadStatistics(const std::vector& files) { ReadStatistics(files, true, true, 1000, 1000, false); } void ReadStatistics(const std::vector& files, bool downsampleTime, bool downsampleFreq, size_t timeSize, size_t freqSize, bool correctHistograms); struct PlotSavingData { QualityTablesFormatter::StatisticKind statisticKind; std::string filenamePrefix; }; void Save(const PlotSavingData& data, size_t width, size_t height); void Initialize(class AOQPageController* controller, bool averagedStats); private: void close(); void readMetaInfoFromMS(const std::string& filename); bool _isOpen; std::unique_ptr _statCollection; std::unique_ptr _histCollection; std::unique_ptr _fullStats; std::vector _antennas; size_t _polarizationCount; class AOQPlotWindow* _window; }; #endif aoflagger-v3.4.0/aoqplot/controllers/aoqplotpagecontroller.h0000644000175000017500000000423614507760372023157 0ustar olesoles#ifndef AOQ_PLOT_PAGE_CONTROLLER #define AOQ_PLOT_PAGE_CONTROLLER #include #include #include #include #include "../../quality/qualitytablesformatter.h" #include "../../plot/xyplot.h" #include "aoqpagecontroller.h" class AOQPlotPageController : public AOQPageController { public: enum SelectedPol { PolPP, PolPQ, PolQP, PolQQ, PolI }; AOQPlotPageController(); void Attach(class TwoDimensionalPlotPage* page) { _page = page; } void SetStatistics( const StatisticsCollection* statCollection, const std::vector& antennas) override final; void CloseStatistics() override final { _statCollection = nullptr; } bool HasStatistics() const { return _statCollection != nullptr; } void SavePdf(const std::string& filename, QualityTablesFormatter::StatisticKind kind); XYPlot& Plot() { return _plot; } void UpdatePlot(); enum PhaseType { AmplitudePhaseType, PhasePhaseType, RealPhaseType, ImaginaryPhaseType }; protected: virtual void processStatistics(const StatisticsCollection*, const std::vector&) {} virtual const std::map& getStatistics() const = 0; virtual void startLine(XYPlot& plot, const std::string& name, int lineIndex, const std::string& yAxisDesc, bool second_axis) = 0; virtual void processPlot(XYPlot& plot) {} const StatisticsCollection* getStatCollection() const { return _statCollection; } class TwoDimensionalPlotPage* page() { return _page; } private: class TwoDimensionalPlotPage* _page; void updatePlotForSettings( const std::vector& kinds, const std::set& pols, const std::set& phases); double getValue(enum PhaseType Phase, const std::complex& val); void plotStatistic(QualityTablesFormatter::StatisticKind kind, SelectedPol pol, PhaseType phase, int lineIndex, const std::string& yDesc, bool second_axis); const StatisticsCollection* _statCollection; XYPlot _plot; }; #endif aoflagger-v3.4.0/aoqplot/controllers/aoqplotcontroller.cpp0000644000175000017500000001171314507760372022653 0ustar olesoles#include "aoqplotcontroller.h" #include "antennapagecontroller.h" #include "baselinepagecontroller.h" #include "blengthpagecontroller.h" #include "frequencypagecontroller.h" #include "tfpagecontroller.h" #include "timepagecontroller.h" #include "../aoqplotwindow.h" #include "../baselineplotpage.h" #include "../blengthplotpage.h" #include "../frequencyplotpage.h" #include "../histogrampage.h" #include "../plotsheet.h" #include "../summarypage.h" #include "../timefrequencyplotpage.h" #include "../../structures/msmetadata.h" #include "../../quality/combine.h" #include "../../quality/histogramtablesformatter.h" #include "../../quality/histogramcollection.h" #include "../../quality/statisticscollection.h" AOQPlotController::AOQPlotController() : _isOpen(false), _window(nullptr) {} AOQPlotController::~AOQPlotController() {} void AOQPlotController::close() { if (_isOpen) { _statCollection.reset(); _histCollection.reset(); _fullStats.reset(); _isOpen = false; } } void AOQPlotController::readMetaInfoFromMS(const string& filename) { const MSMetaData ms(filename); _polarizationCount = ms.PolarizationCount(); const unsigned antennaCount = ms.AntennaCount(); _antennas.clear(); for (unsigned a = 0; a < antennaCount; ++a) _antennas.push_back(ms.GetAntennaInfo(a)); } void AOQPlotController::ReadStatistics(const std::vector& files, bool downsampleTime, bool downsampleFreq, size_t timeSize, size_t freqSize, bool correctHistograms) { close(); if (!files.empty()) { const std::string& firstFile = *files.begin(); readMetaInfoFromMS(firstFile); quality::FileContents contents = quality::ReadAndCombine(files, true); _statCollection = std::make_unique( std::move(contents.statistics_collection)); _histCollection = std::make_unique( std::move(contents.histogram_collection)); if (_window != nullptr) _window->SetShowHistograms(!_histCollection->Empty()); if (downsampleTime) { std::cout << "Lowering time resolution..." << std::endl; _statCollection->LowerTimeResolution(timeSize); } if (downsampleFreq) { std::cout << "Lowering frequency resolution..." << std::endl; _statCollection->LowerFrequencyResolution(freqSize); } std::cout << "Integrating baseline statistics to one channel..." << std::endl; _statCollection->IntegrateBaselinesToOneChannel(); std::cout << "Regridding time statistics..." << std::endl; _statCollection->RegridTime(); std::cout << "Copying statistics..." << std::endl; _fullStats = std::make_unique(*_statCollection); std::cout << "Integrating time statistics to one channel..." << std::endl; _statCollection->IntegrateTimeToOneChannel(); std::cout << "Opening statistics panel..." << std::endl; _isOpen = true; } } void AOQPlotController::Save(const AOQPlotController::PlotSavingData& data, size_t width, size_t height) { const std::string& prefix = data.filenamePrefix; const QualityTablesFormatter::StatisticKind kind = data.statisticKind; std::cout << "Saving " << prefix << "-antennas.pdf...\n"; AntennaePageController antController; antController.SetStatistics(_statCollection.get(), _antennas); antController.SavePdf(prefix + "-antennas.pdf", kind); std::cout << "Saving " << prefix << "-baselines.pdf...\n"; BaselinePageController baselController; // BaselinePlotPage baselPage(&baselController); baselController.SetStatistics(_statCollection.get(), _antennas); baselController.SavePdf(prefix + "-baselines.pdf", kind, width, height); std::cout << "Saving " << prefix << "-baselinelengths.pdf...\n"; BLengthPageController blenController; blenController.SetStatistics(_statCollection.get(), _antennas); blenController.SavePdf(prefix + "-baselinelengths.pdf", kind); std::cout << "Saving " << prefix << "-timefrequency.pdf...\n"; TFPageController tfController; tfController.SetStatistics(_fullStats.get(), _antennas); tfController.SavePdf(prefix + "-timefrequency.pdf", kind, width, height); std::cout << "Saving " << prefix << "-time.pdf...\n"; TimePageController timeController; timeController.SetStatistics(_statCollection.get(), _antennas); timeController.SavePdf(prefix + "-time.pdf", kind); std::cout << "Saving " << prefix << "-frequency.pdf...\n"; FrequencyPageController freqController; freqController.SetStatistics(_statCollection.get(), _antennas); freqController.SavePdf(prefix + "-frequency.pdf", kind); } void AOQPlotController::Initialize(AOQPageController* controller, bool averagedStats) { if (averagedStats) controller->SetStatistics(_statCollection.get(), _antennas); else controller->SetStatistics(_fullStats.get(), _antennas); controller->SetHistograms(_histCollection.get()); } aoflagger-v3.4.0/aoqplot/controllers/blengthpagecontroller.h0000644000175000017500000000430514507760372023120 0ustar olesoles#ifndef BLENGTH_PATH_CONTROLLER_H #define BLENGTH_PATH_CONTROLLER_H #include #include #include #include #include "aoqplotpagecontroller.h" #include "../../quality/baselinestatisticsmap.h" #include "../../quality/statisticscollection.h" class BLengthPageController final : public AOQPlotPageController { public: void SetIncludeAutoCorrelations(bool inclAutos) { _includeAutoCorrelations = inclAutos; } protected: void processStatistics(const StatisticsCollection* statCollection, const std::vector& antennas) override { _statisticsWithAutocorrelations.clear(); _statisticsWithoutAutocorrelations.clear(); const BaselineStatisticsMap& map = statCollection->BaselineStatistics(); std::vector> baselines = map.BaselineList(); for (std::vector>::const_iterator i = baselines.begin(); i != baselines.end(); ++i) { Baseline bline(antennas[i->first], antennas[i->second]); const DefaultStatistics& statistics = map.GetStatistics(i->first, i->second); _statisticsWithAutocorrelations.insert( std::pair(bline.Distance(), statistics)); if (i->first != i->second) _statisticsWithoutAutocorrelations.insert( std::pair(bline.Distance(), statistics)); } } const std::map& getStatistics() const override { return _includeAutoCorrelations ? _statisticsWithAutocorrelations : _statisticsWithoutAutocorrelations; } void startLine(XYPlot& plot, const std::string& name, int lineIndex, const std::string& yAxisDesc, bool second_axis) override { XYPointSet& points = plot.StartLine(name, "Baseline length (m)", yAxisDesc, XYPointSet::DrawPoints); points.SetUseSecondYAxis(second_axis); } private: bool _includeAutoCorrelations = false; std::map _statisticsWithAutocorrelations; std::map _statisticsWithoutAutocorrelations; }; #endif aoflagger-v3.4.0/aoqplot/controllers/heatmappagecontroller.cpp0000644000175000017500000000731314507760372023451 0ustar olesoles#include "heatmappagecontroller.h" #include "../../quality/statisticscollection.h" #include "../../quality/statisticsderivator.h" #include "../grayscaleplotpage.h" #include "../../structures/samplerow.h" HeatMapPageController::HeatMapPageController() : _page(nullptr), _statisticKind(QualityTablesFormatter::StandardDeviationStatistic), _polarization(aocommon::Polarization::StokesI), _phase(TimeFrequencyData::AmplitudePart) { _heatMap.SetCairoFilter(Cairo::FILTER_NEAREST); _heatMap.SetColorMap(ColorMap::HotCold); _heatMap.SetZRange(FullRange()); _heatMap.SetLogZScale(true); _heatMap.SetZAxisDescription("Statistical value"); _heatMap.SetManualZAxisDescription(true); } void HeatMapPageController::updateImageImpl( QualityTablesFormatter::StatisticKind statisticKind, aocommon::PolarizationEnum polarisation, enum TimeFrequencyData::ComplexRepresentation phase) { std::pair pair = constructImage(statisticKind); TimeFrequencyData& data = pair.first; if (!data.IsEmpty()) { setToPolarization(data, polarisation); setToPhase(data, phase); Image2DCPtr image = data.GetSingleImage(); if (_page != nullptr) { if (_page->NormalizeXAxis()) image = Image2D::MakePtr(normalizeXAxis(*image)); if (_page->NormalizeYAxis()) image = Image2D::MakePtr(normalizeYAxis(*image)); } _heatMap.SetZAxisDescription( StatisticsDerivator::GetDescWithUnits(statisticKind)); _heatMap.SetImage(std::unique_ptr(new PlotImage(image))); _heatMap.SetOriginalMask(data.GetSingleMask()); if (pair.second != nullptr) _heatMap.SetMetaData(pair.second); if (_page != nullptr) _page->Redraw(); } } Image2D HeatMapPageController::normalizeXAxis(const Image2D& input) { Image2D output = Image2D::MakeUnsetImage(input.Width(), input.Height()); for (size_t x = 0; x < input.Width(); ++x) { const SampleRow row = SampleRow::MakeFromColumn(&input, x); num_t norm; if (_normalization == Mean) norm = 1.0 / row.MeanWithMissings(); else if (_normalization == Winsorized) norm = 1.0 / row.WinsorizedMeanWithMissings(); else // _medianNormButton norm = 1.0 / row.MedianWithMissings(); for (size_t y = 0; y < input.Height(); ++y) output.SetValue(x, y, input.Value(x, y) * norm); } return output; } Image2D HeatMapPageController::normalizeYAxis(const Image2D& input) { Image2D output = Image2D::MakeUnsetImage(input.Width(), input.Height()); for (size_t y = 0; y < input.Height(); ++y) { const SampleRow row = SampleRow::MakeFromRow(&input, y); num_t norm; if (_normalization == Mean) norm = 1.0 / row.MeanWithMissings(); else if (_normalization == Winsorized) norm = 1.0 / row.WinsorizedMeanWithMissings(); else // _medianNormButton norm = 1.0 / row.MedianWithMissings(); for (size_t x = 0; x < input.Width(); ++x) output.SetValue(x, y, input.Value(x, y) * norm); } return output; } void HeatMapPageController::setToPolarization( TimeFrequencyData& data, aocommon::PolarizationEnum polarisation) { if ((polarisation == aocommon::Polarization::StokesI && data.HasPolarization(aocommon::Polarization::XX) && data.HasPolarization(aocommon::Polarization::YY)) || (polarisation != aocommon::Polarization::StokesI && data.HasPolarization(polarisation))) { data = data.Make(polarisation); if (polarisation == aocommon::Polarization::StokesI) data.MultiplyImages(0.5); } else { data.SetImagesToZero(); } } void HeatMapPageController::setToPhase( TimeFrequencyData& data, enum TimeFrequencyData::ComplexRepresentation phase) { data = data.Make(phase); } aoflagger-v3.4.0/aoqplot/controllers/histogrampagecontroller.h0000644000175000017500000000755614507760372023505 0ustar olesoles#ifndef HISTOGRAM_PAGE_CONTROLLER_H #define HISTOGRAM_PAGE_CONTROLLER_H #include #include #include "aoqplotpagecontroller.h" #include "../../plot/xyplot.h" class HistogramPageController : public AOQPageController { public: HistogramPageController(); ~HistogramPageController(); void Attach(class HistogramPage* page) { _page = page; } void SetHistograms(const HistogramCollection* histograms) override final; void SetHistograms(const std::string& filename) { _statFilename = filename; readFromFile(); updatePlot(); } void CloseStatistics() override final; bool HasStatistics() const { return _histograms != nullptr; } XYPlot& Plot() { return _plot; } std::string SlopeText(const class LogHistogram& histogram); void SetAutomaticFitRange(bool automaticFitRange) { _automaticFitRange = automaticFitRange; } void SetFitStart(double fitStart) { _fitStart = fitStart; } void SetFitEnd(double fitEnd) { _fitEnd = fitEnd; } void SetFitLogarithmic(bool fitLog) { _fitLogarithmic = fitLog; } double FitStart() { return _fitStart; } double FitEnd() { return _fitEnd; } void SetAutomaticSlopeRange(bool automaticSlopeRange) { _automaticSlopeRange = automaticSlopeRange; } void SetSlopeStart(double start) { _slopeStart = start; } void SetSlopeEnd(double end) { _slopeEnd = end; } void SetSlopeRFIRatio(double rfiRatio) { _slopeRFIRatio = rfiRatio; } double SlopeStart() { return _slopeStart; } double SlopeEnd() { return _slopeEnd; } void SetDrawTotal(bool drawTotal) { _totalHistogram = drawTotal; } void SetDrawFit(bool drawFit) { _fit = drawFit; } void SetDrawSubtractedFit(bool drawSubtrFit) { _subtractFit = drawSubtrFit; } void SetDrawSlope(bool drawSlope) { _drawSlope = drawSlope; } void SetDrawSlope2(bool drawSlope2) { _drawSlope2 = drawSlope2; } void SetDrawRFI(bool drawRFI) { _rfiHistogram = drawRFI; } void SetDrawNonRFI(bool drawNonRFI) { _notRFIHistogram = drawNonRFI; } void SetDerivative(bool derivative) { _derivative = derivative; } void SetStaircase(bool staircaseFunction) { _staircaseFunction = staircaseFunction; } void SetNormalize(bool normalize) { _normalize = normalize; } void SetDeltaS(double deltaS) { _deltaS = deltaS; } void SetDrawXX(bool drawXX) { _drawXX = drawXX; } void SetDrawXY(bool drawXY) { _drawXY = drawXY; } void SetDrawYX(bool drawYX) { _drawYX = drawYX; } void SetDrawYY(bool drawYY) { _drawYY = drawYY; } void SetDrawSum(bool drawSum) { _drawSum = drawSum; } private: void updatePlot(); void addHistogramToPlot(const class LogHistogram& histogram); void addRayleighToPlot(const class LogHistogram& histogram, double sigma, double n); void addRayleighDifferenceToPlot(const LogHistogram& histogram, double sigma, double n); void plotPolarization(const HistogramCollection& histogramCollection, unsigned polarization); void plotPolarization(const class LogHistogram& totalHistogram, const class LogHistogram& rfiHistogram); void plotFit(const class LogHistogram& histogram, const std::string& title); void plotSlope(const class LogHistogram& histogram, const std::string& title, bool useLowerLimit2); void readFromFile(); class HistogramPage* _page; std::string _statFilename; XYPlot _plot; std::unique_ptr _histograms; std::unique_ptr _summedPolarizationHistograms; bool _drawXX, _drawXY, _drawYX, _drawYY, _drawSum; bool _automaticFitRange; double _fitStart, _fitEnd; bool _fitLogarithmic, _automaticSlopeRange; double _slopeStart, _slopeEnd, _slopeRFIRatio; bool _totalHistogram, _fit, _subtractFit, _drawSlope, _drawSlope2, _rfiHistogram, _notRFIHistogram; bool _derivative, _staircaseFunction, _normalize; double _deltaS; }; #endif aoflagger-v3.4.0/aoqplot/controllers/baselinepagecontroller.cpp0000644000175000017500000000651414507760372023616 0ustar olesoles#include "baselinepagecontroller.h" #include "../../quality/statisticscollection.h" #include "../../quality/statisticsderivator.h" using aocommon::Polarization; std::pair BaselinePageController::constructImage( QualityTablesFormatter::StatisticKind kind) { if (HasStatistics()) { const unsigned polarizationCount = _statCollection->PolarizationCount(); std::vector> baselines = _statCollection->BaselineStatistics().BaselineList(); const StatisticsDerivator derivator(*_statCollection); const unsigned antennaCount = _statCollection->BaselineStatistics().AntennaCount(); std::vector realImages(polarizationCount); std::vector imagImages(polarizationCount); std::vector mask(polarizationCount); for (unsigned p = 0; p < polarizationCount; ++p) { realImages[p] = Image2D::CreateUnsetImagePtr(antennaCount, antennaCount); realImages[p]->SetAll(std::numeric_limits::quiet_NaN()); imagImages[p] = Image2D::CreateUnsetImagePtr(antennaCount, antennaCount); imagImages[p]->SetAll(std::numeric_limits::quiet_NaN()); mask[p] = Mask2D::CreateSetMaskPtr(antennaCount, antennaCount); } for (std::vector>::const_iterator i = baselines.begin(); i != baselines.end(); ++i) { const unsigned antenna1 = i->first, antenna2 = i->second; for (unsigned p = 0; p < polarizationCount; ++p) { const std::complex val = derivator.GetComplexBaselineStatistic(kind, antenna1, antenna2, p); realImages[p]->SetValue(antenna1, antenna2, val.real()); imagImages[p]->SetValue(antenna1, antenna2, val.imag()); mask[p]->SetValue(antenna1, antenna2, false); } } TimeFrequencyData data; if (polarizationCount == 1) { data = TimeFrequencyData(Polarization::StokesI, realImages[0], imagImages[0]); data.SetGlobalMask(mask[0]); } else if (polarizationCount == 2) { data = TimeFrequencyData(Polarization::XX, realImages[0], imagImages[0], Polarization::YY, realImages[1], imagImages[1]); data.SetIndividualPolarizationMasks(mask[0], mask[1]); } else if (polarizationCount == 4) { data = TimeFrequencyData::FromLinear( realImages[0], imagImages[0], realImages[1], imagImages[1], realImages[2], imagImages[2], realImages[3], imagImages[3]); data.SetIndividualPolarizationMasks(mask[0], mask[1], mask[2], mask[3]); } else { std::stringstream s; s << "Set has not 1, 2 or 4 polarizations (?!?) : " "StatisticsCollection.PolarizationCount() == " << polarizationCount; throw std::runtime_error(s.str()); } return std::pair( data, TimeFrequencyMetaDataCPtr()); } else { return std::pair( TimeFrequencyData(), TimeFrequencyMetaDataCPtr()); } } std::string BaselinePageController::AntennaName(size_t index) const { std::string name; if (_antennas == nullptr) { std::stringstream s; s << index; name = s.str(); } else { name = (*_antennas)[index].name; } return name; } aoflagger-v3.4.0/aoqplot/controllers/timepagecontroller.h0000644000175000017500000000147314507760372022436 0ustar olesoles#ifndef TIME_PAGE_CONTROLLER_H #define TIME_PAGE_CONTROLLER_H #include #include #include "aoqplotpagecontroller.h" #include "../../quality/statisticscollection.h" class TimePageController final : public AOQPlotPageController { protected: const std::map& getStatistics() const override { if (getStatCollection()->AllTimeStatistics().empty()) { static std::map empty_set; return empty_set; } else { return getStatCollection()->TimeStatistics(); } } void startLine(XYPlot& plot, const std::string& name, int lineIndex, const std::string& yAxisDesc, bool second_axis) override { XYPointSet& points = plot.StartLine(name, "Time", yAxisDesc); points.SetUseSecondYAxis(second_axis); } }; #endif aoflagger-v3.4.0/aoqplot/controllers/tfpagecontroller.h0000644000175000017500000000142114507760372022102 0ustar olesoles#ifndef TF_PAGE_CONTROLLER_H #define TF_PAGE_CONTROLLER_H #include #include #include "heatmappagecontroller.h" class TFPageController : public HeatMapPageController { public: TFPageController(); void SetStatistics(const StatisticsCollection* statCollection, const std::vector&) override final { _statCollection = statCollection; UpdateImage(); } void CloseStatistics() override final { _statCollection = nullptr; } bool HasStatistics() const { return _statCollection != nullptr; } protected: std::pair constructImage( QualityTablesFormatter::StatisticKind kind) final override; private: const StatisticsCollection* _statCollection; }; #endif aoflagger-v3.4.0/aoqplot/controllers/aoqplotpagecontroller.cpp0000644000175000017500000001147414507760372023514 0ustar olesoles#include "aoqplotpagecontroller.h" #include "../twodimensionalplotpage.h" #include "../../quality/statisticsderivator.h" #include "../../util/logger.h" AOQPlotPageController::AOQPlotPageController() : _page(nullptr), _statCollection(nullptr) {} void AOQPlotPageController::UpdatePlot() { if (_page != nullptr) { updatePlotForSettings(_page->GetSelectedKinds(), _page->GetSelectedPolarizations(), _page->GetSelectedPhases()); } } void AOQPlotPageController::updatePlotForSettings( const std::vector& kinds, const std::set& pols, const std::set& phases) { if (HasStatistics()) { _plot.Clear(); std::map units; for (const QualityTablesFormatter::StatisticKind k : kinds) { const std::string unit_str = StatisticsDerivator::GetUnits(k); std::map::const_iterator iterator = units.find(unit_str); if (iterator == units.end()) { units.emplace(unit_str, units.size() % 2); } } _plot.Y2Axis().SetShow(false); int index = 0; for (const QualityTablesFormatter::StatisticKind k : kinds) { const std::string unit_str = StatisticsDerivator::GetUnits(k); const int axis_number = units.find(unit_str)->second; const bool multiple_units = units.size() > 3 || (units.size() > 2 && (axis_number % 2) == 0); XYPlotAxis& y_axis = axis_number == 1 ? _plot.Y2Axis() : _plot.YAxis(); y_axis.SetShow(true); for (const SelectedPol p : pols) { for (const PhaseType ph : phases) { const std::string description = multiple_units ? "Value" : StatisticsDerivator::GetDescWithUnits(k); plotStatistic(k, p, ph, index, description, axis_number == 1); ++index; } } } processPlot(_plot); if (_page != nullptr) { _page->Redraw(); } } } double AOQPlotPageController::getValue(enum PhaseType phase, const std::complex& val) { switch (phase) { default: case AmplitudePhaseType: return sqrt(val.real() * val.real() + val.imag() * val.imag()); case PhasePhaseType: return atan2(val.imag(), val.real()); case RealPhaseType: return val.real(); case ImaginaryPhaseType: return val.imag(); } } void AOQPlotPageController::plotStatistic( QualityTablesFormatter::StatisticKind kind, SelectedPol pol, PhaseType phase, int lineIndex, const std::string& yDesc, bool second_axis) { const StatisticsDerivator derivator(*_statCollection); const size_t polCount = _statCollection->PolarizationCount(); const std::map& statistics = getStatistics(); std::ostringstream s; int polIndex = -1; s << StatisticsDerivator::GetDescription(kind); switch (pol) { case PolI: s << ", pol I"; polIndex = 0; break; case PolPP: s << ", pol PP"; polIndex = 0; break; case PolPQ: s << ", pol PQ"; if (polCount == 4) polIndex = 1; break; case PolQP: s << ", pol QP"; if (polCount == 4) polIndex = 2; break; case PolQQ: s << ", pol QQ"; if (polCount == 4) polIndex = 3; else if (polCount == 2) polIndex = 1; break; } if (phase == RealPhaseType) s << " (real)"; else if (phase == ImaginaryPhaseType) s << " (imag)"; if (polIndex >= 0) { startLine(_plot, s.str(), lineIndex, yDesc, second_axis); for (std::map::const_iterator i = statistics.begin(); i != statistics.end(); ++i) { const double x = i->first; std::complex val; if (pol == PolI) { const std::complex valA = derivator.GetComplexStatistic(kind, i->second, 0); const std::complex valB = derivator.GetComplexStatistic(kind, i->second, polCount - 1); val = valA * 0.5l + valB * 0.5l; } else { val = derivator.GetComplexStatistic(kind, i->second, polIndex); } _plot.PushDataPoint(x, getValue(phase, val)); } } } void AOQPlotPageController::SavePdf( const string& filename, QualityTablesFormatter::StatisticKind kind) { const std::vector kinds{kind}; const std::set pols{PolI}; const std::set phases{AmplitudePhaseType}; updatePlotForSettings(kinds, pols, phases); _plot.SavePdf(filename, 640, 480); } void AOQPlotPageController::SetStatistics( const StatisticsCollection* statCollection, const std::vector& antennas) { processStatistics(statCollection, antennas); _statCollection = statCollection; UpdatePlot(); } aoflagger-v3.4.0/aoqplot/controllers/histogrampagecontroller.cpp0000644000175000017500000002646614507760372024041 0ustar olesoles#include "histogrampagecontroller.h" #include "../histogrampage.h" #include "../../quality/histogramtablesformatter.h" #include "../../quality/histogramcollection.h" #include "../../quality/rayleighfitter.h" #include "../../structures/msmetadata.h" #ifndef HAVE_EXP10 #define exp10(x) exp((2.3025850929940456840179914546844) * (x)) #endif HistogramPageController::HistogramPageController() : _page(nullptr), _histograms(nullptr), _summedPolarizationHistograms(nullptr) {} HistogramPageController::~HistogramPageController() { CloseStatistics(); } void HistogramPageController::readFromFile() { CloseStatistics(); HistogramTablesFormatter histogramTables(_statFilename); if (histogramTables.HistogramsExist()) { const MSMetaData set(_statFilename); const unsigned polarizationCount = set.PolarizationCount(); _histograms.reset(new HistogramCollection(polarizationCount)); _histograms->Load(histogramTables); } } void HistogramPageController::CloseStatistics() { _statFilename = std::string(); _histograms.reset(); _summedPolarizationHistograms.reset(); } void HistogramPageController::SetHistograms( const HistogramCollection* histograms) { CloseStatistics(); _histograms.reset(new HistogramCollection(*histograms)); _summedPolarizationHistograms.reset( _histograms->CreateSummedPolarizationCollection()); _histograms->CreateMissingBins(); _summedPolarizationHistograms->CreateMissingBins(); updatePlot(); } void HistogramPageController::updatePlot() { if (HasStatistics()) { _plot.Clear(); const unsigned polarizationCount = _histograms->PolarizationCount(); if (_drawXX) plotPolarization(*_histograms, 0); if (_drawXY && polarizationCount >= 2) plotPolarization(*_histograms, 1); if (_drawYX && polarizationCount >= 3) plotPolarization(*_histograms, 2); if (_drawYY && polarizationCount >= 4) plotPolarization(*_histograms, 3); if (_drawSum) plotPolarization(*_summedPolarizationHistograms, 0); if (_page != nullptr) _page->Redraw(); } } void HistogramPageController::plotPolarization( const HistogramCollection& histogramCollection, unsigned polarization) { LogHistogram totalHistogram, rfiHistogram; histogramCollection.GetTotalHistogramForCrossCorrelations(polarization, totalHistogram); histogramCollection.GetRFIHistogramForCrossCorrelations(polarization, rfiHistogram); plotPolarization(totalHistogram, rfiHistogram); } std::string HistogramPageController::SlopeText(const LogHistogram& histogram) { if (_automaticSlopeRange) { histogram.GetRFIRegion(_slopeStart, _slopeEnd); } std::stringstream str; const double slope = histogram.NormalizedSlope(_slopeStart, _slopeEnd), powerLawExp = histogram.PowerLawExponent(_slopeStart), powerLawExpError = histogram.PowerLawExponentStdError(_slopeStart, powerLawExp), offset = histogram.NormalizedSlopeOffset(_slopeStart, _slopeEnd, slope), error = histogram.NormalizedSlopeStdError(_slopeStart, _slopeEnd, slope), errorB = histogram.NormalizedSlopeStdDevBySampling( _slopeStart, _slopeEnd, slope, _deltaS), upperLimit = histogram.PowerLawUpperLimit(_slopeStart, slope, exp10(offset)), lowerLimit = histogram.PowerLawLowerLimit( _slopeStart, slope, exp10(offset), _slopeRFIRatio), lowerError = fabs(lowerLimit - histogram.PowerLawLowerLimit( _slopeStart, slope - error, exp10(offset), _slopeRFIRatio)), lowerLimit2 = histogram.PowerLawLowerLimit2( _slopeStart, slope, exp10(offset), _slopeRFIRatio); str << slope << "±" << error << "\n/±" << errorB << "\nb=" << exp10(offset) << "\nPL:" << powerLawExp << "±" << powerLawExpError << "\n[" << log10(lowerLimit) << "±" << lowerError << ';' << log10(upperLimit) << ']' << '\n' << log10(lowerLimit2); return str.str(); } void HistogramPageController::plotSlope(const LogHistogram& histogram, const std::string& title, bool useLowerLimit2) { double start, end; if (_automaticSlopeRange) { histogram.GetRFIRegion(start, end); } else { start = _slopeStart; end = _slopeEnd; } double xMin = log10(histogram.MinPositiveAmplitude()), rfiRatio = _slopeRFIRatio, slope = histogram.NormalizedSlope(start, end), offset = histogram.NormalizedSlopeOffset(start, end, slope), upperLimit = log10(histogram.PowerLawUpperLimit(start, slope, exp10(offset))), lowerLimit = useLowerLimit2 ? log10(histogram.PowerLawLowerLimit2( start, slope, exp10(offset), rfiRatio)) : log10(histogram.PowerLawLowerLimit( start, slope, exp10(offset), rfiRatio)); double xStart, xEnd; if (std::isfinite(lowerLimit)) xStart = lowerLimit; else xStart = log10(start) - 1.0; if (std::isfinite(upperLimit)) xEnd = upperLimit; else xEnd = log10(histogram.MaxAmplitude()); double yStart = xStart * slope + offset, yEnd = xEnd * slope + offset; _plot.StartLine(title, "Amplitude in arbitrary units (log)", "Frequency (log)"); if (useLowerLimit2 && std::isfinite(xMin)) _plot.PushDataPoint(xMin, yStart); _plot.PushDataPoint(xStart, yStart); _plot.PushDataPoint(xEnd, yEnd); } void HistogramPageController::plotPolarization( const LogHistogram& totalHistogram, const LogHistogram& rfiHistogram) { if (_totalHistogram) { _plot.StartLine("Total histogram", "Amplitude in arbitrary units (log)", "Frequency (log)"); addHistogramToPlot(totalHistogram); if (_fit || _subtractFit) { plotFit(totalHistogram, "Fit to total"); } if (_drawSlope) { plotSlope(totalHistogram, "Fitted slope", false); } if (_drawSlope2) { plotSlope(totalHistogram, "Fitted slope", true); } const std::string str = SlopeText(totalHistogram); _page->SetSlopeFrame(str); } if (_rfiHistogram) { _plot.StartLine("RFI histogram", "Amplitude in arbitrary units (log)", "Frequency (log)"); addHistogramToPlot(rfiHistogram); if (_fit || _subtractFit) { plotFit(rfiHistogram, "Fit to RFI"); } const std::string str = SlopeText(rfiHistogram); _page->SetSlopeFrame(str); if (_drawSlope) { plotSlope(rfiHistogram, "Fitted slope", false); } if (_drawSlope2) { plotSlope(rfiHistogram, "Fitted slope", true); } } if (_notRFIHistogram) { _plot.StartLine("Non-RFI histogram", "Amplitude in arbitrary units (log)", "Frequency (log)"); LogHistogram histogram(totalHistogram); histogram -= rfiHistogram; addHistogramToPlot(histogram); if (_fit || _subtractFit) { plotFit(histogram, "Fit to Non-RFI"); } } } void HistogramPageController::plotFit(const LogHistogram& histogram, const std::string& title) { double sigmaEstimate; sigmaEstimate = RayleighFitter::SigmaEstimate(histogram); if (_automaticFitRange) { RayleighFitter::FindFitRangeUnderRFIContamination( histogram.MinPositiveAmplitude(), sigmaEstimate, _fitStart, _fitEnd); } double sigma = RayleighFitter::SigmaEstimate(histogram, _fitStart, _fitEnd), n = RayleighFitter::NEstimate(histogram, _fitStart, _fitEnd); RayleighFitter fitter; fitter.SetFitLogarithmic(_fitLogarithmic); fitter.Fit(_fitStart, _fitEnd, histogram, sigma, n); if (_fit) { _plot.StartLine(title, "Amplitude in arbitrary units (log)", "Frequency (log)"); addRayleighToPlot(histogram, sigma, n); } if (_subtractFit) { _plot.StartLine(title, "Amplitude in arbitrary units (log)", "Frequency (log)"); addRayleighDifferenceToPlot(histogram, sigma, n); } std::stringstream str; str << "σ=1e" << log10(sigma) << ",n=1e" << log10(n) << '\n' << "n_t=1e" << log10(histogram.NormalizedTotalCount()) << '\n' << "mode=1e" << log10(histogram.AmplitudeWithMaxNormalizedCount()) << '\n' << "ε_R=" << RayleighFitter::ErrorOfFit(histogram, _fitStart, _fitEnd, sigma, n); _page->SetFitText(str.str()); } void HistogramPageController::addRayleighToPlot(const LogHistogram& histogram, double sigma, double n) { const bool derivative = _derivative; double x = histogram.MinPositiveAmplitude(); const double xend = sigma * 5.0; const double sigmaP2 = sigma * sigma; while (x < xend) { const double logx = log10(x); if (derivative) { const double dc = -(exp10(2.0 * x) - sigmaP2) / sigmaP2; if (std::isfinite(logx) && std::isfinite(dc)) _plot.PushDataPoint(logx, dc); } else { const double c = n * x / (sigmaP2)*exp(-x * x / (2 * sigmaP2)); const double logc = log10(c); if (std::isfinite(logx) && std::isfinite(logc)) _plot.PushDataPoint(logx, logc); } x *= 1.05; } } void HistogramPageController::addRayleighDifferenceToPlot( const LogHistogram& histogram, double sigma, double n) { const double sigmaP2 = sigma * sigma; const double minCount = histogram.MinPosNormalizedCount(); for (LogHistogram::iterator i = histogram.begin(); i != histogram.end(); ++i) { const double x = i.value(); const double c = n * x / (sigmaP2)*exp(-x * x / (2 * sigmaP2)); const double diff = fabs(i.normalizedCount() - c); if (diff >= minCount) { const double logx = log10(x); const double logc = log10(diff); if (std::isfinite(logx) && std::isfinite(logc)) _plot.PushDataPoint(logx, logc); } } } void HistogramPageController::addHistogramToPlot( const LogHistogram& histogram) { const bool derivative = _derivative; const bool staircase = _staircaseFunction; const bool normalize = _normalize; double deltaS = _deltaS; if (deltaS <= 1.0001) deltaS = 1.0001; for (LogHistogram::iterator i = histogram.begin(); i != histogram.end(); ++i) { double x = i.value(), logxStart, logxEnd; if (staircase) { logxStart = log10(i.binStart()); logxEnd = log10(i.binEnd()); } else { logxStart = log10(x); logxEnd = 0.0; // unused, but to avoid warning } if (derivative) { const double cslope = histogram.NormalizedSlope(x / deltaS, x * deltaS); // if(std::isfinite(logxStart) && std::isfinite(cslope)) _plot.PushDataPoint(logxStart, cslope); if (staircase) // && std::isfinite(logxEnd) && std::isfinite(cslope)) _plot.PushDataPoint(logxEnd, cslope); } else { const double logc = log10(normalize ? i.normalizedCount() : i.unnormalizedCount()); // if(std::isfinite(logxStart) && std::isfinite(logc)) _plot.PushDataPoint(logxStart, logc); if (staircase) // && std::isfinite(logxEnd) && std::isfinite(logc)) _plot.PushDataPoint(logxEnd, logc); } } } aoflagger-v3.4.0/aoqplot/baselineplotpage.h0000644000175000017500000000104714507760372017504 0ustar olesoles#ifndef GUI_QUALITY__BASELINEPLOTPAGE_H #define GUI_QUALITY__BASELINEPLOTPAGE_H #include #include #include #include #include "../quality/qualitytablesformatter.h" #include "grayscaleplotpage.h" class BaselinePlotPage : public GrayScalePlotPage { public: explicit BaselinePlotPage(class BaselinePageController* controller); virtual ~BaselinePlotPage(); protected: private: class BaselinePageController* _controller; void onMouseMoved(double x, double y); }; #endif aoflagger-v3.4.0/applications/0000755000175000017500000000000014516225226015014 5ustar olesolesaoflagger-v3.4.0/applications/badstations.cpp0000644000175000017500000001602014507760372020040 0ustar olesoles#include "../algorithms/antennaselector.h" #include "../algorithms/baselineselector.h" #include "../structures/msmetadata.h" #include "../quality/defaultstatistics.h" #include "../quality/histogramcollection.h" #include "../quality/qualitytablesformatter.h" #include "../quality/statisticscollection.h" #include "../quality/statisticsderivator.h" #include "../quality/histogramtablesformatter.h" #include #include #include #include using algorithms::AntennaSelector; using algorithms::BaselineSelector; StatisticsCollection load(const std::string& filename, std::vector& antennae) { StatisticsCollection statisticsCollection; const HistogramCollection histogramCollection; const MSMetaData ms(filename); const unsigned polarizationCount = ms.PolarizationCount(); statisticsCollection.SetPolarizationCount(polarizationCount); QualityTablesFormatter qualityData(filename); statisticsCollection.Load(qualityData); const unsigned antennaCount = ms.AntennaCount(); for (unsigned a = 0; a < antennaCount; ++a) antennae.push_back(ms.GetAntennaInfo(a)); return statisticsCollection; } std::set detectRFIPercentage(const char* filename) { std::vector antennae; StatisticsCollection statisticsCollection = load(filename, antennae); BaselineSelector selector; selector.SetUseLog(true); statisticsCollection.IntegrateBaselinesToOneChannel(); const BaselineStatisticsMap& baselineMap = statisticsCollection.BaselineStatistics(); const std::vector> list = baselineMap.BaselineList(); for (std::vector>::const_iterator i = list.begin(); i != list.end(); ++i) { const unsigned a1 = i->first, a2 = i->second; DefaultStatistics statistic = baselineMap.GetStatistics(a1, a2); selector.Add(statistic, antennae[a1], antennae[a2]); } std::vector markedBaselines; std::set badStations; selector.Search(markedBaselines); selector.ImplyStations(markedBaselines, 0.3, badStations); std::cout << "List of " << badStations.size() << " bad stations:\n"; for (const size_t ant : badStations) { std::cout << antennae[ant].name << " (" << ant << ")\n"; } return std::set(badStations.begin(), badStations.end()); } std::set detectStddev(const char* filename) { std::vector antennae; const StatisticsCollection statisticsCollection = load(filename, antennae); AntennaSelector selector; std::vector badStations = selector.Run(statisticsCollection); std::cout << "List of " << badStations.size() << " bad stations:\n"; for (const size_t ant : badStations) { std::cout << antennae[ant].name << " (" << ant << ")\n"; } return std::set(badStations.begin(), badStations.end()); } void flagAntennas(const char* filename, const std::set& antennae) { casacore::MeasurementSet ms(filename, casacore::Table::Update); /** * Read some meta data from the measurement set */ const casacore::MSSpectralWindow spwTable = ms.spectralWindow(); const size_t spwCount = spwTable.nrow(); if (spwCount != 1) throw std::runtime_error("Set should have exactly one spectral window"); const casacore::ScalarColumn numChanCol( spwTable, casacore::MSSpectralWindow::columnName( casacore::MSSpectralWindowEnums::NUM_CHAN)); const size_t channelCount = numChanCol.get(0); if (channelCount == 0) throw std::runtime_error("No channels in set"); const casacore::ScalarColumn ant1Column( ms, ms.columnName(casacore::MSMainEnums::ANTENNA1)); const casacore::ScalarColumn ant2Column( ms, ms.columnName(casacore::MSMainEnums::ANTENNA2)); casacore::ArrayColumn flagsColumn( ms, ms.columnName(casacore::MSMainEnums::FLAG)); if (ms.nrow() == 0) throw std::runtime_error("Table has no rows (no data)"); const casacore::IPosition flagsShape = flagsColumn.shape(0); const casacore::Array flags(flagsShape, true); std::cout << "Flagging... " << std::flush; /** * Flag */ size_t crossCount = 0, autoCount = 0; for (size_t rowIndex = 0; rowIndex != ms.nrow(); ++rowIndex) { // Selected? if (antennae.find(ant1Column.get(rowIndex)) != antennae.end() || antennae.find(ant2Column.get(rowIndex)) != antennae.end()) { if (ant1Column.get(rowIndex) == ant2Column.get(rowIndex)) ++autoCount; else ++crossCount; flagsColumn.put(rowIndex, flags); } } std::cout << "DONE (selected " << crossCount << " cross- and " << autoCount << " auto-correlated timesteps)\n"; } void printSyntax(std::ostream& stream, char* argv[]) { stream << "The executable 'badstations' will give a list of stations that " "are outliers\n" "according to the RFI statistics.\n" "\n" "Syntax: badstations [options] \n" "\n" "Options:\n" "-flag\n" " Will not only show statistics, but also flag the antennas that " "are found\n" " to be bad in the measurement set.\n" " (this only works if the given filename is a measurement set, " "not a .ref).\n" "-method \n" " Select detection method. Method 'stddev' is the default, and " "simply detects\n" " stations with an outlyer standard deviation. Method " "'percentage' detects\n" " outliers based on the percentage RFI statistic, taking into " "account that\n" " short baselines often see fewer RFI, by fitting a curve to the " "statistic\n" " as a function of baseline.\n"; } int main(int argc, char* argv[]) { #ifdef HAS_LOFARSTMAN register_lofarstman(); #endif // HAS_LOFARSTMAN int argi = 1; bool doFlag = false; enum Method { StddevMethod, RFIPercentangeMethod } method = StddevMethod; while (argi < argc && argv[argi][0] == '-') { const std::string p(argv[argi] + 1); if (p == "flag") { doFlag = true; } else if (p == "method") { ++argi; const std::string m = argv[argi]; if (m == "stddev") method = StddevMethod; else if (m == "percentage") method = RFIPercentangeMethod; else throw std::runtime_error("Unknown method given"); } else { throw std::runtime_error("Unknown parameter"); } ++argi; } if (argi >= argc) { printSyntax(std::cerr, argv); return -1; } else { const char* filename = argv[argi]; std::set badAntennas; switch (method) { case StddevMethod: badAntennas = detectStddev(filename); break; case RFIPercentangeMethod: badAntennas = detectRFIPercentage(filename); break; } if (doFlag) flagAntennas(filename, badAntennas); return 0; } } aoflagger-v3.4.0/applications/aoflagger.cpp0000644000175000017500000002111514507760372017455 0ustar olesoles#include "../aoluarunner/options.h" #include "../structures/types.h" #include "../util/logger.h" #include "../util/stopwatch.h" #include "../util/numberlist.h" #include "../aoluarunner/runner.h" #include #include #include #include #include #include #define RETURN_SUCCESS 0 #define RETURN_CMDLINE_ERROR 10 #define RETURN_STRATEGY_PARSE_ERROR 20 #define RETURN_UNHANDLED_EXCEPTION 30 void checkRelease() { #ifndef NDEBUG Logger::Warn << "This version of the AOFlagger has been compiled as DEBUG " "version! (NDEBUG was not defined)\n" << "For better performance, recompile it as a RELEASE.\n\n"; #endif } void generalInfo() { Logger::Info << "AOFlagger " << AOFLAGGER_VERSION_STR << " (" << AOFLAGGER_VERSION_DATE_STR << ") command line application\n" "Author: André Offringa (offringa@gmail.com)\n\n"; } int main(int argc, char** argv) { if (argc == 1) { generalInfo(); Logger::Error << "This program will execute a Lua flagging script that can be " "created with the RFI gui\n" "and executes it on one or several observations.\n\n" "Usage: " << argv[0] << " [options] [ [..]]" << R"( -v will produce verbose output -j overrides the number of threads specified in the strategy (default: one thread for each CPU core) -strategy Specifies a customized strategy. -direct-read Will perform the slowest IO but will always work. -indirect-read Will reorder the measurement set before starting, which is normally faster but requires free disk space to reorder the data to. -memory-read Will read the entire measurement set in memory. This is the fastest, but requires much memory. -auto-read-mode Will select either memory or direct mode based on available memory (default). -skip-flagged Will skip an ms if it has already been processed by AOFlagger according to its HISTORY table. -uvw Reads uvw values (some exotic strategies require these). -column Specify column to flag. -interval Only process the specified timesteps. Indices are zero indexed, and the end is exclusive, such that -interval 10 20 selects 10, 11, ... 19. -chunk-size This will split the set into intervals with the given maximum size, and flag each interval independently. This lowers the amount of memory required. The flagger has slightly less information per interval, but for a size of 1000 timesteps there is no noticable difference. With a size of 100 the difference is mostly not problematic either. In some cases, splitting the data increases accuracy, in particular when the statistics in the set change significantly over time (e.g. rising Galaxy). -bands Comma separated list of (zero-indexed) band ids to process. -fields Comma separated list of (zero-indexed) field ids to process. -baselines < all / cross / auto > Run the strategy on the given baseline types. The default is to run the strategy on all cross-correlation baselines. This parameter has no effect for single-dish observations. -combine-spws Join all SPWs together in frequency direction before flagging. -preamble Runs the specified Lua statement before starting to flag. This is typically used to define a variable, e.g. -preamble "bandpassfile = mybandpass.txt". -concatenate-frequency Reads all obs arguments and processes them as one measurement set. Every obs argument contains one band the same measurement; meaning the other metadata of the measurement sets is identical. This tool supports the Casacore measurement set, the SDFITS and Filterbank formats and some more. See the documentation for support of other file types. )"; checkRelease(); return RETURN_CMDLINE_ERROR; } Options options; size_t parameterIndex = 1; while (parameterIndex < (size_t)argc && argv[parameterIndex][0] == '-') { std::string flag(argv[parameterIndex] + 1); // If "--" was used, strip another dash if (!flag.empty() && flag[0] == '-') flag = flag.substr(1); if (flag == "j" && parameterIndex < (size_t)(argc - 1)) { ++parameterIndex; options.threadCount = atoi(argv[parameterIndex]); } else if (flag == "v") { options.logVerbosity = Logger::VerboseVerbosity; } else if (flag == "version") { Logger::Info << "AOFlagger " << AOFLAGGER_VERSION_STR << " (" << AOFLAGGER_VERSION_DATE_STR << ")\n"; return 0; } else if (flag == "direct-read") { options.readMode = DirectReadMode; } else if (flag == "reorder" || flag == "indirect-read") { options.readMode = ReorderingReadMode; if (flag == "indirect-read") Logger::Warn << "WARNING: Parameter '-indirect-read' is deprecated, " "use '-reorder' instead.\n"; } else if (flag == "memory-read") { options.readMode = MemoryReadMode; } else if (flag == "auto-read-mode") { options.readMode = AutoReadMode; } else if (flag == "strategy") { parameterIndex++; options.strategyFilename = argv[parameterIndex]; } else if (flag == "skip-flagged") { options.skipFlagged = true; } else if (flag == "uvw") { options.readUVW = true; } else if (flag == "column") { parameterIndex++; options.dataColumn = std::string(argv[parameterIndex]); } else if (flag == "bands") { ++parameterIndex; NumberList::ParseIntList(argv[parameterIndex], options.bands); } else if (flag == "fields") { ++parameterIndex; NumberList::ParseIntList(argv[parameterIndex], options.fields); } else if (flag == "combine-spws") { options.combineSPWs = true; } else if (flag == "concatenate-frequency") { options.concatenateFrequency = true; } else if (flag == "preamble") { ++parameterIndex; options.preamble.emplace_back(argv[parameterIndex]); } else if (flag == "interval") { options.startTimestep = atoi(argv[parameterIndex + 1]); options.endTimestep = atoi(argv[parameterIndex + 2]); parameterIndex += 2; } else if (flag == "chunk-size" || flag == "max-interval-size") { ++parameterIndex; options.chunkSize = atoi(argv[parameterIndex]); } else if (flag == "baselines") { ++parameterIndex; const std::string bTypes = argv[parameterIndex]; if (bTypes == "all") { options.baselineSelection = BaselineSelection::All; } else if (bTypes == "cross") { options.baselineSelection = BaselineSelection::CrossCorrelations; } else if (bTypes == "auto") { options.baselineSelection = BaselineSelection::AutoCorrelations; } else { Logger::Error << "Incorrect usage; baselines parameter should be set " "to 'all', 'cross' or 'auto'.\n"; return RETURN_CMDLINE_ERROR; } } else { Logger::Error << "Incorrect usage; parameter \"" << argv[parameterIndex] << "\" not understood.\n"; return RETURN_CMDLINE_ERROR; } ++parameterIndex; } try { Logger::SetVerbosity( options.logVerbosity.value_or(Logger::NormalVerbosity)); generalInfo(); checkRelease(); const Stopwatch watch(true); std::stringstream commandLineStr; commandLineStr << argv[0]; for (int i = 1; i < argc; ++i) { commandLineStr << " \"" << argv[i] << '\"'; } options.commandLine = commandLineStr.str(); for (int i = parameterIndex; i < argc; ++i) options.filenames.emplace_back(argv[i]); const std::filesystem::path strategyPath = options.strategyFilename; if (boost::to_lower_copy(strategyPath.extension().string()) == ".rfis") { Logger::Error << "An old .rfis file was specified. AOFlagger version 3 " "supports only Lua scripts and can\n" "not run the old .rfis-style files. Example Lua " "strategies can be found in the aoflagger\n" "source directory under data/strategies.\n"; return RETURN_CMDLINE_ERROR; } Runner runner(options); runner.Run(); Logger::Debug << "Time: " << watch.ToString() << "\n"; return RETURN_SUCCESS; } catch (std::exception& exception) { std::cerr << "An unhandled exception occured: " << exception.what() << '\n' << "If you think this is a bug, please contact offringa@gmail.com\n"; return RETURN_UNHANDLED_EXCEPTION; } } aoflagger-v3.4.0/applications/aoqplot.cpp0000644000175000017500000001102114507760372017200 0ustar olesoles#include "../aoqplot/aoqplotwindow.h" #include "../aoqplot/controllers/aoqplotcontroller.h" #include #include #include #include #include "../util/logger.h" bool SelectFile(AOQPlotWindow& window, std::string& filename) { Gtk::FileChooserDialog fileDialog(window, "Open observation set"); fileDialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); fileDialog.add_button("_Open", Gtk::RESPONSE_OK); const Glib::RefPtr filter = Gtk::FileFilter::create(); filter->set_name("Observation sets (*.{vds,gds,ref,MS})"); filter->add_pattern("*.vds"); filter->add_pattern("*.gds"); filter->add_pattern("*.gvds"); filter->add_pattern("*.ref"); filter->add_pattern("*.MS"); fileDialog.add_filter(filter); if (fileDialog.run() == Gtk::RESPONSE_OK) { filename = fileDialog.get_filename(); return true; } else { return false; } } int main(int argc, char* argv[]) { // We have to 'lie' about argc to create(..), because of a bug in older // gtkmms. int altArgc = 1; AOQPlotController controller; std::unique_ptr window; bool openGUI = true; int argi = 1; std::vector savedPlots; std::vector files; while (argi < argc) { if (argv[argi][0] == '-') { std::string p; if (argv[argi][1] == '-') p = &argv[argi][2]; else p = &argv[argi][1]; if (p == "help" || p == "h") { Logger::Info << "Syntax: aoqplot [] []\n\n" " can be a measurement set for opening a single " "observation.\n" "To get statistics for a (remote) observation consisting of " "multiple measurement\n" "sets, specify a measurement set specifier instead (generally a " ".ref, .vds\n" ".gvds or .gds file).\n" "\n" "Options can be:\n" "-help\n" " Show syntax help.\n" "-version\n" " Print version info and exit.\n" "-v\n" " Verbose logging.\n" "-save [filename prefix] [statistic name]\n" " Save every plot for the given kind of statistic as a PDF " "file. This\n" " will prevent the GUI from opening. You can repeat this " "parameter to save\n" " multiple kinds at once. A list of allowed names can be " "retrieved with\n" " 'aoquality liststats'. Some common ones are: " "StandardDeviation, Variance, Mean,\n" " RFIPercentage, RFIRatio, Count.\n" "\n" "AOQPlot is part of the AOFlagger software package, written by " "André Offringa\n" " (offringa@gmail.com). This AOQPlot belongs to AOFlagger " << AOFLAGGER_VERSION_STR << " (" << AOFLAGGER_VERSION_DATE_STR << ")\n"; return 0; } else if (p == "save") { AOQPlotController::PlotSavingData newPlot; newPlot.filenamePrefix = argv[argi + 1]; newPlot.statisticKind = QualityTablesFormatter::NameToKind(argv[argi + 2]); argi += 2; openGUI = false; savedPlots.push_back(newPlot); } else if (p == "version") { Logger::Info << "AOQplot " << AOFLAGGER_VERSION_STR << " (" << AOFLAGGER_VERSION_DATE_STR << ")\n"; return 0; } else if (p == "v") { Logger::SetVerbosity(Logger::VerboseVerbosity); } else { Logger::Error << "Bad parameter specified: " << argv[argi] << '\n'; return 1; } } else { files.push_back(argv[argi]); } ++argi; } if (openGUI) { const Glib::RefPtr app = Gtk::Application::create( altArgc, argv, "", Gio::APPLICATION_HANDLES_OPEN); window.reset(new AOQPlotWindow(&controller)); window->show_all(); if (files.empty()) { std::string filename; if (SelectFile(*window, filename)) files.push_back(filename); else return 0; } window->Open(files); app->run(*window); } else { Pango::init(); if (files.empty()) { Logger::Error << "No observation specified.\n"; return 1; } controller.ReadStatistics(files); for (const AOQPlotController::PlotSavingData& plot : savedPlots) { controller.Save(plot, 640, 480); } } return 0; } aoflagger-v3.4.0/applications/rfigui.cpp0000644000175000017500000001455514507760372017025 0ustar olesoles#include "../rfigui/rfiguiwindow.h" #include "../rfigui/controllers/imagecomparisoncontroller.h" #include "../rfigui/controllers/rfiguicontroller.h" #include "../util/logger.h" #include "../util/progress/stdoutreporter.h" #include "../imagesets/msimageset.h" #include "../imagesets/msoptions.h" #include #include #include #include #include #include #include #include struct SavedBaseline { size_t a1Index, a2Index, bandIndex, sequenceIndex; std::string filename; bool operator<(const SavedBaseline& rhs) const { return std::tie(a1Index, a2Index, bandIndex, sequenceIndex, filename) < std::tie(rhs.a1Index, rhs.a2Index, rhs.bandIndex, rhs.sequenceIndex, rhs.filename); } }; static void run(int argc, char* argv[]) { int argi = 1; std::vector filenames; std::set savedBaselines; bool interactive = true; std::string dataColumnName = "DATA"; bool plotFlags = true; std::optional intervalStart, intervalEnd; while (argi < argc) { if (argv[argi][0] == '-') { std::string p; if (argv[argi][1] == '-') p = &argv[argi][2]; else p = &argv[argi][1]; if (p == "h" || p == "help" || p == "?") { Logger::Info << "The RFIGui is a program to analyze the time-frequency " "information in radio astronomical observations.\n" << "It is written by André Offringa (offringa@gmail.com) and " "published under the GPL 3.\n" << "This program is part of AOFlagger " << AOFLAGGER_VERSION_STR << " (" << AOFLAGGER_VERSION_DATE_STR << ")\n\n" << "Syntax:\n" << " rfigui [-option1 [-option2 ...]] [measurement set]\n\n" << "The main window will be opened when no parameters are " "specified.\n" << "Possible options:\n" << " -help\n" << " Display this help message and exit.\n" << " -version\n" << " Display AOFlagger version and exit.\n" << " -v\n" << " Verbose logging.\n" << " -save-baseline " "\n" << " Save the selected baseline to the given filename. The " "parameter can be specified\n" << " multiple times to save multiple baselines in one run. When " "this parameter is specified,\n" << " the main window will not open and the program will exit " "after saving the requested baselines.\n" << " -data-column \n" << " Open the selected column name.\n" << " -hide-flags / -show-flags\n" << " Do not (or do) plot the flag mask on top of the data. " "Default: plot them.\n"; return; } else if (p == "version") { Logger::Info << "AOFlagger " << AOFLAGGER_VERSION_STR << " (" << AOFLAGGER_VERSION_DATE_STR << ")\n"; return; } else if (p == "save-baseline") { SavedBaseline sb; sb.filename = argv[argi + 1]; sb.a1Index = atoi(argv[argi + 2]); sb.a2Index = atoi(argv[argi + 3]); sb.bandIndex = atoi(argv[argi + 4]); sb.sequenceIndex = atoi(argv[argi + 5]); savedBaselines.insert(sb); interactive = false; argi += 5; } else if (p == "data-column") { ++argi; dataColumnName = argv[argi]; } else if (p == "hide-flags") { plotFlags = false; } else if (p == "show-flags") { plotFlags = true; } else if (p == "v") { Logger::SetVerbosity(Logger::VerboseVerbosity); } else { Logger::Error << "Unknown parameter " << argv[argi] << " specified on command line.\n"; return; } } else { filenames.push_back(argv[argi]); } ++argi; } // We have to 'lie' about argc to create(..), because of a bug in older // gtkmms. int altArgc = 1; RFIGuiController controller; Glib::RefPtr app; std::unique_ptr window; if (interactive) { app = Gtk::Application::create(altArgc, argv, "", Gio::APPLICATION_HANDLES_OPEN); window = std::make_unique(&controller, argv[0]); window->present(); } try { if (!filenames.empty()) { if (interactive) { window->OpenPaths(filenames); } else { Pango::init(); MSOptions options; options.ioMode = DirectReadMode; options.dataColumnName = dataColumnName; options.combineSPWs = false; options.intervalStart = intervalStart; options.intervalEnd = intervalEnd; options.baselineIntegration.enable = false; controller.OpenMS(filenames, options); } } if (!savedBaselines.empty()) { imagesets::IndexableSet* imageSet = dynamic_cast(&controller.GetImageSet()); if (imageSet == nullptr) throw std::runtime_error( "Option -save-baseline can only be used for measurement sets.\n"); for (const SavedBaseline& b : savedBaselines) { auto index = imageSet->Index(b.a1Index, b.a2Index, b.bandIndex, b.sequenceIndex); if (!index) throw std::runtime_error("Baseline not found!"); controller.SetImageSetIndex(*index); StdOutReporter reporter; controller.LoadCurrentTFDataAsync(reporter); controller.LoadCurrentTFDataFinish(true); MaskedHeatMap& plot = controller.TFController().Plot(); plot.SetShowOriginalMask(plotFlags); plot.SetShowXAxisDescription(true); plot.SetShowYAxisDescription(true); plot.SetShowZAxisDescription(true); plot.SaveByExtension(b.filename, 800, 480); } } if (interactive) app->run(*window); } catch (const std::exception& e) { Logger::Error << "\n" "==========\n" "An unhandled exception occured while executing RFIGui. " "The error is:\n" << e.what() << '\n'; } } int main(int argc, char* argv[]) { run(argc, argv); Glib::Error::register_cleanup(); Glib::wrap_register_cleanup(); return 0; } aoflagger-v3.4.0/applications/aoquality.cpp0000644000175000017500000003171314507760372017543 0ustar olesoles#include #include "../util/plot.h" #include "../quality/operations.h" #include namespace { std::vector AsVector(char* argv[], size_t start, size_t argc) { std::vector result; for (size_t i = start; i != argc; ++i) result.emplace_back(argv[i]); return result; } void printSyntax(std::ostream& stream, char* argv[]) { stream << "Syntax: " << argv[0] << " [options]\n\n" "Possible actions:\n" "\thelp - Get more info about an action (usage: '" << argv[0] << " help ')\n" "\tcollect - Processes the entire measurement set, collects " "the statistics\n" "\t and writes them in the quality tables.\n" "\tcombine - Combine several tables.\n" "\thistogram - Various histogram actions.\n" "\tliststats - Display a list of possible statistic kinds.\n" "\tquery_a - Query per antenna.\n" "\tquery_b - Query per baseline.\n" "\tquery_t - Query per time step.\n" "\tquery_f - Query per frequency.\n" "\tquery_fr - Query a frequency range\n" "\tquery_g - Query single global statistic.\n" "\tremove - Remove all quality tables.\n" "\tsummarize - Give a summary of the statistics currently in the " "quality tables.\n" "\tsummarizerfi- Give a summary of the rfi statistics.\n" "\n\n" "A few actions take a statistic kind. Some common statistic kinds " "are: StandardDeviation,\n" "Variance, Mean, RFIPercentage, RFIRatio, Count. These are case " "sensitive. Run 'aoquality liststats' for a full list.\n"; } void HistogramAction(const std::string& filename, const std::string& query, const char* dataColumnName) { if (query == "rfislope") { quality::PrintRfiSlope(filename); } else if (query == "rfislope-per-baseline") { quality::PrintRfiSlopePerBaseline(filename, dataColumnName); } else if (query == "remove") { quality::RemoveHistogram(filename); } else { std::cerr << "Unknown histogram command: " << query << "\n"; } } } // namespace int main(int argc, char* argv[]) { #ifdef HAS_LOFARSTMAN register_lofarstman(); #endif // HAS_LOFARSTMAN if (argc < 2) { printSyntax(std::cerr, argv); return -1; } else { const std::string action = argv[1]; if (action == "help") { if (argc != 3) { printSyntax(std::cout, argv); } else { const std::string helpAction = argv[2]; if (helpAction == "help") { printSyntax(std::cout, argv); } else if (helpAction == "collect") { std::cout << "Syntax: " << argv[0] << " collect [-d [column]/-tf/-h] [quack timesteps] [list " "of antennae]\n\n" "The collect action will go over a whole measurement set and " "\n" "collect the default statistics. It will write the results in " "the \n" "quality subtables of the main measurement set.\n\n" "Currently, the default statistics are:\n" "\tRFIRatio, Count, Mean, SumP2, DCount, DMean, DSumP2.\n" "The subtables that will be updated are:\n" "\tQUALITY_KIND_NAME, QUALITY_TIME_STATISTIC,\n" "\tQUALITY_FREQUENCY_STATISTIC and " "QUALITY_BASELINE_STATISTIC.\n\n"; } else if (helpAction == "summarize") { std::cout << "Syntax: " << argv[0] << " summarize \n\n" "Gives a summary of the statistics in the measurement set.\n"; } else if (helpAction == "query_a") { std::cout << "Syntax: " << argv[0] << " query_a \n\n" "Prints the given statistic for each antenna.\n"; } else if (helpAction == "query_b") { std::cout << "Syntax: " << argv[0] << " query_b \n\n" "Prints the given statistic for each baseline.\n"; } else if (helpAction == "query_t") { std::cout << "Syntax: " << argv[0] << " query_t \n\n" "Print the given statistic for each time step.\n"; } else if (helpAction == "query_f") { std::cout << "Syntax: " << argv[0] << " query_f \n\n" "Print the given statistic for each frequency.\n"; } else if (helpAction == "query_g") { std::cout << "Syntax " << argv[0] << " query_g \n\n" "Print the given statistic for this measurement set.\n"; } else if (helpAction == "combine") { std::cout << "Syntax: " << argv[0] << " combine [ [ ..]]\n\n" "This will read all given input measurement sets, " "combine the statistics and \n" "write the results to a target measurement set. The " "target measurement set should\n" "not exist beforehand.\n"; } else if (helpAction == "histogram") { std::cout << "Syntax: " << argv[0] << " histogram ]\n\n" "Query can be:\n" "\trfislope - performs linear regression on the part of " "the histogram that should contain the RFI.\n" "\t Reports one value per polarisation.\n"; } else if (helpAction == "remove") { std::cout << "Syntax: " << argv[0] << " remove [ms]\n\n" "This will completely remove all quality tables from " "the measurement set.\n"; } else { std::cerr << "Unknown action specified in help.\n"; return -1; } } } else if (action == "liststats") { quality::ListStatistics(); } else if (action == "collect") { if (argc < 3) { std::cerr << "collect actions needs one or two parameters (the " "measurement set)\n"; return -1; } else { int argi = 2; bool histograms = false, timeFrequency = false; const char* dataColumnName = "DATA"; size_t intervalStart = 0, intervalEnd = 0; while (argi < argc && argv[argi][0] == '-') { const std::string p = &argv[argi][1]; if (p == "h") { histograms = true; } else if (p == "d") { ++argi; dataColumnName = argv[argi]; } else if (p == "tf") { timeFrequency = true; } else if (p == "interval") { intervalStart = atoi(argv[argi + 1]); intervalEnd = atoi(argv[argi + 2]); argi += 2; } else { throw std::runtime_error( "Bad parameter given to aoquality collect"); } ++argi; } const std::string filename = argv[argi]; size_t flaggedTimesteps = 0; ++argi; std::set flaggedAntennae; if (argi != argc) { flaggedTimesteps = atoi(argv[argi]); ++argi; while (argi != argc) { flaggedAntennae.insert(atoi(argv[argi])); ++argi; } } Collector::CollectingMode mode; if (histograms) mode = Collector::CollectHistograms; else if (timeFrequency) mode = Collector::CollectTimeFrequency; else mode = Collector::CollectDefault; quality::CollectStatistics(filename, mode, flaggedTimesteps, std::move(flaggedAntennae), dataColumnName, intervalStart, intervalEnd); } } else if (action == "combine") { if (argc < 3) { std::cerr << "combine actions needs at least one parameter: aoquality " "combine [ ...]\n"; return -1; } else { const std::string outFilename = argv[2]; quality::CombineStatistics(outFilename, AsVector(argv, 3, argc)); } } else if (action == "histogram") { if (argc < 4) { std::cerr << "histogram actions needs at least two parameters (the query and " "the measurement set)\n"; return -1; } else { HistogramAction(argv[3], argv[2], "DATA"); } } else if (action == "summarize") { if (argc < 3) { std::cerr << "summarize actions needs at least one parameter (the " "measurement set)\n"; return -1; } else { quality::PrintSummary(AsVector(argv, 2, argc)); } } else if (action == "summarizerfi") { if (argc < 3) { std::cerr << "summarizerfi actions needs at least one parameter (the " "measurement set)\n"; return -1; } else { quality::PrintRfiSummary(AsVector(argv, 2, argc)); } } else if (action == "query_g") { if (argc < 4) { std::cerr << "Syntax for query global stat: 'aoquality query_g " " [ ...]'\n"; return -1; } else { quality::PrintGlobalStatistic(argv[2], AsVector(argv, 3, argc)); } } else if (action == "query_a") { if (argc < 4) { std::cerr << "Syntax for query antennas: 'aoquality query_a " " [ ...]'\n"; return -1; } else { quality::PrintPerAntennaStatistics(argv[2], AsVector(argv, 3, argc)); return 0; } } else if (action == "query_b") { if (argc < 4) { std::cerr << "Syntax for query baselines: 'aoquality query_b " " [ ...]'\n"; return -1; } else { quality::PrintPerBaselineStatistics(argv[2], AsVector(argv, 3, argc)); } } else if (action == "query_f") { if (argc < 4) { std::cerr << "Syntax for query times: 'aoquality query_t [options] " " [ ...]'\n" "Options:\n" " -downsample \n" " Average down the statistics in frequency to the " "given nr of bins.\n"; return -1; } else { size_t argi = 2; std::optional downsample; while (argv[argi][0] == '-') { const std::string p(&argv[argi][1]); if (p == "downsample") { ++argi; downsample = std::atoi(argv[argi]); } else { throw std::runtime_error("Invalid parameter: " + p); } ++argi; } quality::PrintPerFrequencyStatistics( argv[argi], AsVector(argv, argi + 1, argc), downsample); return 0; } } else if (action == "query_fr") { if (argc == 5) { const std::string range = argv[4]; if (range == "DVB4") { quality::PrintFrequencyRangeStatistic( argv[2], AsVector(argv, 3, argc), 167, 174); } else if (range == "DVB5") { quality::PrintFrequencyRangeStatistic( argv[2], AsVector(argv, 3, argc), 174, 181); } else if (range == "DVB6") { quality::PrintFrequencyRangeStatistic( argv[2], AsVector(argv, 3, argc), 181, 188); } else if (range == "DVB7") { quality::PrintFrequencyRangeStatistic( argv[2], AsVector(argv, 3, argc), 188, 195); } else { std::cerr << "Syntax for query times: 'aoquality query_fr " " '\n"; return -1; } return 0; } else if (argc == 6) { quality::PrintFrequencyRangeStatistic(argv[2], {argv[3]}, atof(argv[4]), atof(argv[5])); return 0; } else { std::cerr << "Syntax for query frequency range: 'aoquality query_fr " " " " '\n"; return -1; } } else if (action == "query_t") { if (argc < 4) { std::cerr << "Syntax for query times: 'aoquality query_t " "[ ...]'\n"; return -1; } else { quality::PrintPerTimeStatistics(argv[2], AsVector(argv, 3, argc)); return 0; } } else if (action == "remove") { if (argc != 3) { std::cerr << "Syntax for removing quality tables: 'aoquality remove '\n"; return -1; } else { quality::RemoveStatistics(argv[2]); return 0; } } else { std::cerr << "Unknown action '" << action << "'.\n\n"; printSyntax(std::cerr, argv); return -1; } return 0; } } aoflagger-v3.4.0/python/0000755000175000017500000000000014516225226013647 5ustar olesolesaoflagger-v3.4.0/python/pyinterface.cpp0000644000175000017500000001523614507760372016701 0ustar olesoles#include "../lua/data.h" #include "../lua/functions.h" #include "pyfunctions.h" #include #include #include namespace py = pybind11; PYBIND11_MODULE(aoflagger, m) { m.doc() = "AOFlagger module for detection of radio-frequency interference"; py::enum_(m, "TelescopeId") .value("Generic", aoflagger::TelescopeId::GENERIC_TELESCOPE) .value("AARTFAAC", aoflagger::TelescopeId::AARTFAAC_TELESCOPE) .value("Arecibo", aoflagger::TelescopeId::ARECIBO_TELESCOPE) .value("Bighorns", aoflagger::TelescopeId::BIGHORNS_TELESCOPE) .value("JVLA", aoflagger::TelescopeId::JVLA_TELESCOPE) .value("LOFAR", aoflagger::TelescopeId::LOFAR_TELESCOPE) .value("MWA", aoflagger::TelescopeId::MWA_TELESCOPE) .value("Parkes", aoflagger::TelescopeId::PARKES_TELESCOPE) .value("WSRT", aoflagger::TelescopeId::WSRT_TELESCOPE); py::class_( m, "ImageSet", "A set of time-frequency 'images' which together contain data for one \n" "correlated baseline or dish. \n" "The class either holds 1, 2, 4 or 8 images. These images have time on " "the \n" "x-axis (most rapidly changing index) and frequency on the y-axis. The \n" "cells specify flux levels, which do not need to have been calibrated. \n" "\n" "If the set contains only one image, it specifies amplitudes of a single " "\n" "polarization. If it contains two images, it specifies the real and " "imaginary \n" "parts of a single polarization. With four images, it contains the real " "\n" "and imaginary values of two polarizations (ordered real pol A, imag pol " "A, \n" "real pol B, imag pol B). With eight images, it contains complex values " "for \n" "four correlated polarizations (ordered real pol A, imag pol A, real pol " "B, \n" "... etc). \n" "\n" "This class wraps the C++ class aoflagger::ImageSet.\n") .def("width", &aoflagger::ImageSet::Width, "Get width (number of time steps) of images") .def("height", &aoflagger::ImageSet::Height, "Get height (number of frequency channels) of images") .def("image_count", &aoflagger::ImageSet::ImageCount, "Get number of images, see class description for details") .def("horizontal_stride", &aoflagger::ImageSet::HorizontalStride) .def("set", &aoflagger::ImageSet::Set, "Set all samples to the specified value") .def("get_image_buffer", aoflagger_python::GetImageBuffer, "Get access to one of the image sets stored in this object. \n" "Returns a numpy double array of ntimes x nchannels.") .def("set_image_buffer", aoflagger_python::SetImageBuffer, "Replace the data of one of the image sets. This function expects\n" "a numpy double array of ntimes x nchannels.") .def("resize_without_reallocation", &aoflagger::ImageSet::ResizeWithoutReallocation); py::class_( m, "FlagMask", "A two-dimensional flag mask.\n\n" "The flag mask specifies which values in an ImageSet are flagged.\n" "A value true means a value is flagged, i.e., contains RFI and should\n" "not be used in further data processing (calibration, imaging, etc.).\n" "A flag denotes that all the value at that time-frequency position " "should\n" "be ignored for all polarizations.\n" "\n" "If polarization-specific flags are needed, one could run the flagger " "on\n" "each polarization individually. However, note that some algorithms, " "like\n" "the morphological scale-invariant rank operator (SIR operator), work " "best\n" "when seeing the flags from all polarizations.\n" "\n" "This class wraps the C++ class aoflagger::FlagMask.") .def("width", &aoflagger::FlagMask::Width, "Get width (number of time steps) of flag mask") .def("height", &aoflagger::FlagMask::Height, "Get height (number of frequency channels) of flag mask") .def("horizontal_stride", &aoflagger::FlagMask::HorizontalStride) .def("get_buffer", aoflagger_python::GetBuffer, "Returns the flag mask as a bool numpy array with dimensions ntimes " "x nchannels.") .def("set_buffer", aoflagger_python::SetBuffer, "Sets the flag mask from a bool numpy array with dimensions ntimes " "x nchannels."); py::class_( m, "Strategy", "Holds a flagging strategy.\n\n" "Telescope-specific flagging strategies can be created with \n" "AOFlagger.make_strategy(), or " "can be loaded from disk with AOFlagger.load_strategy(). Strategies\n" "can not be changed with this interface. A user can create strategies\n" "with the @c rfigui tool that is part of the aoflagger package.") .def("run", aoflagger_python::Run1) .def("run", aoflagger_python::Run2); py::class_(m, "QualityStatistics") .def(py::self += py::self) .def("collect_statistics", &aoflagger::QualityStatistics::CollectStatistics) .def("write_statistics", &aoflagger::QualityStatistics::WriteStatistics); py::class_( m, "AOFlagger", "Main class that gives access to the aoflagger functions.") .def(py::init<>()) .def("make_image_set", aoflagger_python::MakeImageSet1, py::return_value_policy::move) .def("make_image_set", aoflagger_python::MakeImageSet2, py::return_value_policy::move) .def("make_image_set", aoflagger_python::MakeImageSet3, py::return_value_policy::move) .def("make_image_set", aoflagger_python::MakeImageSet4, py::return_value_policy::move) .def("make_flag_mask", aoflagger_python::MakeFlagMask1, py::return_value_policy::move) .def("make_flag_mask", aoflagger_python::MakeFlagMask2, py::return_value_policy::move) .def("find_strategy_file", aoflagger_python::FindStrategyFile1) .def("find_strategy_file", aoflagger_python::FindStrategyFile2) .def("load_strategy_file", aoflagger_python::LoadStrategyFile, py::return_value_policy::move) .def("make_quality_statistics", aoflagger_python::MakeQualityStatistics1, py::return_value_policy::move) .def("make_quality_statistics", aoflagger_python::MakeQualityStatistics2, py::return_value_policy::move) .def_static("get_version_string", &aoflagger::AOFlagger::GetVersionString) .def_static("get_version_date", &aoflagger::AOFlagger::GetVersionDate); } aoflagger-v3.4.0/python/pyfunctions.h0000644000175000017500000000555714507760372016423 0ustar olesoles#ifndef PY_FUNCTION_H #define PY_FUNCTION_H #include "../lua/data.h" #include "../interface/aoflagger.h" #include #include namespace aoflagger_python { pybind11::object get_flag_function(); void set_flag_function(PyObject* callable); pybind11::list polarizations(const aoflagger_lua::Data* data); pybind11::array_t GetImageBuffer(const aoflagger::ImageSet* imageSet, size_t imageIndex); void SetImageBuffer(aoflagger::ImageSet* imageSet, size_t imageIndex, pybind11::array_t& values); pybind11::array_t GetBuffer(const aoflagger::FlagMask* flagMask); void SetBuffer(aoflagger::FlagMask* flagMask, pybind11::array_t& values); pybind11::object MakeImageSet1(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count); pybind11::object MakeImageSet2(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count, size_t widthCapacity); pybind11::object MakeImageSet3(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count, float initialValue); pybind11::object MakeImageSet4(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count, float initialValue, size_t widthCapacity); pybind11::object MakeFlagMask1(aoflagger::AOFlagger* flagger, size_t width, size_t height); pybind11::object MakeFlagMask2(aoflagger::AOFlagger* flagger, size_t width, size_t height, bool initialValue); pybind11::object FindStrategyFile1(aoflagger::AOFlagger* flagger, enum aoflagger::TelescopeId telescopeId); pybind11::object FindStrategyFile2(aoflagger::AOFlagger* flagger, enum aoflagger::TelescopeId telescopeId, const char* scenario); pybind11::object LoadStrategyFile(aoflagger::AOFlagger* flagger, const char* filename); pybind11::object Run1(aoflagger::Strategy* strategy, const aoflagger::ImageSet& input); pybind11::object Run2(aoflagger::Strategy* strategy, const aoflagger::ImageSet& input, const aoflagger::FlagMask& existingFlags); pybind11::object MakeQualityStatistics1( aoflagger::AOFlagger* flagger, pybind11::array_t& scanTimes, pybind11::array_t& channelFrequencies, size_t nPolarizations, bool computeHistograms); pybind11::object MakeQualityStatistics2( aoflagger::AOFlagger* flagger, pybind11::array_t& scanTimes, pybind11::array_t& channelFrequencies, size_t nPolarizations); }; // namespace aoflagger_python #endif aoflagger-v3.4.0/python/pyfunctions.cpp0000644000175000017500000002157414507760372016753 0ustar olesoles#include "pyfunctions.h" #include #include namespace py = pybind11; namespace aoflagger_python { py::array_t GetImageBuffer(const aoflagger::ImageSet* imageSet, size_t imageIndex) { if (imageIndex >= imageSet->ImageCount()) throw std::out_of_range( "aoflagger.get_image_buffer: Image index out of bounds"); const float* values = imageSet->ImageBuffer(imageIndex); py::buffer_info buf = py::buffer_info( nullptr, // ask NumPy to allocate sizeof(double), py::format_descriptor::value, 2, {ptrdiff_t(imageSet->Height()), ptrdiff_t(imageSet->Width())}, {sizeof(double) * imageSet->Width(), sizeof(double)} /* Strides for each dimension */ ); py::array_t result(buf); buf = result.request(); char* resultData = (char*)buf.ptr; const int stride0 = buf.strides[0]; const int stride1 = buf.strides[1]; for (size_t y = 0; y != imageSet->Height(); ++y) { const float* rowOut = values + y * imageSet->HorizontalStride(); char* rowIn = resultData + y * stride0; for (size_t x = 0; x != imageSet->Width(); ++x) { *reinterpret_cast(rowIn + x * stride1) = rowOut[x]; } } return result; } void SetImageBuffer(aoflagger::ImageSet* imageSet, size_t imageIndex, py::array_t& values) { if (imageIndex >= imageSet->ImageCount()) throw std::out_of_range( "aoflagger.get_image_buffer: Image index out of bounds"); if (values.ndim() != 2) throw std::runtime_error( "ImageSet.set_image_buffer(): require a two-dimensional array"); if (values.shape(0) != int(imageSet->Height()) || values.shape(1) != int(imageSet->Width())) throw std::runtime_error( "ImageSet.set_image_buffer(): dimensions of provided array doesn't " "match with image set"); const py::buffer_info buf = values.request(); const int stride0 = buf.strides[0]; const int stride1 = buf.strides[1]; const char* data = static_cast(buf.ptr); if (!data) throw std::runtime_error( "Data needs to be provided that is interpretable as a double array"); float* buffer = imageSet->ImageBuffer(imageIndex); for (size_t y = 0; y != imageSet->Height(); ++y) { const char* rowIn = data + y * stride0; float* rowOut = buffer + y * imageSet->HorizontalStride(); for (size_t x = 0; x != imageSet->Width(); ++x) { rowOut[x] = *reinterpret_cast(rowIn + x * stride1); } } } py::array_t GetBuffer(const aoflagger::FlagMask* flagMask) { const bool* values = flagMask->Buffer(); py::buffer_info buf = py::buffer_info( nullptr, // ask NumPy to allocate sizeof(bool), py::format_descriptor::value, 2, {ptrdiff_t(flagMask->Height()), ptrdiff_t(flagMask->Width())}, {sizeof(bool) * flagMask->Width(), sizeof(bool)} /* Strides for each dimension */ ); py::array_t result(buf); buf = result.request(); char* resultData = static_cast(buf.ptr); const int stride0 = buf.strides[0]; const int stride1 = buf.strides[1]; for (size_t y = 0; y != flagMask->Height(); ++y) { const bool* rowOut = values + y * flagMask->HorizontalStride(); char* rowIn = resultData + y * stride0; for (size_t x = 0; x != flagMask->Width(); ++x) { *reinterpret_cast(rowIn + x * stride1) = rowOut[x]; } } return result; } void SetBuffer(aoflagger::FlagMask* flagMask, pybind11::array_t& values) { if (values.ndim() != 2) throw std::runtime_error( "FlagMask.set_buffer(): Invalid dimensions specified for data array; " "two dimensional array required"); if (values.shape(0) != int(flagMask->Height()) || values.shape(1) != int(flagMask->Width())) throw std::runtime_error( "FlagMask.set_buffer(): dimensions of provided array don't match with " "image set"); py::buffer_info buf = values.request(); const char* data = static_cast(buf.ptr); if (!data) throw std::runtime_error( "Data needs to be provided that is interpretable as a bool array"); bool* buffer = flagMask->Buffer(); const int stride0 = buf.strides[0]; const int stride1 = buf.strides[1]; for (size_t y = 0; y != flagMask->Height(); ++y) { const char* rowIn = data + y * stride0; bool* rowOut = buffer + y * flagMask->HorizontalStride(); for (size_t x = 0; x != flagMask->Width(); ++x) { rowOut[x] = *reinterpret_cast(rowIn + x * stride1); } } } py::object MakeImageSet1(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count) { return py::cast(flagger->MakeImageSet(width, height, count)); } py::object MakeImageSet2(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count, size_t widthCapacity) { return py::cast(flagger->MakeImageSet(width, height, count, widthCapacity)); } py::object MakeImageSet3(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count, float initialValue) { return py::cast(flagger->MakeImageSet(width, height, count, initialValue)); } py::object MakeImageSet4(aoflagger::AOFlagger* flagger, size_t width, size_t height, size_t count, float initialValue, size_t widthCapacity) { return py::cast( flagger->MakeImageSet(width, height, count, initialValue, widthCapacity)); } py::object MakeFlagMask1(aoflagger::AOFlagger* flagger, size_t width, size_t height) { return py::cast(flagger->MakeFlagMask(width, height)); } py::object MakeFlagMask2(aoflagger::AOFlagger* flagger, size_t width, size_t height, bool initialValue) { return py::cast(flagger->MakeFlagMask(width, height, initialValue)); } py::object FindStrategyFile1(aoflagger::AOFlagger* flagger, enum aoflagger::TelescopeId telescopeId) { return FindStrategyFile2(flagger, telescopeId, ""); } py::object FindStrategyFile2(aoflagger::AOFlagger* flagger, enum aoflagger::TelescopeId telescopeId, const char* scenario) { const std::string path = flagger->FindStrategyFile(telescopeId, std::string(scenario)); if (path.empty()) throw std::runtime_error( "find_strategy(): Could not find requested strategy"); return py::cast(path); } py::object LoadStrategyFile(aoflagger::AOFlagger* flagger, const char* filename) { return py::cast(flagger->LoadStrategyFile(std::string(filename)), py::return_value_policy::move); } py::object Run1(aoflagger::Strategy* strategy, const aoflagger::ImageSet& input) { return py::cast(strategy->Run(input)); } py::object Run2(aoflagger::Strategy* strategy, const aoflagger::ImageSet& input, const aoflagger::FlagMask& existingFlags) { return py::cast(strategy->Run(input, existingFlags)); } py::object MakeQualityStatistics1(aoflagger::AOFlagger* flagger, py::array_t& scanTimes, py::array_t& channelFrequencies, size_t nPolarizations, bool computeHistograms) { if (scanTimes.ndim() != 1) throw std::runtime_error( "AOFlagger.make_quality_statistics(): Invalid dimensions specified for " "scanTimes array; one dimensional array required"); const size_t nScans = scanTimes.shape(0); const py::buffer_info tbuf = scanTimes.request(); const double* scanTimesArr = reinterpret_cast(tbuf.ptr); if (!scanTimesArr) throw std::runtime_error( "scanTimes data needs to be provided that is interpretable as a double " "array"); if (channelFrequencies.ndim() != 1) throw std::runtime_error( "AOFlagger.make_quality_statistics(): Invalid dimensions specified for " "channelFrequencies array; one dimensional array required"); const size_t nChannels = channelFrequencies.shape(0); const py::buffer_info fbuf = scanTimes.request(); const double* channelFrequenciesArr = reinterpret_cast(fbuf.ptr); if (!channelFrequenciesArr) throw std::runtime_error( "Data needs to be provided that is interpretable as a double array"); return py::cast(flagger->MakeQualityStatistics( scanTimesArr, nScans, channelFrequenciesArr, nChannels, nPolarizations, computeHistograms)); } py::object MakeQualityStatistics2(aoflagger::AOFlagger* flagger, py::array_t& scanTimes, py::array_t& channelFrequencies, size_t nPolarizations) { return MakeQualityStatistics1(flagger, scanTimes, channelFrequencies, nPolarizations, false); } } // namespace aoflagger_python aoflagger-v3.4.0/python/pythonstrategy.cpp0000644000175000017500000000343614507760372017473 0ustar olesoles#include "pythonstrategy.h" #include "../lua/data.h" #include "../lua/functions.h" #include "../python/pyfunctions.h" #include #include #include #include PythonStrategy::PythonStrategy() : _code() { std::ifstream file("strategy.py"); if (file.good()) { file.seekg(0, std::ios::end); const size_t size = file.tellg(); std::vector data(size + 1, 0); file.seekg(0, std::ios::beg); file.read(data.data(), size); _code = data.data(); } Py_Initialize(); // The following statement add the curr path to the Python search path const std::filesystem::path workingDir = std::filesystem::canonical(std::filesystem::current_path()); PyObject* sysPath = PySys_GetObject(const_cast("path")); PyList_Insert(sysPath, 0, PyUnicode_FromString(workingDir.string().c_str())); } PythonStrategy::~PythonStrategy() { Py_Finalize(); } void PythonStrategy::Execute(TimeFrequencyData& tfData, TimeFrequencyMetaDataCPtr metaData, class ScriptData& scriptData) { /* pybind11::object global(pybind11::module::import("__main__").attr("__dict__")); // exec requires a recent pybind11 version ! pybind11::exec(_code.c_str(), global); pybind11::object flagFunction = aoflagger_python::get_flag_function(); if(flagFunction.is_none()) throw std::runtime_error("Incorrect Python strategy: strategy did not provide a flag method. Make sure your strategy uses aoflagger.set_flag_function() to provide the flag function to the caller"); else { aoflagger_lua::Data::Context context; aoflagger_lua::Data data(tfData, metaData, context); flagFunction(std::ref(data)); tfData = data.TFData(); } */ } aoflagger-v3.4.0/python/pythonstrategy.h0000644000175000017500000000063014507760372017131 0ustar olesoles#ifndef PYTHON_STRATEGY_H #define PYTHON_STRATEGY_H #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include class PythonStrategy { public: PythonStrategy(); ~PythonStrategy(); void Execute(TimeFrequencyData& tfData, TimeFrequencyMetaDataCPtr metaData, class ScriptData& scriptData); private: std::string _code; }; #endif aoflagger-v3.4.0/python/CMakeLists.txt0000644000175000017500000000054614507760372016422 0ustar olesolespybind11_add_module(python_aoflagger MODULE pyinterface.cpp pyfunctions.cpp) set_target_properties(python_aoflagger PROPERTIES SOVERSION 0) set_target_properties(python_aoflagger PROPERTIES OUTPUT_NAME "aoflagger") target_link_libraries( python_aoflagger PUBLIC aoflagger-lib PUBLIC ${ALL_LIBRARIES}) install(TARGETS python_aoflagger DESTINATION lib) aoflagger-v3.4.0/.gitmodules0000644000175000017500000000032414507760372014510 0ustar olesoles[submodule "external/aocommon"] path = external/aocommon url = https://gitlab.com/aroffringa/aocommon.git [submodule "external/pybind11"] path = external/pybind11 url = https://github.com/pybind/pybind11.git aoflagger-v3.4.0/Doxyfile.in0000644000175000017500000030374214507760372014460 0ustar olesoles# Doxyfile 1.8.7 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "AOFlagger" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = YES # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See # also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = @CMAKE_CURRENT_SOURCE_DIR@/interface/aoflagger.h @CMAKE_CURRENT_SOURCE_DIR@/interface/interface.dox # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.h \ *.dox # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , / - 1 - 1 + 1.5 + 1.5 1 1 0 This shows that the sensitivity (both time and frequency direction) of the SumThreshold actions were changed from 1 to 1.5. In the old ``.rfis`` strateges, the sensitivity values are specified every time an action is executed. Because the SumThresholdAction occurs two times, there are two different places in the ``.rfis`` file. This is not the case for Lua files: in Lua, one can define variables, and the default strategy makes use of this. It lists the most commonly used parameters near the start of the Lua file, and changing the sensitivity of the SumThreshold step can be done simply by changing the base_threshold variable from its default: .. code-block:: lua local base_threshold = 1.0 -- lower means more sensitive detection to: .. code-block:: lua local base_threshold = 1.5 -- lower means more sensitive detection aoflagger-v3.4.0/doc/source/installation-redhat.rst0000644000175000017500000000743414507760372021111 0ustar olesolesInstallation on Redhat ====================== This page describes installing AOFlagger 2.14 on RHEL 7.6 (Thanks to Leonardo Saavedra from NRAO) aoflagger depends on many packages, most of then are provided by RHEL 7.6, but you will need to install the modern version of them. In particular: **fftw** and **boost** * https://gitlab.com/aroffringa/aoflagger * http://www.fftw.org * https://github.com/casacore/casacore * https://www.boost.org/ Install RPMs ------------ You need install hdf from epel (or install from the sources as detailed below), so you need to set EPEL repo. .. code-block :: bash yum install hdf hdf-devel yum install gtkmm30 gtkmm30-devel Set environment --------------- .. code-block :: bash mkdir ~/Downloads2/aoflagger cd ~/Downloads2/aoflagger wget -c http://www.fftw.org/fftw-3.3.8.tar.gz wget -c https://github.com/casacore/casacore/archive/v3.1.1.tar.gz wget -c https://sourceforge.net/projects/aoflagger/files/aoflagger-2.14.0/aoflagger-2.14.0.tar.bz2 wget -c https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz LOCAL5=/opt/local5 Install FFTW 3.3.8 ------------------ .. code-block :: bash tar xzvf fftw-3.3.8.tar.gz cd fftw-3.3.8/ ./configure --prefix=${LOCAL5} --enable-threads --enable-openmp --enable-shared make -j `nproc` make install cd .. Install Casacore 3.3.1 ---------------------- Set new environment ^^^^^^^^^^^^^^^^^^^ .. code-block :: bash export LD_LIBRARY_PATH=${LOCAL5}/lib:$LD_LIBRARY_PATH export PATH=$PATH:${LOCAL5}/bin .. code-block :: bash tar xzvf v3.1.1.tar.gz cd casacore-3.1.1/ mkdir build cd build cmake ../ -DCMAKE_PREFIX_PATH=${LOCAL5} make -j `nproc` make install vim cmake_install.cmake <-- modified CMAKE_INSTALL_PREFIX to point to ${LOCAL5} make install Install boost 1.68 ------------------ Previous to compile boost, you have to make sure that your python installation uses a 4-byte representation for Unicode characters. To check that, you can run the following script, if it reports 'UCS2 Build', you have to either install a new python or use other python version. https://docs.python.org/2/faq/extending.html#can-i-create-an-object-class-with-some-methods-implemented-in-c-and-others-in-python-e-g-through-inheritance .. code-block :: bash python cat CheckUnide.py import sys if sys.maxunicode > 65535: print ('UCS4 Build') else: print ('UCS2 Build') .. code-block :: bash python CheckUnide.py UCS4 Build .. code-block :: bash tar xzvf boost_1_68_0.tar.gz cd boost_1_68_0 ./bootstrap.sh --with-python=python --prefix=${LOCAL5} --with-icu ./b2 ./b2 link=shared install --prefix=${LOCAL5} (cd ${LOCAL5}/lib ; ln -s libboost_python27.so libboost_python.so) cd .. Install HDF5 ------------ This is optional, you can skip if you have hdf5 from Epel. Download hdf-1.10.5.tar from https://www.hdfgroup.org/downloads/hdf5/source-code/ .. code-block :: bash ./configure --enable-cxx --with-szlib --enable-shared --enable-hl --disable-silent-rules --enable-fortran --enable-fortran2003 --prefix=${LOCAL5} make -j `nproc` make check make install make installcheck Install AOFlagger 2.14 ---------------------- .. code-block :: bash tar xjvf aoflagger-2.14.0.tar.bz2 cd aoflagger-2.14.0 mkdir build cd build cmake ../ -DCMAKE_PREFIX_PATH=${LOCAL5} -DCMAKE_INSTALL_PREFIX={LOCAL5} make -j `nproc` vim cmake_install.cmake <-- modified (or make sure) CMAKE_INSTALL_PREFIX point to ${LOCAL5} make install Check aoflagger version ----------------------- .. code-block :: bash which python /opt/local5/bin/python aoflagger --version AOFlagger 2.14.0 (2019-02-14) aoflagger-v3.4.0/doc/source/strategy_options.rst0000644000175000017500000000532214507760372020552 0ustar olesolesStrategy option list ==================== .. default-domain:: lua The following table lists all the options that can be set when implementing the :meth:`options` function. ============================ ======= =========== option type description ============================ ======= =========== bands table List of integer (zero-indexed) band ids to process. baselines string ``"auto"``, ``"cross"`` or ``"all"`` for selecting auto/cross-correlations or both. baseline-integration string Average baselines together to a single dynamic spectrum, with a specified method. Allowed values are: ``"count"``, ``"average"``, ``"average-abs"``, ``"squared"`` or ``"stddev"``. chunk-size integer When not zero, ``aoflagger`` will process the data in chunks with the given maximum chunk size. column-name string What data column to use, e.g. ``"DATA"``, ``"CORRECTED_DATA"``. etc. combine-spws boolean Whether to concatenate all spectral windows together while flagging. execute-file string Name of file to load for this run, which should provide the execute-function. By default, it is assumed to be the currently loaded file (which also provides the :meth:`options` call). execute-function string Name of function to run (note this is a string, not a function). Default: ``"execute"``. fields table List of integer (zero-indexed) field ids to process. files table List of strings that are the names of the files to process. min‑aoflagger-version string Minimum AOFlagger version required, of the form "major.minor". Defaults to ``"3.0"``. quiet boolean Inhibits all output except errors. read-mode string ``"direct"``, ``"indirect"``, ``"memory"`` or ``"auto"``. read-uvws boolean Whether to read the UVWs. This is not done by default. script-version string Version of this strategy. Can have the form "major.minor[.subminor] [extra description]", for example ``"2.4 beta"`` or ``"3.1.4 modified by André"``. start-timestep /end-timestep integer Timestep (zero-indexed) from/at which to start/end processing. threads integer Number of threads to use. The default is to use one thread per core. verbose boolean Sets verbose logging. ============================ ======= =========== aoflagger-v3.4.0/doc/source/script_example.rst0000644000175000017500000001205014507760372020150 0ustar olesolesExample script ============== .. default-domain:: lua This section demonstrates a simple example script. Copying the script below into the ``rfigui`` Lua editor will allow you to interactively change this script. .. code-block:: lua function execute(data) data:clear_mask() for _,polarization in ipairs(data:get_polarizations()) do local pol_data = data:convert_to_polarization(polarization) pol_data = pol_data:convert_to_complex("amplitude") aoflagger.high_pass_filter(pol_data, 51, 51, 3, 3) aoflagger.visualize(pol_data, "Low-pass filtered", 0) aoflagger.sumthreshold(pol_data, 1, 1, true, true) aoflagger.scale_invariant_rank_operator(pol_data, 0.2, 0.2) pol_data = pol_data:convert_to_complex("complex") data:set_polarization_data(polarization, pol_data) end -- end of polarization iterations end We will discuss this script line by line. When AOFlagger calls the ``execute()`` function, the script starts by calling :meth:`Data.clear_mask`, which unsets all flags: .. code-block:: lua function execute(data) data:clear_mask() If the input data was already flagged, these flags are removed. The next step is a ``for`` loop over the different polarizations in the set: .. code-block:: lua for _,polarization in ipairs(data:get_polarizations()) do Almost any flagging script will need such a loop, because most operations can only work on a single polarization. The input data could consist of 1-4 linear polarizations (XX, XY, YX, YY), circular polarizations (LL, LR, RL, RR) or Stokes polarizations (I, Q, U, V). :meth:`Data.get_polarizations()` returns a table of strings, and ``ipairs`` converts this to an iterator. A loop over a table captures an (index, value) pair. In this case we only need the value (``polarization``), and ignore the index with the underscore. To work on a single polarization only, :meth:`Data.convert_to_polarization` is used to create a new data object that contains just that single polarization: .. code-block:: lua local pol_data = data:convert_to_polarization(polarization) The new object is stored as ``local`` variable. In Lua, any variable that is not declared as ``local``, is a global. This might cause the data to be stored longer than necessary, causing more memory usage, so local variables should be preferred. [1]_ Most input data sets are complex. Thresholding is more effective on the amplitudes of the samples though. Function ``Data.convert_to_complex`` is used to calculate the amplitudes: .. code-block:: lua pol_data = pol_data:convert_to_complex("amplitude") Another new object is created, but the previous ``pol_data`` object is overwritten. The next step is high-pass filtering the data: .. code-block:: lua aoflagger.high_pass_filter(pol_data, 51, 51, 3, 3) Function :meth:`aoflagger.high_pass_filter` filters the visibility data in `pol_data`. A kernel of 51 x 51 samples is used (ntimes x nchannels), with a Gaussian width of 3 samples in both directions. The filtered data is "visualized" with function :meth:`aoflagger.visualize`: .. code-block:: lua aoflagger.visualize(pol_data, "Low-pass filtered", 0) This statement makes it possible to display the result of filtering the data in ``rfigui``. When the script is not running interactively from a gui, the call is ignored. Note that ``visualize()`` will be called for all polarizations. The gui will recombine visualizations from different polarizations, as long as they have the same name and sorting index. The :meth:`aoflagger.sumthreshold` searches the (filtered) data for consecutive high values in time or frequency: .. code-block:: lua aoflagger.sumthreshold(pol_data, 1, 1, true, true) The resulting ``pol_data`` object will now contain a flag mask. This flag mask is morphologically extended in the time and frequency direction with the :meth:`aoflagger.scale_invariant_rank_operator` function: .. code-block:: lua aoflagger.scale_invariant_rank_operator(pol_data, 0.2, 0.2) Finally, the data are converted back to its original form, so that the polarizations can be combined. The first step is to convert the data back to complex values using :meth:`Data.convert_to_complex`: .. code-block:: lua pol_data = pol_data:convert_to_complex("complex") This "conversion" can be seen as an update of the metadata. The phases were lost while converting to amplitudes, so these are not restored, and just assumed to be constant. The ``pol_data`` now holds a complex data and our new flag mask. The last step is to update the input data with our new data using :meth:`Data.set_polarization_data`: .. code-block:: lua data:set_polarization_data(polarization, pol_data) By iterating over all polarizations in the input set, the polarizations in the input data object are replaced one by one. .. [1] Data objects are emptied by AOFlagger at the end of the ``execute()`` function, so the user should normally not worry about memory usage. aoflagger-v3.4.0/doc/source/introduction.rst0000644000175000017500000000520514507760372017656 0ustar olesolesIntroduction ============ AOFlagger makes it possible to detect radio-frequency interference in radio-observations. In this process, often called "flagging" the data, samples that are contaminated by interference are marked. As shown by the figure below, the frequencies covered by telescopes like LOFAR and the MWA are considerably affected by radio-frequency interference (RFI). Efficient RFI detection is essential to obtain high quality images. .. image:: images/LOFAR-rfi-spectrum.png :alt: LOFAR RFI spectrum The AOFlagger software is aimed at being a fast and accurate flagger. Implemented algorithms such as the SumThreshold method, background fitting techniques (smoothing, sliding window, median filters, high-pass filters) and morphological operators can be combined into strategy scripts. These are written in the `Lua language `_. The default strategy performs well on a wide range of telescope observations. Further tweaking to accomodate for specific features of a telescope can sometimes improve the results. The software consists of the flagger library (``libaoflagger``) that can be integrated into observatory pipelines by using the Application Programming Interface (API). It also provides several programs to execute the flagger on measurement sets, tweak strategies and visualize results. Tools are provided that can for example plot time-frequency diagrams and power spectra, both interactively or from scripts. The two main programs are :doc:`aoflagger ` and :doc:`rfigui `. Furthermore, aoqplot can be used to visualize plots (:doc:`interactively ` or :doc:`scripted `). The API is available as for programs written in C++ and Python. AOFlagger is used by default for the LOFAR, MWA and Apertif radio telescope. The software can run in a fully automated way, but a graphical interface (rfigui) is provided to analyse results and tweak the strategy. The preferred input file format is the Casa Measurement Set (MS) format, but single dish SDFits files are also supported. I believe that the AOFlagger is the best available flagger, both in terms of accuracy and speed. It has been succesfully used on several interferometric telescopes, including LOFAR, WSRT, Apertif, VLA, GMRT, ATCA and MWA, and the single-dish telescopes Parkes and Arecibo 305m. History ^^^^^^^ The AOFlagger was originally written as part of my PhD thesis for the LOFAR Epoch of Reionization key science project, which needed a fast flagger with high accuracy. Since then it was made more generic and functionality was added to work on data from other observatories and at other frequency ranges. aoflagger-v3.4.0/doc/source/index.rst0000644000175000017500000000152014507760372016240 0ustar olesolesAOFlagger manual ================ This is the manual for the AOFlagger software suite. The AOFlagger software can find and remove radio-frequency interference (RFI) in radio astronomical observations. The Lua language is used for writing flexible flagging strategies. The tools are applicable to a wide range of telescopes. Contents: .. toctree:: :maxdepth: 2 introduction getting_started usage designing_strategies python_interface cpp_interface further_information changelogs/list.rst Other sources of information: * `AOFlagger on Gitlab `_ * `Debian AOFlagger tracker `_ * `The LOFAR cookbook `_ for LOFAR-specific info Navigate -------- * :ref:`genindex` * :ref:`search` aoflagger-v3.4.0/doc/Makefile0000644000175000017500000000117614507760372014546 0ustar olesoles# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = source BUILDDIR = build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) aoflagger-v3.4.0/util/0000755000175000017500000000000014516225226013303 5ustar olesolesaoflagger-v3.4.0/util/types.h0000644000175000017500000000013414507760372014624 0ustar olesoles#ifndef UTIL_TYPES_H #define UTIL_TYPES_H class ProgressListener; #endif // UTIL_TYPES_H aoflagger-v3.4.0/util/logger.h0000644000175000017500000000473014507760372014745 0ustar olesoles#ifndef AOFLAGGER #define AOFLAGGER #include #include #include class Logger { public: enum LoggerLevel { NoLevel = 5, FatalLevel = 4, ErrorLevel = 3, WarningLevel = 2, InfoLevel = 1, DebugLevel = 0 }; enum VerbosityLevel { QuietVerbosity, NormalVerbosity, VerboseVerbosity }; template class LogWriter { public: LogWriter() : _atNewLine(true) {} LogWriter& operator<<(const std::string& str) { boost::mutex::scoped_lock lock(_mutex); size_t start = 0, end; while (std::string::npos != (end = str.find('\n', start))) { outputLinePart(str.substr(start, end - start + 1), true); start = end + 1; } outputLinePart(str.substr(start, str.size() - start), false); return *this; } LogWriter& operator<<(const char* str) { (*this) << std::string(str); return *this; } LogWriter& operator<<(const char c) { boost::mutex::scoped_lock lock(_mutex); outputLinePart(std::string(1, c), c == '\n'); return *this; } template LogWriter& operator<<(const S& str) { std::ostringstream stream; stream << str; (*this) << stream.str(); return *this; } void Flush() { boost::mutex::scoped_lock lock(_mutex); if (ToStdErr) std::cerr.flush(); else std::cout.flush(); } private: boost::mutex _mutex; bool _atNewLine; void outputLinePart(const std::string& str, bool endsWithCR) { if ((int)_coutLevel <= (int)Level && !str.empty()) { if (_atNewLine && _logTime) outputTime(ToStdErr); if (ToStdErr) std::cerr << str; else std::cout << str; _atNewLine = endsWithCR; } } }; static void SetVerbosity(VerbosityLevel verbosityLevel); static bool IsVerbose() { return _coutLevel == DebugLevel; } static void SetLogTime(bool logTime) { _logTime = logTime; } static bool LogTime() { return _logTime; } static class LogWriter Debug; static class LogWriter Info; static class LogWriter Warn; static class LogWriter Error; static class LogWriter Fatal; static class LogWriter Progress; private: Logger() {} static void outputTime(bool toStdErr); static enum LoggerLevel _coutLevel; static bool _logTime; }; #endif aoflagger-v3.4.0/util/stopwatch.cpp0000644000175000017500000000734214507760372016037 0ustar olesoles#include "stopwatch.h" #include #include #include Stopwatch::Stopwatch() : _running(false), _sum(boost::posix_time::seconds(0)) {} Stopwatch::Stopwatch(bool start) : _running(start), _startTime(boost::posix_time::microsec_clock::local_time()), _sum(boost::posix_time::seconds(0)) {} Stopwatch::~Stopwatch() {} void Stopwatch::Start() { if (!_running) { _startTime = boost::posix_time::microsec_clock::local_time(); _running = true; } } void Stopwatch::Pause() { if (_running) { _sum += (boost::posix_time::microsec_clock::local_time() - _startTime); _running = false; } } void Stopwatch::Reset(bool start) { _running = false; _sum = boost::posix_time::seconds(0); if (start) Start(); } std::string Stopwatch::ToString() const { if (_running) { const boost::posix_time::time_duration current = _sum + (boost::posix_time::microsec_clock::local_time() - _startTime); return to_simple_string(current); } else { return to_simple_string(_sum); } } std::string Stopwatch::ToShortString() const { const long double seconds = Seconds(); if (seconds >= 60 * 60 * 24) return ToDaysString(); else if (seconds >= 60 * 60) return ToHoursString(); else if (seconds >= 60) return ToMinutesString(); else if (seconds >= 1.0) return ToSecondsString(); else if (seconds >= 0.001) return ToMilliSecondsString(); else if (seconds >= 0.000001) return ToMicroSecondsString(); else return ToNanoSecondsString(); } std::string Stopwatch::ToDaysString() const { const long double days = roundl(Seconds() / (60.0 * 60.0)) / 24.0; std::stringstream str; if (days >= 10.0) str << roundl(days) << " days"; else str << floorl(days) << 'd' << (days * 24.0) << 'h'; return str.str(); } std::string Stopwatch::ToHoursString() const { const long double hours = roundl(Seconds() / 60.0) / 60.0; std::stringstream str; if (hours >= 10.0) str << roundl(hours) << 'h'; else str << floorl(hours) << 'h' << (hours * 60.0) << 'm'; return str.str(); } std::string Stopwatch::ToMinutesString() const { const long double mins = roundl(Seconds()) / 60.0; std::stringstream str; if (mins >= 10.0) str << roundl(mins) << " min"; else str << floorl(mins) << 'm' << fmod(mins * 60.0, 60.0) << 's'; return str.str(); } std::string Stopwatch::ToSecondsString() const { const long double seconds = roundl(Seconds() * 10.0) / 10.0; std::stringstream str; if (seconds >= 10.0) str << roundl(Seconds()) << 's'; else str << seconds << 's'; return str.str(); } std::string Stopwatch::ToMilliSecondsString() const { const long double msec = roundl(Seconds() * 10000.0) / 10.0; std::stringstream str; if (msec >= 10.0) str << roundl(Seconds() * 1000.0) << "ms"; else str << msec << "ms"; return str.str(); } std::string Stopwatch::ToMicroSecondsString() const { const long double usec = roundl(Seconds() * 10000000.0) / 10.0; std::stringstream str; if (usec >= 10.0) str << roundl(Seconds() * 1000000.0) << "µs"; else str << usec << "µs"; return str.str(); } std::string Stopwatch::ToNanoSecondsString() const { const long double nsec = roundl(Seconds() * 10000000000.0) / 10.0; std::stringstream str; if (nsec >= 10.0) str << roundl(Seconds() * 1000000000.0) << "ns"; else str << nsec << "ns"; return str.str(); } long double Stopwatch::Seconds() const { if (_running) { const boost::posix_time::time_duration current = _sum + (boost::posix_time::microsec_clock::local_time() - _startTime); return (long double)current.total_milliseconds() / 1000.0; } else { return (long double)_sum.total_milliseconds() / 1000.0; } } aoflagger-v3.4.0/util/numberparser.h0000644000175000017500000001015614507760372016172 0ustar olesoles#include #include #include #ifndef HAVE_EXP10 #define exp10(x) exp((2.3025850929940456840179914546844) * (x)) #endif class NumberParsingException : public std::runtime_error { public: explicit NumberParsingException(const std::string& str) : std::runtime_error(std::string("Failed to parse number: ") + str) {} }; /** * This class implements functions that copy the behaviour of atof and strtod, * etc. Unfortunately, atof are locale-dependent and e.g. a Dutch machine will * interpret a decimal point differently. This is undesirable, hence the * reimplementation here. * TODO can be replaced by std::from_chars() once C++17 is used. */ class NumberParser { public: /** * @throws NumberParsingException when @c str can not be parsed. */ static double ToDouble(const char* str) { return toNumber(str); } /** * @throws NumberParsingException when @c str can not be parsed. */ static short ToShort(const char* str) { return toSignedInteger(str); } private: /** * @throws NumberParsingException when @c str can not be parsed. */ template static T toNumber(const char* str) { if (*str == 0) throw NumberParsingException("Supplied string is empty"); // Read optional sign bool isNegative; if (isNegativeSymbol(*str)) { isNegative = true; ++str; } else if (isPositiveSymbol(*str)) { isNegative = false; ++str; } else { isNegative = false; } // Read everything before decimal point if (!isDigit(*str)) throw NumberParsingException( "Number did not start with digits after optional sign symbol"); T val = (T)((*str) - '0'); ++str; while (isDigit(*str)) { val = val * 10.0 + (T)((*str) - '0'); ++str; } // Skip decimal point if given if (isDecimalPoint(*str)) ++str; // Read decimals T currentValue = 0.1; while (isDigit(*str)) { val += currentValue * (T)((*str) - '0'); currentValue /= 10.0; ++str; } // Read optional exponent if (isExponentSymbol(*str)) { ++str; try { short e = ToShort(str); val = val * intPow10(e); } catch (NumberParsingException& e) { throw NumberParsingException("Could not parse exponent"); } } // If there was an exponent, ToShort has checked for garbage at the end and // str is not updated, otherwise we still need to check that... else if (*str != 0) throw NumberParsingException( "The number contains invalid characters after its digits"); if (isNegative) return -val; else return val; } /** * @throws NumberParsingException when @c str can not be parsed. */ template static T toSignedInteger(const char* str) { if (*str == 0) throw NumberParsingException("Supplied string is empty"); // Read optional sign bool isNegative; if (isNegativeSymbol(*str)) { isNegative = true; ++str; } else if (isPositiveSymbol(*str)) { isNegative = false; ++str; } else { isNegative = false; } // Read digits if (!isDigit(*str)) throw NumberParsingException( "Integer did not start with digits after optional sign symbol"); T val = (T)((*str) - '0'); ++str; while (isDigit(*str)) { val = val * 10 + (T)((*str) - '0'); ++str; } // Check if str is completely read. if (*str == 0) { if (isNegative) return -val; else return val; } else { throw NumberParsingException( "The integer contains invalid characters after its digits"); } } static double intPow10(int par) { // TODO this can be done a lot faster and more accurate with knowledge that // par = int. return exp10((double)par); } static bool isDigit(char c) { return c >= '0' && c <= '9'; } static bool isPositiveSymbol(char c) { return c == '+'; } static bool isNegativeSymbol(char c) { return c == '-'; } static bool isDecimalPoint(char c) { return c == '.'; } static bool isExponentSymbol(char c) { return c == 'e' || c == 'E'; } }; aoflagger-v3.4.0/util/plot.h0000644000175000017500000000750114507760372014443 0ustar olesoles#ifndef PLOT_H #define PLOT_H #include #include #include #include class Plot { public: //[[ deprecated("Superceded by plot2d class") ]] explicit Plot(const std::string& pdfFile); ~Plot(); void StartLine() { StartLine(""); } void StartLine(const std::string& lineTitle); void StartScatter() { StartScatter(""); } void StartScatter(const std::string& lineTitle); void StartBoxes() { StartScatter(""); } void StartBoxes(const std::string& lineTitle); void StartGrid() { StartGrid(""); } void StartGrid(const std::string& gridTitle); void PushDataPoint(long double x, long double y); void PushDataPoint(long double x, long double y, long double z); void PushUnknownDataPoint(long double x, long double y); void PushDataBlockEnd(); void Close(); void AddRectangle(long double x1, double y1, double x2, double y2); void SetTitle(const std::string& title) throw() { _title = title; } void SetXAxisText(const std::string& text) throw() { _xAxisText = text; } void SetYAxisText(const std::string& text) throw() { _yAxisText = text; } void SetZAxisText(const std::string& text) throw() { _zAxisText = text; } void SetXRange(long double min, long double max) throw() { _xRangeHasMin = true; _xRangeHasMax = true; _xRangeMin = min; _xRangeMax = max; } void SetXRangeAutoMax(long double min) throw() { _xRangeHasMin = true; _xRangeHasMax = false; _xRangeMin = min; } void SetXRangeAutoMin(long double max) throw() { _xRangeHasMin = false; _xRangeHasMax = true; _xRangeMax = max; } void SetXRangeAuto() throw() { _xRangeHasMin = false; _xRangeHasMax = false; } void SetYRange(long double min, long double max) throw() { if (_yRangeHasMin) { if (min < _yRangeMin) _yRangeMin = min; } else { _yRangeHasMin = true; _yRangeMin = min; } if (_yRangeHasMax) { if (max > _yRangeMax) _yRangeMax = max; } else { _yRangeHasMax = true; _yRangeMax = max; } } void SetYRangeAutoMax(long double min) throw() { _yRangeHasMin = true; _yRangeHasMax = false; _yRangeMin = min; } void SetYRangeAutoMin(long double max) throw() { _yRangeHasMin = false; _yRangeHasMax = true; _yRangeMax = max; } void SetYRangeAuto() throw() { _yRangeHasMin = false; _yRangeHasMax = false; } void SetZRange(long double min, long double max) throw() { _zRangeHasMin = true; _zRangeHasMax = true; _zRangeMin = min; _zRangeMax = max; } void SetCBRange(long double min, long double max) throw() { _cbRangeHasMin = true; _cbRangeHasMax = true; _cbRangeMin = min; _cbRangeMax = max; } void SetLogScale(bool x, bool y, bool z = false) { _logX = x; _logY = y; _logZ = z; } void SetFontSize(size_t newSize) { _fontSize = newSize; } void Show(); private: enum Type { Line, Scatter, Boxes, Grid } _curType; void RunGnuplot(); char _tmpPlotFile[16]; void Write(int fd, const std::string& str) { if (write(fd, str.c_str(), str.length()) != (int)str.length()) throw std::runtime_error("write() reported an error"); } void CloseCurFd(); void ExecuteCmd(const std::string& cmd) const; std::vector _lineFiles, _lineTitles; std::vector _lineTypes; int _curLineFd; const std::string _pdfFile; bool _open; std::string _title, _xAxisText, _yAxisText, _zAxisText; bool _xRangeHasMin, _xRangeHasMax; bool _yRangeHasMin, _yRangeHasMax; bool _zRangeHasMin, _zRangeHasMax; bool _cbRangeHasMin, _cbRangeHasMax; long double _xRangeMin, _xRangeMax; long double _yRangeMin, _yRangeMax; long double _zRangeMin, _zRangeMax; long double _cbRangeMin, _cbRangeMax; bool _clipZ; std::vector _extraHeaders; bool _logX, _logY, _logZ; bool _hasBoxes; size_t _fontSize; }; #endif aoflagger-v3.4.0/util/progress/0000755000175000017500000000000014516225226015147 5ustar olesolesaoflagger-v3.4.0/util/progress/progresslistener.h0000644000175000017500000000124014507760372020735 0ustar olesoles#ifndef UTIL_PROGRESS_PROGRESS_LISTENER_H_ #define UTIL_PROGRESS_PROGRESS_LISTENER_H_ #include #include class ProgressListener { public: ProgressListener() = default; virtual ~ProgressListener() = default; virtual void OnStartTask(const std::string& description) = 0; virtual void OnProgress(size_t progress, size_t max_progress) = 0; /** * This function will be called exactly once, unless * an exception occurred. In that case, @ref OnException() will * be called only. */ virtual void OnFinish() = 0; virtual void OnException(std::exception& thrown_exception) = 0; }; #endif // UTIL_PROGRESS_PROGRESS_LISTENER_H_ aoflagger-v3.4.0/util/progress/dummyprogresslistener.h0000644000175000017500000000064214507760372022016 0ustar olesoles#ifndef UTIL_PROGRESS_DUMMY_PROGRESS_LISTENER_H_ #define UTIL_PROGRESS_DUMMY_PROGRESS_LISTENER_H_ #include "progresslistener.h" #include #include class DummyProgressListener final : public ProgressListener { void OnStartTask(const std::string&) override {} void OnProgress(size_t, size_t) override {} void OnFinish() override {} void OnException(std::exception&) override {} }; #endif aoflagger-v3.4.0/util/progress/subtasklistener.h0000644000175000017500000000172714507760372020557 0ustar olesoles#ifndef UTIL_PROGRESS_SUB_TASK_LISTENER_H_ #define UTIL_PROGRESS_SUB_TASK_LISTENER_H_ #include "progresslistener.h" class SubTaskListener final : public ProgressListener { public: SubTaskListener(ProgressListener& parentListener, size_t progress, size_t maxProgress) : _parentListener(parentListener), _fullProgress(progress), _fullMaxProgress(maxProgress) {} void OnStartTask(const std::string& description) override { _parentListener.OnStartTask(description); } void OnProgress(size_t progress, size_t maxProgress) override { _parentListener.OnProgress(_fullProgress * maxProgress + progress, maxProgress * _fullMaxProgress); } void OnFinish() override {} void OnException(std::exception& thrownException) override { _parentListener.OnException(thrownException); } private: ProgressListener& _parentListener; size_t _fullProgress; size_t _fullMaxProgress; }; #endif aoflagger-v3.4.0/util/progress/stdoutreporter.h0000644000175000017500000000163314507760372020436 0ustar olesoles#ifndef UTIL_PROGRESS_STD_OUT_REPORTER_H_ #define UTIL_PROGRESS_STD_OUT_REPORTER_H_ #include "progresslistener.h" #include #include #include class StdOutReporter final : public ProgressListener { public: void OnStartTask(const std::string& description) override { std::cout << description << "...\n"; } void OnProgress(size_t progress, size_t max_progress) override { const unsigned two_percent = (max_progress + 49) / 50; if ((progress % two_percent) == 0) { if (((progress / two_percent) % 5) == 0) std::cout << (100 * progress / max_progress) << std::flush; else std::cout << '.' << std::flush; } } void OnFinish() override { std::cout << "100\n"; } void OnException(std::exception& thrown_exception) override { std::cerr << "ERROR! " << thrown_exception.what() << '\n'; } }; #endif // UTIL_PROGRESS_STD_OUT_REPORTER_H_ aoflagger-v3.4.0/util/numberlist.h0000644000175000017500000000205514507760372015650 0ustar olesoles#ifndef NUMBERLIST_H #define NUMBERLIST_H #include #include #include #include class NumberList { public: template static void ParseIntList(const std::string& str, std::vector& list) { std::string temp = str; size_t pos = temp.find(","); while (pos != std::string::npos) { std::string idStr = temp.substr(0, pos); temp = temp.substr(pos + 1); IntType num = atoi(idStr.c_str()); list.push_back(num); pos = temp.find(","); } IntType num = atoi(temp.c_str()); list.push_back(num); } template static void ParseIntList(const std::string& str, std::set& list) { std::string temp = str; size_t pos = temp.find(","); while (pos != std::string::npos) { std::string idStr = temp.substr(0, pos); temp = temp.substr(pos + 1); IntType num = atoi(idStr.c_str()); list.insert(num); pos = temp.find(","); } IntType num = atoi(temp.c_str()); list.insert(num); } }; #endif aoflagger-v3.4.0/util/gtkmm-compat.h0000644000175000017500000000060314507760372016061 0ustar olesoles#ifndef GTKMM_COMPAT_H #define GTKMM_COMPAT_H #include #include inline void gtkmm_set_image_from_icon_name( Gtk::Button& button, const Glib::ustring& icon_name, Gtk::IconSize size = Gtk::ICON_SIZE_BUTTON) { Gtk::Image* image = Gtk::manage(new Gtk::Image()); image->set_from_icon_name(icon_name, size); button.set_image(*image); } #endif aoflagger-v3.4.0/util/rng.h0000644000175000017500000000163314507760372014253 0ustar olesoles#ifndef RNG_H #define RNG_H #include "../structures/types.h" class RNG { public: static double Gaussian(); static double GaussianProduct(); static double GaussianPartialProduct(); static double GaussianComplex(); static double Rayleigh(); static double Uniform(); static double EvaluateRayleigh(double x, double sigmaSquared); static long double EvaluateGaussian(long double x, long double sigmaSquared); static double EvaluateUnnormalizedGaussian(double x, double sigmaSquared); static double EvaluateGaussian(double x, double sigmaSquared); static double EvaluateGaussian2D(long double x1, long double x2, long double sigmaX1, long double sigmaX2); static double IntegrateGaussian(long double upperLimit); static void DoubleGaussian(long double& a, long double& b); static void ComplexGaussianAmplitude(num_t& r, num_t& i); private: RNG(); }; #endif aoflagger-v3.4.0/util/integerdomain.cpp0000644000175000017500000000503214507760372016642 0ustar olesoles#include "integerdomain.h" #include IntegerDomain::IntegerDomain(const IntegerDomain& source) { for (std::vector::const_iterator i = source._values.begin(); i != source._values.end(); ++i) _values.push_back(*i); } IntegerDomain::IntegerDomain(int singleValue) { _values.push_back(singleValue); } IntegerDomain::IntegerDomain(const int* values, unsigned count) { for (unsigned i = 0; i < count; ++i) _values.push_back(values[i]); } IntegerDomain::IntegerDomain(int first, unsigned count) { for (int i = first; i < (int)(first + count); ++i) _values.push_back(i); } IntegerDomain::IntegerDomain(int first, unsigned step, unsigned count) { for (unsigned i = 0; i < count; ++i) _values.push_back(first + i * step); } IntegerDomain::IntegerDomain(const std::string& str) { enum State { Accepting, Number, Interval } state = Accepting; int number, i1 = 0; for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) { switch (state) { case Accepting: if (*i >= '0' && *i <= '9') { state = Number; number = *i - '0'; } break; case Number: if (*i >= '0' && *i <= '9') { number = number * 10 + (*i - '0'); } else if (*i == '-') { state = Interval; i1 = number; number = 0; } break; case Interval: if (*i >= '0' && *i <= '9') { number = number * 10 + (*i - '0'); } break; } } switch (state) { case Number: _values.push_back(number); break; case Interval: for (int n = i1; n <= number; ++n) _values.push_back(n); break; case Accepting: break; } } void IntegerDomain::Join(const IntegerDomain& other) throw() { for (std::vector::const_iterator i = other._values.begin(); i != other._values.end(); ++i) { bool found = false; for (std::vector::const_iterator j = _values.begin(); j != _values.end(); ++j) { if (*i == *j) { found = true; break; } } if (!found) _values.push_back(*i); } } IntegerDomain IntegerDomain::Split(unsigned partCount, unsigned partIndex) const { const unsigned start = _values.size() * partIndex / partCount; const unsigned end = _values.size() * (partIndex + 1) / partCount; int* values = new int[end - start]; for (unsigned i = start; i < end; ++i) values[i - start] = _values[i]; const IntegerDomain domain(*values, end - start); delete[] values; return domain; } aoflagger-v3.4.0/util/process.h0000644000175000017500000000172614507760372015146 0ustar olesoles#include #include #include #include class Process { public: explicit Process(const std::string& cmdLine) { _pid = vfork(); switch (_pid) { case -1: // Error throw std::runtime_error( "Could not vfork() new process for executing remote client"); case 0: // Child execl("/bin/sh", "sh", "-c", cmdLine.c_str(), NULL); _exit(127); } } void Join() { // Wait for process to terminate int pStatus; do { int pidReturn; do { pidReturn = waitpid(_pid, &pStatus, 0); } while (pidReturn == -1 && errno == EINTR); } while (!WIFEXITED(pStatus) && !WIFSIGNALED(pStatus)); if (WIFEXITED(pStatus)) { const int exitStatus = WEXITSTATUS(pStatus); onFinished(exitStatus != 0, exitStatus); } else { onFinished(true, 0); } } private: std::function onFinished; // TODO int _pid; }; aoflagger-v3.4.0/util/baseexception.h0000644000175000017500000000435514507760372016322 0ustar olesoles/** @file * This is the header file for some of the exception classes and for the base * exception class BaseException. * @author André Offringa */ #ifndef BASEEXCEPTION_H #define BASEEXCEPTION_H #include #include /** * The base exception class that all exceptions should inherit from. */ class BaseException : public std::runtime_error { public: /** * Constructor that initialises the exception as if an unspecified error * occured. */ BaseException() noexcept : std::runtime_error("Unspecified error") {} /** * Constructor that initialises the exception with a specified description. * @param description The description that should describe the cause of the * exception. */ explicit BaseException(const std::string& description) noexcept : std::runtime_error(description) {} /** * Destructor. */ virtual ~BaseException() noexcept {} private: }; /** * Exception that is throwed in case of Input/Output exceptions. */ class IOException : public BaseException { public: /** * Constructor that initialises the IOException without a description. */ IOException() noexcept : BaseException() {} /** * Constructor that initialises the IOException with a description * @param description The description of the Input/Output exception */ explicit IOException(const std::string& description) noexcept : BaseException(description) {} }; /** * Exception that is throwed in case of an incorrect configuration */ class ConfigurationException : public BaseException { public: /** * Constructor that initialises the ConfigurationException with a description * @param description The description of the configuration error */ explicit ConfigurationException(const std::string& description) noexcept : BaseException(description) {} }; /** * Exception that is throwed in case of an incorrect usage of a function */ class BadUsageException : public BaseException { public: /** * Constructor that initialises the BadUsageException with a description * @param description The description of the incorrect usage */ explicit BadUsageException(const std::string& description) noexcept : BaseException(description) {} }; #endif aoflagger-v3.4.0/util/serializable.h0000644000175000017500000000545414507760372016140 0ustar olesoles#ifndef SERIALIZABLE_H #define SERIALIZABLE_H #include #include #include class Serializable { public: virtual ~Serializable() {} virtual void Serialize(std::ostream& stream) const = 0; virtual void Unserialize(std::istream& stream) = 0; template static void SerializeToUInt64(std::ostream& stream, T value) { uint64_t val64t = value; stream.write(reinterpret_cast(&val64t), sizeof(val64t)); } template static void SerializeToUInt32(std::ostream& stream, T value) { uint32_t val32t = value; stream.write(reinterpret_cast(&val32t), sizeof(val32t)); } static void SerializeToFloat(std::ostream& stream, float value) { stream.write(reinterpret_cast(&value), sizeof(value)); } static void SerializeToDouble(std::ostream& stream, double value) { stream.write(reinterpret_cast(&value), sizeof(value)); } static void SerializeToLDouble(std::ostream& stream, long double value) { stream.write(reinterpret_cast(&value), sizeof(value)); } static void SerializeToLDoubleC(std::ostream& stream, std::complex value) { stream.write(reinterpret_cast(&value), sizeof(value)); } static void SerializeToString(std::ostream& stream, const std::string& str) { SerializeToUInt64(stream, str.size()); stream.write(str.c_str(), str.size()); } static uint64_t UnserializeUInt64(std::istream& stream) { return Unserialize(stream); } static uint32_t UnserializeUInt32(std::istream& stream) { return Unserialize(stream); } static double UnserializeFloat(std::istream& stream) { return Unserialize(stream); } static double UnserializeDouble(std::istream& stream) { return Unserialize(stream); } static long double UnserializeLDouble(std::istream& stream) { return Unserialize(stream); } static std::complex UnserializeLDoubleC(std::istream& stream) { return Unserialize>(stream); } static void UnserializeString(std::istream& stream, std::string& destStr) { size_t size = UnserializeUInt64(stream); char* str = new char[size]; stream.read(str, size); destStr = std::string(str, size); delete[] str; } static std::string UnserializeString(std::istream& stream) { size_t size = UnserializeUInt64(stream); std::string result; if (size) { char* str = new char[size]; stream.read(str, size); result = std::string(str, size); delete[] str; } return result; } private: template static T Unserialize(std::istream& stream) { T val; stream.read(reinterpret_cast(&val), sizeof(val)); return val; } }; #endif aoflagger-v3.4.0/util/ffttools.h0000644000175000017500000000737214507760372015333 0ustar olesoles/** @file * This is the header file for the FFTTools class. * @author André Offringa */ #ifndef FFTTOOLS_H #define FFTTOOLS_H #include "../structures/image2d.h" #include "../structures/samplerow.h" /** * This is a wrapper around the fftw3 library that is able to calculate fast * Fourier transformations. */ class FFTTools { public: /** * What will be outputted by the FFT method. */ enum FFTOutputMethod { /** * The transformation to real data. */ Real, /** * The transformation to imaginary data. */ Imaginary, /** * The transformation to the absolute value of real and imaginary. */ Absolute, /** * The transformation to the real and the imaginary data. */ Both }; /** * Create the FFT of an image. * @param original The original image. * @param method Which method to use. * @return A new image that contains the FFT. The caller should @c delete the * image when it is no longer required. */ static Image2D* CreateFFTImage(const Image2D& original, FFTOutputMethod method); static Image2DPtr CreateFFTImagePtr(Image2DCPtr original, FFTOutputMethod method) { return Image2DPtr(CreateFFTImage(*original, method)); } static void CreateFFTImage(const Image2D& real, const Image2D& imaginary, Image2D& realOut, Image2D& imaginaryOut, bool centerAfter = true, bool negate = false); static Image2D* CreateFullImageFromFFT(const Image2D& fft); static Image2D* CreateShiftedImageFromFFT(const Image2D& fft); static Image2D* CreateAbsoluteImage(const Image2D& real, const Image2D& imaginary); static Image2DPtr CreateAbsoluteImage(Image2DCPtr real, Image2DCPtr imaginary) { return Image2DPtr(CreateAbsoluteImage(*real, *imaginary)); } static Image2DPtr CreatePhaseImage(Image2DCPtr real, Image2DCPtr imaginary); static void FFTConvolve(const Image2D& realIn, const Image2D& imaginaryIn, const Image2D& realKernel, const Image2D& imaginaryKernel, Image2D& outReal, Image2D& outImaginary); static void FFTConvolveFFTKernel(const Image2D& realIn, const Image2D& imaginaryIn, const Image2D& realFFTKernel, const Image2D& imaginaryFFTKernel, Image2D& outReal, Image2D& outImaginary); static void Multiply(Image2D& left, const Image2D& right); static void Divide(Image2D& left, const Image2D& right); static void Multiply(Image2D& leftReal, Image2D& leftImaginary, const Image2D& rightReal, const Image2D& rightImaginary); static void Sqrt(Image2D& image); static void Sqrt(Image2DPtr image) { Sqrt(*image); } static void SignedSqrt(Image2D& image); static void SignedSqrt(Image2DPtr image) { SignedSqrt(*image); } static void CreateHorizontalFFTImage(Image2D& real, Image2D& imaginary, bool inverse = false); static void CreateDynamicHorizontalFFTImage(Image2DPtr real, Image2DPtr imaginary, unsigned sections, bool inverse = false); static Image2DPtr AngularTransform(Image2DCPtr input); static void FFT(SampleRow& realRow, SampleRow& imaginaryRow); // static void FFTConvolve(num_t *realValues, num_t *imagValues, num_t // *realKernel, num_t *imagKernel, size_t count); private: FFTTools() {} ~FFTTools(){}; }; #endif aoflagger-v3.4.0/util/ffttools.cpp0000644000175000017500000003534214507760372015664 0ustar olesoles#include "ffttools.h" #include #include "../algorithms/sinusfitter.h" Image2D* FFTTools::CreateFFTImage(const Image2D& original, FFTOutputMethod method) { Image2D* image; if (method == Both) image = Image2D::CreateUnsetImage(original.Width() + 2, original.Height()); else image = Image2D::CreateUnsetImage(original.Width() / 2 + 1, original.Height()); const unsigned long n_in = original.Width() * original.Height(); const unsigned long n_out = original.Width() * (original.Height() / 2 + 1); double* in = (double*)fftw_malloc(sizeof(double) * n_in); fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n_out); // According to the specification of fftw, the execute function might // destroy the input array ("in"), wherefore we need to copy it. unsigned long ptr = 0; for (unsigned long y = 0; y < original.Height(); ++y) { for (unsigned long x = 0; x < original.Width(); ++x) { in[ptr] = original.Value(x, y); ++ptr; } } fftw_plan plan = fftw_plan_dft_r2c_2d(original.Width(), original.Height(), in, out, FFTW_ESTIMATE); fftw_execute(plan); // Copy data to new image if (method != Both) { ptr = 0; const unsigned long halfwidth = original.Width() / 2 + 1; for (unsigned long y = 0; y < image->Height(); ++y) { for (unsigned long x = 0; x < halfwidth; ++x) { switch (method) { case Real: image->SetValue(x, y, out[ptr][0]); break; case Imaginary: image->SetValue(x, y, out[ptr][1]); break; case Absolute: default: image->SetValue( x, y, sqrtl(out[ptr][0] * out[ptr][0] + out[ptr][1] * out[ptr][1])); break; } ptr++; } } } else { unsigned out_ptr = 0; const unsigned long halfwidth = original.Width() / 2 + 1; for (unsigned long y = 0; y < image->Height(); ++y) { for (unsigned long x = 0; x < halfwidth; ++x) { image->SetValue(x, y, out[out_ptr][0]); ++out_ptr; } out_ptr -= halfwidth; for (unsigned long x = 0; x < halfwidth; ++x) { image->SetValue(x, y, out[out_ptr][1]); ++out_ptr; } } } fftw_destroy_plan(plan); fftw_free(in); fftw_free(out); return image; } void FFTTools::CreateFFTImage(const Image2D& real, const Image2D& imaginary, Image2D& realOut, Image2D& imaginaryOut, bool centerAfter, bool negate) { const unsigned long n_in = real.Width() * real.Height(); fftw_complex* in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n_in); fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n_in); const bool centerBefore = true; if (centerBefore) { Image2D* tmp = CreateShiftedImageFromFFT(real); realOut = *tmp; delete tmp; tmp = CreateShiftedImageFromFFT(imaginary); imaginaryOut = *tmp; delete tmp; } else { realOut = real; imaginaryOut = imaginary; } unsigned long ptr = 0; for (unsigned long y = 0; y < real.Height(); y++) { for (unsigned long x = 0; x < real.Width(); x++) { in[ptr][0] = realOut.Value(x, y); in[ptr][1] = imaginaryOut.Value(x, y); ptr++; } } int sign = 1; if (negate) sign = -1; fftw_plan plan = fftw_plan_dft_2d(real.Width(), real.Height(), in, out, sign, FFTW_ESTIMATE); fftw_execute(plan); ptr = 0; const num_t normFactor = 1.0 / sqrtn((num_t)real.Width() * real.Height()); for (unsigned long y = 0; y < real.Height(); y++) { for (unsigned long x = 0; x < real.Width(); x++) { realOut.SetValue(x, y, out[ptr][0] * normFactor); imaginaryOut.SetValue(x, y, out[ptr][1] * normFactor); ptr++; } } fftw_destroy_plan(plan); fftw_free(in); fftw_free(out); if (centerAfter) { Image2D* tmp = CreateShiftedImageFromFFT(realOut); realOut = *tmp; delete tmp; tmp = CreateShiftedImageFromFFT(imaginaryOut); imaginaryOut = *tmp; delete tmp; } } Image2D* FFTTools::CreateFullImageFromFFT(const Image2D& fft) { const int width = fft.Width() * 2; Image2D* image = Image2D::CreateUnsetImage(width, fft.Height()); for (unsigned y = 0; y < fft.Height(); ++y) { for (unsigned x = 0; x < fft.Width(); ++x) { image->SetValue(x, y, fft.Value(fft.Width() - x - 1, (y + fft.Height() / 2) % fft.Height())); image->SetValue(fft.Width() * 2 - x - 1, fft.Height() - y - 1, fft.Value(fft.Width() - x - 1, (y + fft.Height() / 2) % fft.Height())); } } return image; } Image2D* FFTTools::CreateShiftedImageFromFFT(const Image2D& fft) { Image2D* image = Image2D::CreateUnsetImage(fft.Width(), fft.Height()); for (unsigned y = 0; y < fft.Height(); ++y) { for (unsigned x = 0; x < fft.Width(); ++x) { image->SetValue(x, y, fft.Value((x + fft.Width() / 2) % fft.Width(), (y + fft.Height() / 2) % fft.Height())); } } return image; } Image2D* FFTTools::CreateAbsoluteImage(const Image2D& real, const Image2D& imaginary) { Image2D* image = Image2D::CreateUnsetImage(real.Width(), real.Height()); for (unsigned y = 0; y < real.Height(); ++y) { for (unsigned x = 0; x < real.Width(); ++x) image->SetValue(x, y, sqrtl(real.Value(x, y) * real.Value(x, y) + imaginary.Value(x, y) * imaginary.Value(x, y))); } return image; } Image2DPtr FFTTools::CreatePhaseImage(Image2DCPtr real, Image2DCPtr imaginary) { Image2DPtr image = Image2D::CreateUnsetImagePtr(real->Width(), real->Height()); for (unsigned y = 0; y < real->Height(); ++y) { for (unsigned x = 0; x < real->Width(); ++x) image->SetValue(x, y, algorithms::SinusFitter::Phase(real->Value(x, y), imaginary->Value(x, y))); } return image; } void FFTTools::FFTConvolve(const Image2D& realIn, const Image2D& imaginaryIn, const Image2D& realKernel, const Image2D& imaginaryKernel, Image2D& outReal, Image2D& outImaginary) { Image2D realFFTIn = Image2D::MakeUnsetImage(realIn.Width(), realIn.Height()), imaginaryFFTIn = Image2D::MakeUnsetImage(imaginaryIn.Width(), imaginaryIn.Height()); CreateFFTImage(realIn, imaginaryIn, realFFTIn, imaginaryFFTIn); Image2D realFFTKernel = Image2D::MakeUnsetImage(realKernel.Width(), realKernel.Height()), imaginaryFFTKernel = Image2D::MakeUnsetImage( imaginaryKernel.Width(), imaginaryKernel.Height()); CreateFFTImage(realKernel, imaginaryKernel, realFFTKernel, imaginaryFFTKernel); Multiply(realFFTIn, imaginaryFFTIn, realFFTKernel, imaginaryFFTKernel); CreateFFTImage(realFFTIn, imaginaryFFTIn, outReal, outImaginary, true, true); } /*void FFTTools::FFTConvolve(num_t *realValues, num_t *imagValues, num_t *realKernel, num_t *imagKernel, size_t count) { fftw_complex *in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * count), *out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * count); for(unsigned i=0;i= 0.0) image.SetValue(x, y, sqrt(image.Value(x, y))); else image.SetValue(x, y, -sqrt(-image.Value(x, y))); } } } void FFTTools::CreateHorizontalFFTImage(Image2D& real, Image2D& imaginary, bool inverse) { if (real.Height() == 0) return; const unsigned long n_in = real.Width(); fftw_complex* in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n_in); fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n_in); for (unsigned long x = 0; x < real.Width(); ++x) { in[x][0] = real.Value(x, 0); in[x][1] = imaginary.Value(x, 0); } int sign = -1; if (inverse) sign = 1; for (unsigned long y = 0; y < real.Height(); ++y) { for (unsigned long x = 0; x < real.Width(); ++x) { in[x][0] = real.Value(x, y); in[x][1] = imaginary.Value(x, y); } fftw_plan plan = fftw_plan_dft_1d(real.Width(), in, out, sign, FFTW_ESTIMATE); fftw_execute(plan); fftw_destroy_plan(plan); for (unsigned long x = 0; x < real.Width(); ++x) { real.SetValue(x, y, out[x][0]); imaginary.SetValue(x, y, out[x][1]); } } fftw_free(out); fftw_free(in); } void FFTTools::CreateDynamicHorizontalFFTImage(Image2DPtr real, Image2DPtr imaginary, unsigned sections, bool inverse) { const size_t width = real->Width(); if (real->Height() == 0 || width == 0) return; SampleRow realRow = SampleRow::MakeFromRowSum(real.get(), 0, real->Height()), imaginaryRow = SampleRow::MakeFromRowSum(imaginary.get(), 0, imaginary->Height()); Image2D destReal = Image2D::MakeUnsetImage(real->Width(), real->Height()), destImag = Image2D::MakeUnsetImage(real->Width(), real->Height()); const unsigned long n_in = width; fftw_complex* in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n_in); fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n_in); int sign = -1; if (inverse) sign = 1; for (unsigned sec = 0; sec < sections; ++sec) { const unsigned secStart = width * sec / (sections + 1), secEnd = width * (sec + 2) / (sections + 1); for (unsigned x = secStart; x < secEnd; ++x) { in[x - secStart][0] = realRow.Value(x); in[x - secStart][1] = imaginaryRow.Value(x); } fftw_plan plan = fftw_plan_dft_1d(secEnd - secStart, in, out, sign, FFTW_ESTIMATE); fftw_execute(plan); fftw_destroy_plan(plan); size_t maxF = secEnd - secStart; if (maxF > destReal.Height()) maxF = destReal.Height(); const unsigned xEnd = width * (sec + 1) / sections; for (unsigned long x = width * sec / sections; x < xEnd; ++x) { for (unsigned long y = 0; y < maxF; ++y) { destReal.SetValue(x, y, out[y][0]); destImag.SetValue(x, y, out[y][1]); } for (unsigned long y = maxF; y < destReal.Height(); ++y) { destReal.SetValue(x, y, 0.0); destImag.SetValue(x, y, 0.0); } } } fftw_free(out); fftw_free(in); *real = destReal; *imaginary = destImag; } Image2DPtr FFTTools::AngularTransform(Image2DCPtr image) { const size_t minDim = image->Width() > image->Height() ? image->Height() : image->Width(); Image2D* transformedImage = Image2D::CreateUnsetImage(minDim, minDim); numl_t halfMinDim = (numl_t)minDim / 2.0, halfWidth = (numl_t)image->Width() / 2.0, halfHeight = (numl_t)image->Height() / 2.0; for (size_t angleIndex = 0; angleIndex < minDim; ++angleIndex) { numl_t angle = (numl_t)angleIndex * M_PInl / (numl_t)minDim, cosAngle = cosnl(angle), sinAngle = sinnl(angle); for (unsigned offsetIndex = 0; offsetIndex < minDim; ++offsetIndex) { numl_t offset = (numl_t)(halfMinDim - offsetIndex), x = halfWidth + offset * cosAngle, y = halfHeight - offset * sinAngle; transformedImage->SetValue(angleIndex, offsetIndex, image->Value((size_t)x, (size_t)y)); } } return Image2DPtr(transformedImage); } void FFTTools::FFT(SampleRow& realRow, SampleRow& imaginaryRow) { const size_t n = realRow.Size(); fftw_complex *in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n), *out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n); for (unsigned i = 0; i < n; ++i) { in[i][0] = realRow.Value(i); in[i][1] = imaginaryRow.Value(i); } fftw_plan p = fftw_plan_dft_1d(n, in, out, FFTW_FORWARD, FFTW_ESTIMATE); fftw_execute(p); fftw_destroy_plan(p); for (unsigned i = 0; i < n; ++i) { realRow.SetValue(i, out[i][0]); imaginaryRow.SetValue(i, out[i][0]); } fftw_free(in); fftw_free(out); } aoflagger-v3.4.0/util/rfiplots.cpp0000644000175000017500000003475614507760372015676 0ustar olesoles#include "rfiplots.h" #include #include #include "../util/plot.h" #include "../util/multiplot.h" #include "../structures/timefrequencydata.h" #include "../structures/timefrequencymetadata.h" #include "../algorithms/sinusfitter.h" #include "../algorithms/thresholdtools.h" #include "../plot/axis.h" #include "../plot/xyplot.h" using aocommon::Polarization; using aocommon::PolarizationEnum; using algorithms::SinusFitter; using algorithms::ThresholdTools; void RFIPlots::Bin(Image2DCPtr image, Mask2DCPtr mask, std::vector& valuesOutput, std::vector& binsOutput, size_t binCount, long double start, long double end, long double factor, long double stretch) throw() { const long double min = start == end ? ThresholdTools::MinValue(image.get(), mask.get()) : start; const long double max = start == end ? ThresholdTools::MaxValue(image.get(), mask.get()) : end; const long double binsize = (max - min) / binCount; valuesOutput.resize(binCount); binsOutput.resize(binCount); for (size_t i = 0; i < binCount; ++i) { valuesOutput[i] = 0; binsOutput[i] = (binsize * ((long double)i + 0.5)) + min; } for (size_t y = 0; y < image->Height(); ++y) { for (size_t x = 0; x < image->Width(); ++x) { if (!mask->Value(x, y)) { const long double value = image->Value(x, y); const size_t index = (size_t)((value * stretch - min) / binsize); if (index < binCount) valuesOutput[index] += 1; } } } if (factor != 1.0) { for (size_t i = 0; i < binCount; ++i) { valuesOutput[i] = (size_t)(factor * valuesOutput[i]); } } } void RFIPlots::MakeDistPlot(XYPointSet& pointSet, Image2DCPtr image, Mask2DCPtr mask) { std::vector valuesOutput; std::vector binsOutput; pointSet.SetXDesc("Visibility"); pointSet.SetYDesc("Occurences"); num_t mean, stddev; num_t min = image->GetMinimum(); num_t max = image->GetMaximum(); ThresholdTools::WinsorizedMeanAndStdDev(image.get(), mean, stddev); if (min < mean - 3.0L * stddev) min = mean - 3.0L * stddev; if (max > mean + 3.0L * stddev) max = mean + 3.0L * stddev; Bin(image, mask, valuesOutput, binsOutput, 40, min, max); for (unsigned i = 0; i < valuesOutput.size(); ++i) pointSet.PushDataPoint(binsOutput[i], valuesOutput[i]); } template void RFIPlots::MakeMeanSpectrumPlot(XYPointSet& pointSet, const TimeFrequencyData& data, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData) { const bool hasBandInfo = metaData != nullptr && metaData->HasBand(); if (hasBandInfo) { pointSet.SetXDesc("Frequency (MHz)"); std::stringstream yDesc; yDesc << metaData->ValueDescription() << " (" << metaData->ValueUnits() << ')'; pointSet.SetYDesc(yDesc.str()); } else { pointSet.SetXDesc("Index"); pointSet.SetYDesc("Mean (undefined units)"); } TimeFrequencyData displayData = data; if (displayData.ComplexRepresentation() == TimeFrequencyData::ComplexParts) { displayData = data.Make(TimeFrequencyData::AmplitudePart); } long double min = 1e100, max = -1e100; const size_t height = data.ImageHeight(), width = data.ImageWidth(); for (size_t y = 0; y < height; ++y) { long double sum = 0.0L; size_t count = 0; for (size_t i = 0; i < displayData.ImageCount(); ++i) { const Image2DCPtr image = displayData.GetImage(i); for (size_t x = 0; x < width; ++x) { if (!mask->Value(x, y) && std::isnormal(image->Value(x, y))) { sum += image->Value(x, y); ++count; } } } if (count > 0) { long double v; if (Weight) v = sum; else v = sum / count; if (v < min) min = v; if (v > max) max = v; if (hasBandInfo) pointSet.PushDataPoint( metaData->Band().channels[y].frequencyHz / 1000000.0, v); else pointSet.PushDataPoint(y, v); } } } template void RFIPlots::MakeMeanSpectrumPlot( XYPointSet& pointSet, const TimeFrequencyData& data, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData); template void RFIPlots::MakeMeanSpectrumPlot( XYPointSet& pointSet, const TimeFrequencyData& data, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData); void RFIPlots::MakePowerSpectrumPlot(XYPointSet& pointSet, const Image2D& real, const Image2D& imag, const Mask2D& mask, const TimeFrequencyMetaData* metaData) { const bool hasBandInfo = metaData != nullptr && metaData->HasBand(); if (hasBandInfo) { pointSet.SetXDesc("Frequency (MHz)"); std::stringstream yDesc; yDesc << metaData->ValueDescription() << "^2 (" << metaData->ValueUnits() << "^2)"; pointSet.SetYDesc(yDesc.str()); } else { pointSet.SetXDesc("Index"); pointSet.SetYDesc("Power (undefined units)"); } for (size_t y = 0; y < real.Height(); ++y) { long double sum = 0.0L; size_t count = 0; for (size_t x = 0; x < real.Width(); ++x) { if (!mask.Value(x, y) && std::isfinite(real.Value(x, y))) { const std::complex val(real.Value(x, y), imag.Value(x, y)); sum += (val * std::conj(val)).real(); ++count; } } long double v; if (count > 0) v = sum / count; else v = std::numeric_limits::quiet_NaN(); if (hasBandInfo) pointSet.PushDataPoint( metaData->Band().channels[y].frequencyHz / 1000000.0, v); else pointSet.PushDataPoint(y, v); } } void RFIPlots::MakePowerTimePlot(XYPointSet& pointSet, Image2DCPtr image, Mask2DCPtr mask, TimeFrequencyMetaDataCPtr metaData) { pointSet.SetXDesc("Time"); pointSet.SetYDesc("Visibility"); bool useMeta; if (metaData != nullptr && metaData->HasObservationTimes()) { useMeta = true; } else { useMeta = false; } const size_t binSize = (size_t)ceil(image->Width() / 256.0L); unsigned index = 0; for (size_t x = 0; x < image->Width(); x += binSize) { long double sum = 0.0L; size_t count = 0; for (size_t binx = 0; binx < binSize; ++binx) { for (size_t y = 0; y < image->Height(); ++y) { if (!mask->Value(x + binx, y) && std::isnormal(image->Value(x + binx, y))) { sum += image->Value(x + binx, y); ++count; } } } if (useMeta) pointSet.PushDataPoint(metaData->ObservationTimes()[x], sum / count); else pointSet.PushDataPoint(index, sum / count); ++index; } } void RFIPlots::MakeComplexPlanePlot(XYPointSet& pointSet, const TimeFrequencyData& data, size_t xStart, size_t length, size_t y, size_t yAvgSize, Mask2DCPtr mask, bool realVersusImaginary, bool drawImaginary) { if (realVersusImaginary) { pointSet.SetXDesc("real"); pointSet.SetYDesc("imaginary"); } else { // pointSet.SetXRange(xStart, xStart+length-1); pointSet.SetXDesc("time"); pointSet.SetYDesc("real/imaginary visibility"); } const Image2DCPtr real = data.GetRealPart(); const Image2DCPtr imaginary = data.GetImaginaryPart(); for (size_t x = xStart; x < xStart + length; ++x) { long double r = 0.0L, i = 0.0L; for (size_t yi = y; yi < yAvgSize + y; ++yi) { if (!mask->Value(x, yi) && std::isfinite(real->Value(x, yi)) && std::isfinite(imaginary->Value(x, yi))) { r += real->Value(x, yi); i += imaginary->Value(x, yi); } } if (realVersusImaginary) pointSet.PushDataPoint(r, i); else if (drawImaginary) pointSet.PushDataPoint(x, i); else pointSet.PushDataPoint(x, r); } } void RFIPlots::MakeFittedComplexPlot(XYPointSet& pointSet, const TimeFrequencyData& data, size_t xStart, size_t length, size_t y, size_t yAvgSize, Mask2DCPtr mask, num_t frequency, bool realVersusImaginary, bool drawImaginary) { if (realVersusImaginary) { pointSet.SetXDesc("real"); pointSet.SetYDesc("imaginary"); } else { // plot.SetXRange(xStart, xStart+length-1); pointSet.SetXDesc("time"); pointSet.SetYDesc("real/imaginary visibility"); } const Image2DCPtr real = data.GetRealPart(); const Image2DCPtr imaginary = data.GetImaginaryPart(); std::vector xReal(length); std::vector xImag(length); std::vector t(length); size_t dataIndex = 0; for (size_t x = xStart; x < xStart + length; ++x) { num_t r = 0.0L, i = 0.0L; size_t count = 0; for (size_t yi = y; yi < yAvgSize + y; ++yi) { if (!mask->Value(x, yi) && std::isfinite(real->Value(x, yi)) && std::isfinite(imaginary->Value(x, yi))) { r += real->Value(x, yi); i += imaginary->Value(x, yi); ++count; } } if (count > 0) { t[dataIndex] = x; xReal[dataIndex] = r; xImag[dataIndex] = i; ++dataIndex; } } if (dataIndex != length) std::cout << "Warning: " << (length - dataIndex) << " time points were removed." << std::endl; SinusFitter fitter; num_t realPhase, realAmplitude, realMean, imagPhase, imagAmplitude, imagMean; const num_t twopi = 2.0 * M_PIn; fitter.FindPhaseAndAmplitudeComplex(realPhase, realAmplitude, xReal.data(), xImag.data(), t.data(), dataIndex, frequency * twopi); imagPhase = realPhase + 0.5 * M_PIn; imagAmplitude = realAmplitude; realMean = fitter.FindMean(realPhase, realAmplitude, xReal.data(), t.data(), dataIndex, frequency * twopi); imagMean = fitter.FindMean(imagPhase, imagAmplitude, xImag.data(), t.data(), dataIndex, frequency * twopi); std::cout << "Amplitude found: " << realAmplitude << " phase found: " << realPhase << std::endl; for (size_t x = xStart; x < xStart + length; ++x) { if (realVersusImaginary) pointSet.PushDataPoint( cosn(frequency * twopi * (long double)x + realPhase) * realAmplitude + realMean, cosn(frequency * twopi * (long double)x + imagPhase) * imagAmplitude + imagMean); else if (drawImaginary) pointSet.PushDataPoint( x, cosn(frequency * twopi * (long double)x + imagPhase) * imagAmplitude + imagMean); else pointSet.PushDataPoint( x, cosn(frequency * twopi * (long double)x + realPhase) * realAmplitude + realMean); } } void RFIPlots::MakeTimeScatterPlot(class MultiPlot& plot, size_t plotIndex, const Image2DCPtr& image, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData) { plot.SetXAxisText("Time (s)"); plot.SetYAxisText("Visibility"); bool useMeta; if (metaData != nullptr && metaData->HasObservationTimes()) useMeta = true; else useMeta = false; double firstTimeStep; if (useMeta) firstTimeStep = metaData->ObservationTimes()[0]; else firstTimeStep = 0; for (size_t x = 0; x < image->Width(); ++x) { size_t count = 0; num_t sum = 0.0; for (size_t y = 0; y < image->Height(); ++y) { if (!mask->Value(x, y) && std::isnormal(image->Value(x, y))) { sum += image->Value(x, y); ++count; } } if (count > 0) { if (useMeta) plot.AddPoint(plotIndex, metaData->ObservationTimes()[x] - firstTimeStep, sum / count); else plot.AddPoint(plotIndex, x, sum / count); } } } void RFIPlots::MakeFrequencyScatterPlot( class MultiPlot& plot, size_t plotIndex, const Image2DCPtr& image, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData) { plot.SetYAxisText("Visibility"); bool useMeta; if (metaData != nullptr && metaData->HasBand()) useMeta = true; else useMeta = false; if (useMeta) plot.SetXAxisText("Frequency (MHz)"); else plot.SetXAxisText("Channel index"); for (size_t y = 0; y < image->Height(); ++y) { size_t count = 0; num_t sum = 0.0; for (size_t x = 0; x < image->Width(); ++x) { if (!mask->Value(x, y) && std::isnormal(image->Value(x, y))) { sum += image->Value(x, y); ++count; } } if (count > 0) { if (useMeta) plot.AddPoint(plotIndex, metaData->Band().channels[y].frequencyHz * 1e-6, sum / count); else plot.AddPoint(plotIndex, y, sum / count); } } } void RFIPlots::MakeTimeScatterPlot(class MultiPlot& plot, const TimeFrequencyData& data, const TimeFrequencyMetaDataCPtr& metaData, unsigned startIndex) { for (size_t polIndex = 0; polIndex != data.PolarizationCount(); ++polIndex) { const PolarizationEnum pol = data.GetPolarization(polIndex); const TimeFrequencyData polTF = data.Make(pol); MakeTimeScatterPlot(plot, startIndex + polIndex, polTF.GetSingleImage(), polTF.GetSingleMask(), metaData); if (data.PolarizationCount() == 1) plot.SetLegend(startIndex, data.Description()); else plot.SetLegend(startIndex + polIndex, Polarization::TypeToFullString(pol)); } } void RFIPlots::MakeFrequencyScatterPlot( class MultiPlot& plot, const TimeFrequencyData& data, const TimeFrequencyMetaDataCPtr& metaData, unsigned startIndex) { for (size_t polIndex = 0; polIndex != data.PolarizationCount(); ++polIndex) { const PolarizationEnum pol = data.GetPolarization(polIndex); const TimeFrequencyData polTF = data.Make(pol); MakeFrequencyScatterPlot(plot, startIndex + polIndex, polTF.GetSingleImage(), polTF.GetSingleMask(), metaData); if (data.PolarizationCount() == 1) plot.SetLegend(startIndex, data.Description()); else plot.SetLegend(startIndex + polIndex, Polarization::TypeToFullString(pol)); } } aoflagger-v3.4.0/util/blaswrap.h0000644000175000017500000000732514507760372015304 0ustar olesoles/* CLAPACK 3.0 BLAS wrapper macros * Feb 5, 2000 */ #ifndef __BLASWRAP_H #define __BLASWRAP_H #ifndef NO_BLAS_WRAP /* BLAS1 routines */ #define srotg_ f2c_srotg #define drotg_ f2c_drotg #define srotmg_ f2c_srotmg #define drotmg_ f2c_drotmg #define srot_ f2c_srot #define drot_ f2c_drot #define srotm_ f2c_srotm #define drotm_ f2c_drotm #define csrot_ f2c_csrot #define zdrot_ f2c_zdrot #define sswap_ f2c_sswap #define dswap_ f2c_dswap #define cswap_ f2c_cswap #define zswap_ f2c_zswap #define sscal_ f2c_sscal #define dscal_ f2c_dscal #define cscal_ f2c_cscal #define zscal_ f2c_zscal #define csscal_ f2c_csscal #define zdscal_ f2c_zdscal #define scopy_ f2c_scopy #define dcopy_ f2c_dcopy #define ccopy_ f2c_ccopy #define zcopy_ f2c_zcopy #define saxpy_ f2c_saxpy #define daxpy_ f2c_daxpy #define caxpy_ f2c_caxpy #define zaxpy_ f2c_zaxpy #define sdot_ f2c_sdot #define ddot_ f2c_ddot #define cdotu_ f2c_cdotu #define zdotu_ f2c_zdotu #define cdotc_ f2c_cdotc #define zdotc_ f2c_zdotc #define snrm2_ f2c_snrm2 #define dnrm2_ f2c_dnrm2 #define scnrm2_ f2c_scnrm2 #define dznrm2_ f2c_dznrm2 #define sasum_ f2c_sasum #define dasum_ f2c_dasum #define scasum_ f2c_scasum #define dzasum_ f2c_dzasum #define isamax_ f2c_isamax #define idamax_ f2c_idamax #define icamax_ f2c_icamax #define izamax_ f2c_izamax /* BLAS2 routines */ #define sgemv_ f2c_sgemv #define dgemv_ f2c_dgemv #define cgemv_ f2c_cgemv #define zgemv_ f2c_zgemv #define sgbmv_ f2c_sgbmv #define dgbmv_ f2c_dgbmv #define cgbmv_ f2c_cgbmv #define zgbmv_ f2c_zgbmv #define chemv_ f2c_chemv #define zhemv_ f2c_zhemv #define chbmv_ f2c_chbmv #define zhbmv_ f2c_zhbmv #define chpmv_ f2c_chpmv #define zhpmv_ f2c_zhpmv #define ssymv_ f2c_ssymv #define dsymv_ f2c_dsymv #define ssbmv_ f2c_ssbmv #define dsbmv_ f2c_dsbmv #define sspmv_ f2c_sspmv #define dspmv_ f2c_dspmv #define strmv_ f2c_strmv #define dtrmv_ f2c_dtrmv #define ctrmv_ f2c_ctrmv #define ztrmv_ f2c_ztrmv #define stbmv_ f2c_stbmv #define dtbmv_ f2c_dtbmv #define ctbmv_ f2c_ctbmv #define ztbmv_ f2c_ztbmv #define stpmv_ f2c_stpmv #define dtpmv_ f2c_dtpmv #define ctpmv_ f2c_ctpmv #define ztpmv_ f2c_ztpmv #define strsv_ f2c_strsv #define dtrsv_ f2c_dtrsv #define ctrsv_ f2c_ctrsv #define ztrsv_ f2c_ztrsv #define stbsv_ f2c_stbsv #define dtbsv_ f2c_dtbsv #define ctbsv_ f2c_ctbsv #define ztbsv_ f2c_ztbsv #define stpsv_ f2c_stpsv #define dtpsv_ f2c_dtpsv #define ctpsv_ f2c_ctpsv #define ztpsv_ f2c_ztpsv #define sger_ f2c_sger #define dger_ f2c_dger #define cgeru_ f2c_cgeru #define zgeru_ f2c_zgeru #define cgerc_ f2c_cgerc #define zgerc_ f2c_zgerc #define cher_ f2c_cher #define zher_ f2c_zher #define chpr_ f2c_chpr #define zhpr_ f2c_zhpr #define cher2_ f2c_cher2 #define zher2_ f2c_zher2 #define chpr2_ f2c_chpr2 #define zhpr2_ f2c_zhpr2 #define ssyr_ f2c_ssyr #define dsyr_ f2c_dsyr #define sspr_ f2c_sspr #define dspr_ f2c_dspr #define ssyr2_ f2c_ssyr2 #define dsyr2_ f2c_dsyr2 #define sspr2_ f2c_sspr2 #define dspr2_ f2c_dspr2 /* BLAS3 routines */ #define sgemm_ f2c_sgemm #define dgemm_ f2c_dgemm #define cgemm_ f2c_cgemm #define zgemm_ f2c_zgemm #define ssymm_ f2c_ssymm #define dsymm_ f2c_dsymm #define csymm_ f2c_csymm #define zsymm_ f2c_zsymm #define chemm_ f2c_chemm #define zhemm_ f2c_zhemm #define ssyrk_ f2c_ssyrk #define dsyrk_ f2c_dsyrk #define csyrk_ f2c_csyrk #define zsyrk_ f2c_zsyrk #define cherk_ f2c_cherk #define zherk_ f2c_zherk #define ssyr2k_ f2c_ssyr2k #define dsyr2k_ f2c_dsyr2k #define csyr2k_ f2c_csyr2k #define zsyr2k_ f2c_zsyr2k #define cher2k_ f2c_cher2k #define zher2k_ f2c_zher2k #define strmm_ f2c_strmm #define dtrmm_ f2c_dtrmm #define ctrmm_ f2c_ctrmm #define ztrmm_ f2c_ztrmm #define strsm_ f2c_strsm #define dtrsm_ f2c_dtrsm #define ctrsm_ f2c_ctrsm #define ztrsm_ f2c_ztrsm #endif /* NO_BLAS_WRAP */ #endif /* __BLASWRAP_H */ aoflagger-v3.4.0/util/integerdomain.h0000644000175000017500000000236314507760372016313 0ustar olesoles#ifndef INTEGERDOMAIN_H #define INTEGERDOMAIN_H #include #include class IntegerDomain { public: IntegerDomain(const IntegerDomain& source); explicit IntegerDomain(int singleValue); IntegerDomain(const int* values, unsigned count); IntegerDomain(int first, unsigned count); IntegerDomain(int first, unsigned step, unsigned count); explicit IntegerDomain(const std::string& str); ~IntegerDomain() {} unsigned ValueCount() const throw() { return _values.size(); } int GetValue(unsigned index) const throw() { return _values[index]; } void Join(const IntegerDomain& other) throw(); bool IsIn(int number) const throw() { for (std::vector::const_iterator i = _values.begin(); i != _values.end(); ++i) { if (*i == number) return true; } return false; } IntegerDomain Split(unsigned partCount, unsigned partIndex) const; unsigned Index(int number) const throw() { for (unsigned i = 0; i != _values.size(); ++i) { if (_values[i] == number) return i; } return unsigned(-1); } std::vector::const_iterator begin() const { return _values.begin(); } std::vector::const_iterator end() const { return _values.end(); } private: std::vector _values; }; #endif aoflagger-v3.4.0/util/rng.cpp0000644000175000017500000000512014507760372014601 0ustar olesoles#include "rng.h" #include #include #ifndef M_PIl #define M_PIl M_PI #endif RNG::RNG() {} double RNG::Uniform() { return (long double)rand() / (long double)RAND_MAX; } double RNG::Gaussian() { long double a, b; DoubleGaussian(a, b); return a; } double RNG::GaussianProduct() { long double a, b; DoubleGaussian(a, b); return a * b; } double RNG::GaussianPartialProduct() { long double a, b; DoubleGaussian(a, b); if (a >= 0.0) a = pow(a, M_SQRT2 / 2.0); else a = -pow(-a, M_SQRT2 / 2.0); if (b >= 0.0) b = pow(b, M_SQRT2 / 2.0); else b = -pow(-b, M_SQRT2 / 2.0); return a * b; } void RNG::DoubleGaussian(long double& a, long double& b) { long double x1, x2, w; do { const long double r1 = (long double)rand() / (long double)RAND_MAX; const long double r2 = (long double)rand() / (long double)RAND_MAX; x1 = 2.0 * r1 - 1.0; x2 = 2.0 * r2 - 1.0; w = x1 * x1 + x2 * x2; } while (w >= 1.0); w = std::sqrt((-2.0 * std::log(w)) / w); a = x1 * w; b = x2 * w; } double RNG::Rayleigh() { double x = Gaussian(), y = Gaussian(); return sqrt(x * x + y * y); } double RNG::EvaluateRayleigh(double x, double sigma) { return x * exp(-x * x / (2.0 * sigma * sigma)) / (sigma * sigma); } double RNG::IntegrateGaussian(long double upperLimit) { long double integral = 0.0L, term = 0.0L, stepSize = 1e-4L; upperLimit -= stepSize / 2.0L; do { term = std::exp(-upperLimit * upperLimit / 2.0L); upperLimit -= stepSize; integral += term * stepSize; } while (term >= 1e-6 || upperLimit >= 0); return integral / std::sqrt(2.0L * M_PIl); } double RNG::EvaluateGaussian(double x, double sigmaSquared) { return 1.0 / (sigmaSquared * std::sqrt(2.0L * M_PI)) * std::exp(-0.5 * x * x / sigmaSquared); } long double RNG::EvaluateGaussian(long double x, long double sigmaSquared) { return 1.0L / (sigmaSquared * std::sqrt(2.0L * M_PI)) * std::exp(-0.5L * x * x / sigmaSquared); } double RNG::EvaluateUnnormalizedGaussian(double x, double sigmaSquared) { return std::exp(-0.5 * x * x / sigmaSquared); } double RNG::EvaluateGaussian2D(long double x1, long double x2, long double sigmaX1, long double sigmaX2) { return 1.0L / (2.0L * M_PI * sigmaX1 * sigmaX2) * std::exp(-0.5L * (x1 * (1.0L / sigmaX1) * x1 + x2 * (1.0L / sigmaX2) * x2)); } void RNG::ComplexGaussianAmplitude(num_t& r, num_t& i) { const num_t amplitude = Gaussian(); const num_t phase = Uniform() * 2.0 * M_PIn; r = amplitude * std::cos(phase); i = amplitude * std::sin(phase); } aoflagger-v3.4.0/util/rfiplots.h0000644000175000017500000001011714507760372015324 0ustar olesoles#ifndef RFIPLOTS_H #define RFIPLOTS_H #include #include "../structures/image2d.h" #include "../structures/mask2d.h" #include "../structures/samplerow.h" #include "../structures/timefrequencymetadata.h" class XYPointSet; class MultiPlot; class TimeFrequencyData; class RFIPlots { public: static void MakeDistPlot(XYPointSet& pointSet, Image2DCPtr image, Mask2DCPtr mask); template static void MakeMeanSpectrumPlot(XYPointSet& pointSet, const TimeFrequencyData& data, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData); static void MakePowerSpectrumPlot(XYPointSet& pointSet, const Image2D& real, const Image2D& imag, const Mask2D& mask, const TimeFrequencyMetaData* metaData); static void MakeRMSSpectrumPlot(XYPointSet& plot, Image2DCPtr image, Mask2DCPtr mask); static void MakePowerTimePlot(XYPointSet& plot, Image2DCPtr image, Mask2DCPtr mask, TimeFrequencyMetaDataCPtr metaData); static void MakeComplexPlanePlot(XYPointSet& plot, const TimeFrequencyData& data, size_t xStart, size_t length, size_t y, size_t yAvgSize, Mask2DCPtr mask, bool realVersusImaginary, bool imaginary); static void MakeFittedComplexPlot(XYPointSet& plot, const TimeFrequencyData& data, size_t xStart, size_t length, size_t y, size_t yAvgSize, Mask2DCPtr mask, num_t sampleFringeFrequency, bool realVersusImaginary, bool imaginary); static void MakeTimeScatterPlot(MultiPlot& plot, size_t plotIndex, const Image2DCPtr& image, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData); static void MakeTimeScatterPlot(MultiPlot& plot, const TimeFrequencyData& data, const TimeFrequencyMetaDataCPtr& metaData, unsigned startIndex = 0); static void MakeFrequencyScatterPlot( MultiPlot& plot, size_t plotIndex, const Image2DCPtr& image, const Mask2DCPtr& mask, const TimeFrequencyMetaDataCPtr& metaData); static void MakeFrequencyScatterPlot( MultiPlot& plot, const TimeFrequencyData& data, const TimeFrequencyMetaDataCPtr& metaData, unsigned startIndex = 0); private: /** * Make a distribution curve for the provided image, ignoring masked values. * @param image The image to make a distribution curve for, by binning * @param mask Mask belonging to the image * @param valuesOutput The number of pixels in the image that are in this bin * @param binsOutput The ranges of the bins; the value in valuesOutput[i] is * closer to value binsOutput[i] then it is to binsOutput[i-1] or * binsOutput[i+1], i.e., valuesOutput[i] is about the average value in the * bin. * @param binCount The number of bins to make * @param start Value that should be the limit for the lowest bin, start==end * means use min * @param end Value that should be the limit for the highest bin, start==end * means use max * @param factor A factor to scale the output (note that the outputs are * integers) * @param stretch A factor that is applied to all pixel-values before binning */ static void Bin(Image2DCPtr image, Mask2DCPtr mask, std::vector& valuesOutput, std::vector& binsOutput, size_t binCount, long double start = 0.0, long double end = 0.0, long double factor = 1.0, long double stretch = 1.0) throw(); RFIPlots() = delete; }; #endif aoflagger-v3.4.0/util/plot.cpp0000644000175000017500000001704314507760372015000 0ustar olesoles#include "plot.h" #include #include #include Plot::Plot(const std::string& pdfFile) : _curLineFd(-1), _pdfFile(pdfFile), _open(true), _xAxisText("x"), _yAxisText("y"), _zAxisText("z"), _xRangeHasMin(false), _xRangeHasMax(false), _yRangeHasMin(false), _yRangeHasMax(false), _zRangeHasMin(false), _zRangeHasMax(false), _cbRangeHasMin(false), _cbRangeHasMax(false), _xRangeMin(0.0), _xRangeMax(0.0), _yRangeMin(0.0), _yRangeMax(0.0), _zRangeMin(0.0), _zRangeMax(0.0), _cbRangeMin(0.0), _cbRangeMax(0.0), _clipZ(false), _logX(false), _logY(false), _logZ(false), _hasBoxes(false), _fontSize(24) {} Plot::~Plot() { Close(); } void Plot::Close() { if (_open) { CloseCurFd(); char tmpPlotFile[] = "/tmp/plot.plt-XXXXXX"; const int fd = mkstemp(tmpPlotFile); if (fd == -1) { std::cerr << "mkstemp returned -1" << std::endl; throw; } std::stringstream header; header << "set term postscript enhanced color"; // font \"Helvetica"; <-- // that did not work with // some gnuplots. // if(_fontSize>0) // header << "," << _fontSize; // header << "\""; header << "\nset title \"" << _title << '\"' << "\nset pm3d map" // at s << "\nset palette rgbformulae 33,13,10" << "\nset xlabel \"" << _xAxisText << '\"' << "\nset ylabel \"" << _yAxisText << '\"' << "\nset cblabel \"" << _zAxisText << '\"' << "\nset datafile missing \"?\"" << "\nset origin -0.05,-0.1" << "\nset size 1.0,1.2" << "\nset output \"" << _pdfFile << "\""; for (std::vector::const_iterator i = _extraHeaders.begin(); i != _extraHeaders.end(); ++i) header << *i; if (_logX) header << "\nset log x"; if (_logY) header << "\nset log y"; if (_logZ) header << "\nset log z"; if (_xRangeHasMin || _xRangeHasMax) { header << "\nset xrange ["; if (_xRangeHasMin) header << _xRangeMin; header << ":"; if (_xRangeHasMax) header << _xRangeMax; header << "]"; } if (_yRangeHasMin || _yRangeHasMax) { header << "\nset yrange ["; if (_yRangeHasMin) header << _yRangeMin; header << ":"; if (_yRangeHasMax) header << _yRangeMax; header << "]"; } if (_zRangeHasMin || _zRangeHasMax) { header << "\nset zrange ["; if (_zRangeHasMin) header << _zRangeMin; header << ":"; if (_zRangeHasMax) header << _zRangeMax; header << "]"; } if (_cbRangeHasMin || _cbRangeHasMax) { header << "\nset cbrange ["; if (_cbRangeHasMin) header << _cbRangeMin; header << ":"; if (_cbRangeHasMax) header << _cbRangeMax; header << "]"; } if (_hasBoxes) { header << "\nset boxwidth 0.3"; } if (_lineTypes.size() > 0) { switch (_lineTypes[0]) { case Line: case Scatter: case Boxes: header << "\nplot \\"; break; case Grid: header << "\nsplot \\"; break; } for (unsigned i = 0; i < _lineFiles.size(); ++i) { if (i != 0) header << ",\\"; switch (_lineTypes[i]) { case Line: header << "\n\"" << _lineFiles[i] << "\" using 1:2 title \"" << _lineTitles[i] << "\" with lines lw 3"; break; case Scatter: header << "\n\"" << _lineFiles[i] << "\" using 1:2 title \"" << _lineTitles[i] << "\" with points"; break; case Boxes: header << "\n\"" << _lineFiles[i] << "\" using 1:2 title \"" << _lineTitles[i] << "\" with boxes fs solid 1.0"; break; case Grid: header << "\n\"" << _lineFiles[i] << "\" using ($1):($2):($3) title \"" << _lineTitles[i] << "\" with pm3d lw 3"; break; } } header << "\n"; Write(fd, header.str()); std::cout << "gnuplot" << std::endl; ExecuteCmd((std::string("gnuplot ") + tmpPlotFile).c_str()); std::cout << "mv" << std::endl; ExecuteCmd( (std::string("mv ") + _pdfFile + " " + _pdfFile + ".ps").c_str()); std::cout << "ps2pdf" << std::endl; ExecuteCmd( (std::string("ps2pdf ") + _pdfFile + ".ps " + _pdfFile).c_str()); std::cout << "rm" << std::endl; ExecuteCmd((std::string("rm ") + _pdfFile + ".ps").c_str()); } _open = false; } } void Plot::Show() { ExecuteCmd((std::string("./kpdf ") + _pdfFile).c_str()); } void Plot::CloseCurFd() { if (_curLineFd != -1) { close(_curLineFd); } } void Plot::StartLine(const std::string& lineTitle) { CloseCurFd(); char tmpLineFile[] = "/tmp/line.txt-XXXXXX"; _curLineFd = mkstemp(tmpLineFile); if (_curLineFd == -1) { std::cerr << "mkstemp returned -1" << std::endl; throw; } _lineFiles.push_back(tmpLineFile); _lineTitles.push_back(lineTitle); _lineTypes.push_back(Line); _curType = Line; } void Plot::StartScatter(const std::string& lineTitle) { CloseCurFd(); char tmpLineFile[] = "/tmp/line.txt-XXXXXX"; _curLineFd = mkstemp(tmpLineFile); if (_curLineFd == -1) { std::cerr << "mkstemp returned -1" << std::endl; throw; } _lineFiles.push_back(tmpLineFile); _lineTitles.push_back(lineTitle); _lineTypes.push_back(Scatter); _curType = Scatter; } void Plot::StartBoxes(const std::string& lineTitle) { _hasBoxes = true; CloseCurFd(); char tmpLineFile[] = "/tmp/line.txt-XXXXXX"; _curLineFd = mkstemp(tmpLineFile); if (_curLineFd == -1) { std::cerr << "mkstemp returned -1" << std::endl; throw; } _lineFiles.push_back(tmpLineFile); _lineTitles.push_back(lineTitle); _lineTypes.push_back(Boxes); _curType = Boxes; } void Plot::StartGrid(const std::string& lineTitle) { CloseCurFd(); char tmpLineFile[] = "/tmp/line.txt-XXXXXX"; _curLineFd = mkstemp(tmpLineFile); if (_curLineFd == -1) { std::cerr << "mkstemp returned -1" << std::endl; throw; } _lineFiles.push_back(tmpLineFile); _lineTitles.push_back(lineTitle); _lineTypes.push_back(Grid); _curType = Grid; } void Plot::PushDataPoint(long double x, long double y) { if (_curLineFd == -1) throw; std::stringstream s; s << x << "\t" << y << std::endl; Write(_curLineFd, s.str()); } void Plot::PushDataPoint(long double x, long double y, long double z) { if (_curLineFd == -1) throw; if (_clipZ) { if (_zRangeHasMin && z < _zRangeMin) z = _zRangeMin; if (_zRangeHasMax && z > _zRangeMax) z = _zRangeMax; } std::stringstream s; s << x << "\t" << y << "\t" << z << std::endl; Write(_curLineFd, s.str()); } void Plot::PushUnknownDataPoint(long double x, long double y) { if (_curLineFd == -1) throw; std::stringstream s; s << x << "\t" << y << "\t?" << std::endl; Write(_curLineFd, s.str()); } void Plot::PushDataBlockEnd() { Write(_curLineFd, "\n"); } void Plot::AddRectangle(long double x1, double y1, double x2, double y2) { std::stringstream s; s << "\nset object " << (_extraHeaders.size() + 1) << " " "rectangle from " << x1 << "," << y1 << " to " << x2 << "," << y2 << " front lw 0 fc rgb \"#FF00FF\" fillstyle solid 1.0 noborder"; _extraHeaders.push_back(s.str()); } void Plot::ExecuteCmd(const std::string& cmd) const { if (system(cmd.c_str()) != 0) throw std::runtime_error("system() returned non-zero"); } aoflagger-v3.4.0/util/multiplot.cpp0000644000175000017500000000112114507760372016041 0ustar olesoles#include "../util/multiplot.h" MultiPlot::MultiPlot(XYPlot& plot, size_t plotCount) : _legends(plotCount), _points(plotCount), _plotCount(plotCount), _plot(plot) {} void MultiPlot::Finish() { for (size_t i = 0; i < _plotCount; ++i) { if (!_points[i].empty()) { _plot.StartLine(_legends[i], _xAxisText, _yAxisText, XYPointSet::DrawPoints); PointList& list = _points[i]; for (PointList::const_iterator p = list.begin(); p != list.end(); ++p) { _plot.PushDataPoint(p->x, p->y); } list.clear(); } } } aoflagger-v3.4.0/util/f2c.h0000644000175000017500000001133314507760372014135 0ustar olesoles/* f2c.h -- Standard Fortran to C header file */ /** barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed." - From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) */ #ifndef F2C_INCLUDE #define F2C_INCLUDE typedef long int integer; typedef unsigned long int uinteger; typedef char* address; typedef short int shortint; typedef float real; typedef double doublereal; typedef struct { real r, i; } complex; typedef struct { doublereal r, i; } doublecomplex; typedef long int logical; typedef short int shortlogical; typedef char logical1; typedef char integer1; #ifdef INTEGER_STAR_8 /* Adjust for integer*8. */ typedef long long longint; /* system-dependent */ typedef unsigned long long ulongint; /* system-dependent */ #define qbit_clear(a, b) ((a) & ~((ulongint)1 << (b))) #define qbit_set(a, b) ((a) | ((ulongint)1 << (b))) #endif #define TRUE_ (1) #define FALSE_ (0) /* Extern is for use with -E */ #ifndef Extern #define Extern extern #endif /* I/O stuff */ #ifdef f2c_i2 /* for -i2 */ typedef short flag; typedef short ftnlen; typedef short ftnint; #else typedef long int flag; typedef long int ftnlen; typedef long int ftnint; #endif /*external read, write*/ typedef struct { flag cierr; ftnint ciunit; flag ciend; char* cifmt; ftnint cirec; } cilist; /*internal read, write*/ typedef struct { flag icierr; char* iciunit; flag iciend; char* icifmt; ftnint icirlen; ftnint icirnum; } icilist; /*open*/ typedef struct { flag oerr; ftnint ounit; char* ofnm; ftnlen ofnmlen; char* osta; char* oacc; char* ofm; ftnint orl; char* oblnk; } olist; /*close*/ typedef struct { flag cerr; ftnint cunit; char* csta; } cllist; /*rewind, backspace, endfile*/ typedef struct { flag aerr; ftnint aunit; } alist; /* inquire */ typedef struct { flag inerr; ftnint inunit; char* infile; ftnlen infilen; ftnint* inex; /*parameters in standard's order*/ ftnint* inopen; ftnint* innum; ftnint* innamed; char* inname; ftnlen innamlen; char* inacc; ftnlen inacclen; char* inseq; ftnlen inseqlen; char* indir; ftnlen indirlen; char* infmt; ftnlen infmtlen; char* inform; ftnint informlen; char* inunf; ftnlen inunflen; ftnint* inrecl; ftnint* innrec; char* inblank; ftnlen inblanklen; } inlist; #define VOID void union Multitype { /* for multiple entry points */ integer1 g; shortint h; integer i; /* longint j; */ real r; doublereal d; complex c; doublecomplex z; }; typedef union Multitype Multitype; /*typedef long int Long;*/ /* No longer used; formerly in Namelist */ struct Vardesc { /* for Namelist */ char* name; char* addr; ftnlen* dims; int type; }; typedef struct Vardesc Vardesc; struct Namelist { char* name; Vardesc** vars; int nvars; }; typedef struct Namelist Namelist; //#define abs(x) ((x) >= 0 ? (x) : -(x)) //#define dabs(x) (doublereal)abs(x) //#define min(a,b) ((a) <= (b) ? (a) : (b)) //#define max(a,b) ((a) >= (b) ? (a) : (b)) //#define dmin(a,b) (doublereal)min(a,b) //#define dmax(a,b) (doublereal)max(a,b) //#define bit_test(a,b) ((a) >> (b) & 1) //#define bit_clear(a,b) ((a) & ~((uinteger)1 << (b))) //#define bit_set(a,b) ((a) | ((uinteger)1 << (b))) /* procedure parameter types for -A and -C++ */ #define F2C_proc_par_types 1 #ifdef __cplusplus typedef int /* Unknown procedure type */ (*U_fp)(...); typedef shortint (*J_fp)(...); typedef integer (*I_fp)(...); typedef real (*R_fp)(...); typedef doublereal (*D_fp)(...), (*E_fp)(...); typedef /* Complex */ VOID (*C_fp)(...); typedef /* Double Complex */ VOID (*Z_fp)(...); typedef logical (*L_fp)(...); typedef shortlogical (*K_fp)(...); typedef /* Character */ VOID (*H_fp)(...); typedef /* Subroutine */ int (*S_fp)(...); #else typedef int /* Unknown procedure type */ (*U_fp)(); typedef shortint (*J_fp)(); typedef integer (*I_fp)(); typedef real (*R_fp)(); typedef doublereal (*D_fp)(), (*E_fp)(); typedef /* Complex */ VOID (*C_fp)(); typedef /* Double Complex */ VOID (*Z_fp)(); typedef logical (*L_fp)(); typedef shortlogical (*K_fp)(); typedef /* Character */ VOID (*H_fp)(); typedef /* Subroutine */ int (*S_fp)(); #endif /* E_fp is for real functions when -R is not specified */ typedef VOID C_f; /* complex function */ typedef VOID H_f; /* character function */ typedef VOID Z_f; /* double complex function */ typedef doublereal E_f; /* real function with -R not specified */ /* undef any lower-case symbols that your C compiler predefines, e.g.: */ #ifndef Skip_f2c_Undefs #undef cray #undef gcos #undef mc68010 #undef mc68020 #undef mips #undef pdp11 #undef sgi #undef sparc #undef sun #undef sun2 #undef sun3 #undef sun4 #undef u370 #undef u3b #undef u3b2 #undef u3b5 #undef unix #undef vax #endif #endif aoflagger-v3.4.0/util/logger.cpp0000644000175000017500000000210214507760372015267 0ustar olesoles#include "logger.h" #include enum Logger::LoggerLevel Logger::_coutLevel = Logger::InfoLevel; bool Logger::_logTime = false; Logger::LogWriter Logger::Debug; Logger::LogWriter Logger::Info; Logger::LogWriter Logger::Warn; Logger::LogWriter Logger::Error; Logger::LogWriter Logger::Fatal; Logger::LogWriter Logger::Progress; void Logger::SetVerbosity(VerbosityLevel verbosityLevel) { switch (verbosityLevel) { case QuietVerbosity: _coutLevel = NoLevel; break; case NormalVerbosity: _coutLevel = InfoLevel; break; case VerboseVerbosity: _coutLevel = DebugLevel; break; } } void Logger::outputTime(bool toStdErr) { const boost::posix_time::ptime t( boost::posix_time::microsec_clock::local_time()); const std::string str = boost::posix_time::to_simple_string(t); if (toStdErr) std::cerr << str << ' '; else std::cout << str << ' '; } aoflagger-v3.4.0/util/multiplot.h0000644000175000017500000000172014507760372015513 0ustar olesoles#ifndef MULTIPLOT_H #define MULTIPLOT_H #include "../structures/types.h" #include #include "../plot/plotmanager.h" class MultiPlot { public: MultiPlot(XYPlot& plot, size_t plotCount); void AddPoint(size_t plotIndex, num_t x, num_t y) { _points[plotIndex].push_back(Point(x, y)); } void SetLegend(int index, const std::string& title) { _legends[index] = title; } void Finish(); XYPlot& Plot() { return _plot; } void SetXAxisText(const std::string& text) { _xAxisText = text; } void SetYAxisText(const std::string& text) { _yAxisText = text; } private: MultiPlot(const MultiPlot&) = delete; MultiPlot& operator=(const MultiPlot&) = delete; struct Point { Point(num_t _x, num_t _y) : x(_x), y(_y) {} num_t x, y; }; typedef std::vector PointList; std::vector _legends; std::vector _points; size_t _plotCount; XYPlot& _plot; std::string _xAxisText, _yAxisText; }; #endif aoflagger-v3.4.0/util/stopwatch.h0000644000175000017500000000141514507760372015477 0ustar olesoles#ifndef STOPWATCH_H #define STOPWATCH_H #include #include class Stopwatch { public: Stopwatch(); explicit Stopwatch(bool start); ~Stopwatch(); void Start(); void Pause(); void Reset(bool start = false); std::string ToString() const; std::string ToShortString() const; long double Seconds() const; std::string ToDaysString() const; std::string ToHoursString() const; std::string ToMinutesString() const; std::string ToSecondsString() const; std::string ToMilliSecondsString() const; std::string ToMicroSecondsString() const; std::string ToNanoSecondsString() const; private: bool _running; boost::posix_time::ptime _startTime; boost::posix_time::time_duration _sum; }; #endif aoflagger-v3.4.0/data/0000755000175000017500000000000014516225226013237 5ustar olesolesaoflagger-v3.4.0/data/example-plot-result.py0000644000175000017500000000220014507760372017534 0ustar olesolesimport aoflagger as aof import matplotlib.pyplot as plt import numpy import sys nch = 256 ntimes = 1000 npol = 2 aoflagger = aof.AOFlagger() path = aoflagger.find_strategy_file(aof.TelescopeId.Generic) strategy = aoflagger.load_strategy_file(path) data = aoflagger.make_image_set(ntimes, nch, npol * 2) # Several consecutive values at the same frequency are increased # in amplitude to simulate a RFI source. These values define # the channel and the start and duration of the added signal. rfi_y = int(nch * 0.3) rfi_x_start = int(ntimes * 0.2) rfi_x_end = int(ntimes * 0.4) rfi_strength = 1 # 1 sigma above the noise for imgindex in range(npol * 2): # Initialize data with random numbers values = numpy.random.normal(0, 1, [nch, ntimes]) # Add fake transmitter values[rfi_y, rfi_x_start:rfi_x_end] = ( values[rfi_y, rfi_x_start:rfi_x_end] + rfi_strength ) data.set_image_buffer(imgindex, values) flags = strategy.run(data) flagvalues = flags.get_buffer() flagvalues = flagvalues * 1 plt.imshow(values, cmap="viridis") plt.colorbar() plt.show() plt.imshow(flagvalues, cmap="viridis") plt.colorbar() plt.show() aoflagger-v3.4.0/data/example.py0000644000175000017500000000314414507760372015254 0ustar olesolesimport aoflagger as aof import numpy print("Flagging with AOFlagger version " + aof.AOFlagger.get_version_string()) nch = 256 ntimes = 1000 aoflagger = aof.AOFlagger() # Load strategy from disk (alternatively use 'make_strategy' to use a default one) path = aoflagger.find_strategy_file(aof.TelescopeId.Generic) strategy = aoflagger.load_strategy_file(path) data = aoflagger.make_image_set(ntimes, nch, 8) print("Number of times: " + str(data.width())) print("Number of channels: " + str(data.height())) # When flagging multiple baselines, iterate over the baselines and # call the following code for each baseline # (to use multithreading, make sure to create an imageset for each # thread) # Make eight images: real and imaginary for 4 pol for imgindex in range(8): # Initialize data values = numpy.zeros([nch, ntimes]) data.set_image_buffer(imgindex, values) flags = strategy.run(data) flagvalues = flags.get_buffer() flagcount = sum(sum(flagvalues)) print( "Percentage flags on zero data: " + str(flagcount * 100.0 / (nch * ntimes)) + "%" ) # Collect statistics # We create some unrealistic time and frequency arrays to be able # to run these functions. Normally, these should hold the time # and frequency values. timeArray = numpy.linspace(0.0, ntimes, num=ntimes, endpoint=False) freqArray = numpy.linspace(0.0, nch, num=nch, endpoint=False) qs = aoflagger.make_quality_statistics(timeArray, freqArray, 4, False) qs.collect_statistics( data, flags, aoflagger.make_flag_mask(ntimes, nch, False), 0, 1 ) try: qs.write_statistics("test.qs") except: print("write_statistics() failed") aoflagger-v3.4.0/data/testpython.sh0000755000175000017500000000016614507760372016030 0ustar olesolesexport LD_LIBRARY_PATH=`pwd`/../build export PYTHONPATH=`pwd`/../build/python:${PYTHONPATH} python3 falsepositives.py aoflagger-v3.4.0/data/applications/0000755000175000017500000000000014516225226015725 5ustar olesolesaoflagger-v3.4.0/data/applications/rfigui.desktop0000644000175000017500000000035714507760372020620 0ustar olesoles[Desktop Entry] Type=Application Name=AOFlagger GUI Comment=Visualize radio data & RFI algorithms Comment[nl]=Visualiseer radiodata & RFI algoritmes Icon=aoflagger Exec=rfigui Terminal=false Categories=Science;Astronomy;DataVisualization; aoflagger-v3.4.0/data/applications/aoqplot.desktop0000644000175000017500000000040614507760372021005 0ustar olesoles[Desktop Entry] Type=Application Name=AOQPlot GenericName=Radio data analyzer Comment=Visualize quality info for radio data Comment[nl]=Analyseer de kwaliteit van radiodata Icon=aoqplot Exec=aoqplot Terminal=false Categories=Science;Astronomy;DataVisualization; aoflagger-v3.4.0/data/icons/0000755000175000017500000000000014516225226014352 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/0000755000175000017500000000000014516225226016011 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/64x64/0000755000175000017500000000000014516225226016604 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/64x64/apps/0000755000175000017500000000000014516225226017547 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/64x64/apps/aoqplot.png0000644000175000017500000000475014507760372021750 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝ  Ov# uIDATxÚí›klTÇÇs÷qwý6صà°ÁY6$¦óHè#éC ¦MÛi›¦J¢,MÔPµ‘šŠTMPó•4O¬©¢ÒP!ŠhDŠœðR9)ï€m ÁÆû˜~¸wïîÞ½»^ð°–#×»sçÌÌÎùÏ™3»pKnÉHKCºp¸+¸FãÀEŠVNA`÷hà-àåaêhÑ•§FËäúªù†©çW€|»À° ”ŒžˆX5uzÞä‰räÞ2Cß™›}òªÉl †¡ë#@Êz¤œŠ\ÿ%CçΛ€U€lÎ4;œ}üJƒ)‘Á;Òƒœ ®°úf˜¬bñþ ØSo|vÿ5êΜ³ó4›.*¼7 ¡ðº¾ÓÜTÌX^7صá}=¦•7ÆpÝR€æ|Ý©\c²àéÆÄOÜhì¦÷ °µQß ø%eúsþ¨ðÖËbà è>v[“!ªóbitq ¬8 [OSl»‘ÁNH<Àûž¹ ÙDSôù†ºÀï¹kî³*|³R¯C^öëÑ\Ñ`ù RN"7Gó}"ŠÐˉåF›Ã×mÆÞèד5¹ˆœìð@¨2‡Ø‹Äca5ñ \Ú µLÓeò³aœÛhUpÝð2ÛlOrËB}°.´lc€Ÿèq¡ˆ™¸ŒãQ²Ó SoÓw]odùåL£]Ýuà)àŸ@/S%t>51þû­ð¹í¢€œ|Ë5ùz8l ‡€l½NFµ’05{AŠp…„Êó 5]8Â+^|€-43;ð(À/æh\/íà›ר°/ËLü pçõר‡ìpg>ìë7‘†€L\ò±Àb·Iõä?1ï| ðƒÒlXÓ¤™hÐ9ÚJÅ‘åxYf xéÇK§øÜªá¿lÐ’arf–Tàê·f7UGI6àÔ˜¹ÞñOöóñ²Í@4^pô"nY«ø»÷Û£Éð™V£ºuÄX:¬Z1þº`½G¤…éÛ€m¼Ëz=©á²Û¬A›Ãš*_—ðS¡í R…æpj^ùãZýÝ:•G3Ù‡œSB˜|`ï`¿ßHš î¸{ìÈ™V øO ;…KZAãõ3D*¨Ö3[2f¯ê ¨ôž Ö“ÿv&ÔvoÇ&Ñåj€º NØW“ÖTºò"|l×Xå1j¦§påmzm× ˆW´O€AÀ‚{Kíðr!Ì®1>ªI¢ëcÃ{g”Ú¬žp.9áÉÆÚ¬J¡ïoÐ8jiïÍÉ}!,štn´sºª´ ¬œe|:5‰®Ç²° öÚ]p°œÂbCPø”B^&X›"êõ0.º× ¼z\1Œáß`ë2ù©„ý“´ –„ør];+‹Jft쟗GkôÌ I$4|Õ㌌TÕ0Mß|Ã>^«5#+aÆx£V$,ÍO~Ä^c³!‰HMœísÂ9€P.¨Ì}uÖ t^†ÏÂ@ÏVÀÛcü(Uá¾"}L"bô XUsarlŸn:¸Øàö"ãÀâH0„eí󴸋ÐÌØTc½=ž®í!×. G{EæP Çfè‡23Úºâ‚ó@:4³ ZÚ ¶"*oOÖT–k;€8am9|­$Îqê š%×8ù_[F¡ÍàrGÌKXBÂýi¾mó“`9@V~¬ŽÈ"UØÒUY €o÷Òr•“N'½2o+†æ"Ó8¢áÕ‰W–.2ŒiFœ¡Øô§ev~b]BýÏPm ‘Lãoxq™ÔÊ~à+Ò+tÁö9¦1¨V¸—œñáF^+OÊ7 †Ò*6\Z6Å2¥ŠÑŠÄ÷+ñ24Z‘^žάŠÓ¿ïIJ±öï_—xƒ–Y!—ž•þ.„bK>ß-óP¸%á#{ŸÀàû@»NÊV§rÐý jD‹&6±.ÎÚ£\`©dP|Qµÿè@Ø2â[‚Dbö´ÃÜ7#RÑ2Ø'û‹õ98ò°æj"ÎbZ’ C×¼ðeùÜuÀj— 1aÄ6s•eNln³L‡ˆ$2Úv-üù‘Æ•%&âPë¤-@ ZŒ®šôªí€<ðçð®z¸*|õ-‹‹¡üH"y1¾ž?I8Öw @(ûp$ÆÀ"tq6˜Y^“ê!~ß4h¼Z6AW€Dô‰ÀE{ñ³ƒlÀþ×£D‚¹Ø"ælðKè Àà•ăsg@í8zØà/€|g7¢ûrêŽð¹.x¼Ö=´rœ ‚Òˆ©ŸÄA'|Ê›´UN'ò¹ˆ’ èbnÊAè퀾A¨­ƒ£‡Àwª†&°giíS)ž…ÀZ$›9©»œÙ#_¾ÈKà¥-)áü¥¡uÁ  €î$˜P¼ŠþÈ;ç/“rqçBÙxÄñO™fªjG»¤°6u ÊÊájÆàÒäÝàºñíuaž{7¢{`dÒø|09üéw¨ºœY¹î1ÄÊï€Ï羸:ݪ°pî~ð'@Qµnƒ <òô|ÁˆÉĦð“~é¤xúψ€Îö]›^§4[ÀU cŠÁÓ 'Ï1¢RXkü›­ºá™·!# >ïž^§´à€Þ~ð'ñ0›ªgÃ⦞øb¶kT4€§ ¦·À €Á¸œCÆá€@’_Š›µN÷0ò2íÏ‚bƒÞ+)VZp@OòŒv±M„8 èOlA“ „, ]P& Y€LDÀl: ¦ ñ8€4³%\ô;FéÏ®Aü€ôE$DlNÈ)Õ‚t§å€?€²Ç¥ (§"PœS¾`z Ú@éŒt‡@š€jÅnÁƒi€Ë¡0 *O€Á49 ¸TÍê «„ ­DJ€³í—é*}Ü’4—ÿ1°Æ‰LËÚIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/apps/aoflagger.png0000644000175000017500000000651214507760372022216 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝÄ—GÜ ×IDATxÚíšytUƯ»: Š(¢‚‚(ˆËÅ !¨0 Ìà€9¸Äý€¢2ÂÃƒŽ¢£à€¨¨è¸"ƒ#”E=Šâq ¢‘=½Ýù£ªº«ª_'’ãðÎétW¥Þr¿w—ïÝ[Š\›N}BÀÅÀÀ¡@¨@øˆqLv¿öY ÚGbìI°,÷=ÛÇÁ­?QošªEÀ4`€sGRýÁB°Î^Ê¢ÂtÄ!ƒHòÜßqYqú‡„Ê‘;ê¡wÝþ¾ ¨.ÈO œDõZç.†ü]S°úá ‹6[ Z<”¿¤Õµ ­ò‹€{³‰NBßÐd$Â5j›rFxçúªß\øó¢ÜH ¿ 8ÓÙ½`,èº Iml {Äâòßl×5ùÀË@%š‰^m¨€£ ;/ÎßIí¿àɨ ð* ª`W>|×â¡€&(PÂ]¿¡Ú¿êÙÄÐ$R+K§W€c|Ž.Ý^D3 U1„€¤Ç+ Ì? ÊÛ8=“Ðr- ûgÆ,ͧ@ëRXSÝúK†)ŸÂÐðØ'?Kø^@Oƒ÷¦„ núg‰C\á{ôäxàP$=°xç^(o Ęý]q8l.2ÆŸÁ5É`Å),mÏÄX˜[J:Ò`ੵÞý , ¸Èo¶Ú÷îÈ2\43=5¨“1œž ¬&†lh–éBI:°ÜﶃèR¥RHà óÜlp|ߢo"B7dam'˜èã?1 ƒþ?¿Œ§g.ÏJ¨: l FòÎ)”Ò)cþ>AõÿNÚÊoŠÎZ—gQýb3Öô. ¨ÊH4_˜:ˆâîÀµ ˜R#¥NÐng˺„K%Î…AI±dÎ"V×"ý’±‹ûìðFvçs©¡çB§ÿÀ~ž"»óxÀwX€fÀþ×qG ¢x[a¾À 4›B5­¹í%txÜ@cÂçvÏýl’´ðµFU‹ÍCQaìúŽó]ôVÂ(üÇhºx5´¸Šæ·{<‡ˆ¢X®!#Ôê z‹¢ å#âxÿ›ç•±qnYîŒÞÂöà½|[Û ±!U6eµm‰†¨ä^€r4Ç£a㣀½~oüpdot5&Ðb“à 0o•½Á}uq\ì¢ !ÿÈ TU€ïÊ#ÉÝ غ w8ˆ_°ÏÑ´wCoË+‡ö_˜Ê8>ËHˆ°¿›]Ë$”-|€ïðåâ9ôèvNÝä+vXpÜçtG¡Ú¬E‚iµuÍ ·Å %Œfå¶—\áÛþŽº˜%6?QA†{C3¢@Á(¨ ir#¢æÅÌZ€¯ßÅQ§÷ƒÿòEŽÚ´Ê`œ2›-Ê‘­×¢¼ó*õ¦.ád&/s€æîZ¾|â!æJ*”JÒÇú‹'ßRÅÇY V8÷¼™ QöŸò•/rÀ’Ù€æ  ÚÃN¡ÍFK±?s>pà;Y áræ7oUžÓ{$_·H[m~,ãĨ:@Ûy](wïµ/Qü!.tõ©¾ ¯GdzÀ77€Ã8‰3Fe&8pb}ÙGÏQÌX¢x (1Ä]7·°Ð9Œ,ÏÄ:„v¶vè½…ôŒŒY°}?À‰yQ$šç__U[½s¬~Ú—ØÇpWõÅÙýh>ý÷AâÿY`Û”A¬VÏ ˜±ŒA±ÓM%e)°ÐX†fvóX›1}ï/*ÃYÍáVPÄh”döcw„-ÞëcñW „?: „Á…»Hx…w}ÀV%tw;¸ÎNlµ/.ŸÎ4ËPŒË¡šäåá}Ÿ€–¾õæœÅE•p…ÊÌÛ͹¡  ÙšmÂ¥¯‘2ŒÎ}+a„!·°¬r"3+;çÎ@>¹“…J˜é,L!T hú]3¢Y œd8bJ–ß^ßmÜIlj€(†úrw¶)²³€©~eßÚΗÛ3¶Ý x0˜EP‰½ËÉŽf.ʈÑñ ˆ)øÇs؆IlŽæQœ¥6 €ùÀ8`ºÒ ØäZyRoA2s¤ÏcÛi¯U“?%øb‘4¶ÓûÁi}i\H¢‰žÜü[PÌqÖÒXfš|Ë‹*Éß0%ÚVy ªý³À%hŸÐ—£¹x$E\ÖÍ«òx×Úe´¸÷x¤¦Ùt£Ò©ýy]‘v⎠+W¡¹Ë9î‹g=—Ÿ¦4`çð? è`8[œ‡¦$ ¼ÛïQì’ù¶€Y¸ã”ÞÂ6ȤÄÁ6aSÂJ·8³ç)¡›øí^”0íÛ4F6r=šûM…‘ۜĂiç;¡™›Ã‘÷ÇJ†OЬµLÏâ7ÜÅ›h¶©ž¼»ó¹4TÂk¢üZ$ õÍT® Á¢êRd*è,˲®b4¹}ì±öwê ¡@˜”üëþ~7Å!·ìx #±<ˆZlÕ?‘?¾ä8ºÆ-Æ"Îóöç«h·8p¶S²€ˆSÂNÑA»ù²×Ð7äqjÃ$¾ÂYà žçüæy‹Cd­~,—`H„/a)•ü‡^ f(¹¹#šå;N%ØlèÁæ$4 ÊMùµ4ìŒÿšÓMØ3Ž¡˜,L)‚ ¹Û’h²7¨_ÿØÛ 3`Ï÷–§k›z\0‚ýy-c±PœïXÍ9p>¿Y^/ñ“7ö°£g ­÷ï~k6Ô‚°=`÷Ø¥s°;S©¶=Fè_#«{àÄG@óÈüTœX/ÑCþ“¼( Ôç'|€>º³½F0¦Þ‡äQ®; ¶HÌW8ê÷ï¡™©à;E~m Ò 1·9Ž@éQhÊI^ä¹bÐS}ÆÙ0=ÅpžŽ'½4ºÕB;daç]Dƒ|h8\té€Ú€vç·«~!—˜seu!¦Áˆ:–¾QÂQ  hžø2Eíýøƒ×ø/þ ƒöbäéìJšœ|!Ým@Þ"®‘!æ4Õ𸗀åÀQàÐ ´M4Êfó¤¥q¯[…0âe7p4½kŒþTEL—!Ôà¡Í¼± ƒg:Ûʇ0Ï ùå¿ ULîm§ÁIC#”õ0´WóãQžH'8rýÌ÷º'îxaÛŸy%³Å»ÜgÐÁ @Ø”ÉçŒK9õŠ^Ín­ÞB¶"~z¥F¾Œs%+2r„®²ø©*Ž–"Îbãï=f&q"(ò¼ó€ð{|j?E·éÆò-Z0Ým¸mA”(ÝÆcæ0I æ+Œúám/òbõ0'xY¹¡³úýè 7)úÛïü›¥è5e^àÚù\¥Ù¬IñøTZFΣÐñRŠ,ÊÜ^f`š1Di—MÈâÕ½KDžÙŠnÿ›ÆuÙ!…ß›’çˆR“’€áóù¤ŒŸWÕ•¾ëOϳ»—¶¨QÁJ¡K=?'ý¤~ê ­i4àœj ’yT!ø´[„óÇZIeÊpxè7xZ ö ¡A³Û˜Ø‡ü¬¢-ËEÀLEÄ÷[ײt6E.a£jþš•È$%Á‚EŒ [ÄHíØØ’©Û^Âèíê%üS5©Ueý+„»êE òëçR­ò™„Í/Ûj¶Kˆ<°ˆÉi©½A‘°úwî|–ú’Yܱ5ŠSœó&·¶÷c²Jæço%2ÉB0H¡!Ã=Ê–,QÐ\ÃýIZ¢-ç¯BP—ΖqÿrÌî-l½DÙè6ŸQŸÕ©Šw_óL&¢µ\†Ïâe¥Û<èKˆ›ÀgÓèì»6ú—>AÀß½cJ˜&$ŸQìî¶ bŸ®õÞ|7QSP,üOœ_íÿ&¡Y«x$•ÚKø¦múU®Ïp¼:3t›TL¢Íðå Ï+V_0aŸ6ËUýH[}¼t—šwµ? Ü}ôÉdU½„¼*[$ܹóxmϺºä@[ Ž)vëÖÒ»Ð5ƒ¿YBiøVׯUÈu]ƒ6kœ7#)>UËޝ,ì`½ì–#Ðl–*[¯XãøÂvꥺ£wN®eQÚ¤¨fók [÷«×{!ù 0)]Ìð£:ÿ#ãr^²B"žüTu4º›ÚÃjyìý[¼CÀ})Íš©pˆ6íeŸ„† ü T_GK·\uz¦ÔL}ns!}oø}C<€`a³óõ` Ð$þçòÁ™`4ôS¸¢Êx€úu)[\ÿ×B&Ã|lbÐŽêN0¼ö?x«Pâq/ß“iÎbvtˆèAñ»× ñP>ÉòÆÁæ,dq3ãMÈÖ(¾ñÛnâ÷ójîŒÍIN9;bN±°yÞâÞ[Îgž@ðð£ Ló^¼«¥uU¿€y¥Ëí½é­½Á§Ì)Ñ¡úOi!“ë˜aÍ¥u6 å°ðaí¾–îÚ^À%gr NF*] 4yg‹l½z°«x4¦»ú›JAÅ]Ì’\f’ÙÅë&ÎÚ&PPèXu«¡gŸ×’½&®Ã÷y¨Ù±V EÆÿÝ&¦lîyeëç‹¡B½ÜÍURÝZtW?ÀxxÓÜÜÞË­_#DÚˤñb:t¦’zs Îaí´pº“¢b¡qrÉÚ[Gnw7E«ÁõŸ$¿tE¨UÀœ=0×îvæ¾Æg*(èªÈ™~Æjhñ€×MFî¶v˜‡v5¸ÝÆ6˜Tƒ[ñ÷?:‹€/|ÁÁáwÔïO1&%õ‡†@ @ ‚9|Ií}r2úIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/actions/spectrum.png0000644000175000017500000001420714507760372022626 0ustar olesoles‰PNG  IHDR@@ªiqÞ„iCCPICC profile(‘}‘=HÃ@Å_[¥R*VqÈP,hqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâäè¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"€Ç„ÄL}NSð_÷ðñõ.Ƴ¼Ïý9z•¼ÉŸ@<ËtÃ"Þ žÞ´tÎûÄV’âsâ1ƒ.HüÈuÙå7ÎE‡ý<3bdÒóÄb¡ØÁr³’¡OGU£|Öe…ógµRc­{ò†óÚÊ2×i#‰E,A„5”Q…­)&Ò´Ÿðð9~‘\2¹Ê`äX@*$Çþ¿»5 “q7)œº_lûcîͺmÛvó<WZÛ_m3Ÿ¤×ÛZôèÛ.®Ûš¼\îƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}2ÔUê88F‹”½îñîžÎÞþ=Óêï¶rÂÛÑk.bKGDÿÿÿ ½§“ pHYs99ÂVtIMEä ;8D×µtEXtCommentCreated with GIMPW_IDATxÚݛ߯dÙUß?kí}Ωû£§»í¶Çf&¶0 `0c%)D$JDFQ ~I ?ðñÂ3H¼ ø Aå!Qâ”HV$ˆÑؘÉL»ûÞ¾÷VÕ9{¯ÅÃ^ûTÝžžîÛ~LIçþ¨:Uç쵿뻾ë»w‰»ó²Ç—õ'~ý-ùáß=œç€´?EМAS{Þ 7GrFrjg/ ^k¼7Þçÿ*¸Ñ>ûèsׇíû“£{ø´Çáœ=Ûg¥ÿå§½xù´³3¯xlÒùé½ásoy¿™~Ÿ"ˆ ²Ù@NíùZÁÆ’¶ç–_–v¾H»u³˜´ÁÔAvûý‡;nÖÎP‘v[qjç‰jLF»—lÏ.¨œ‹Èý8sçî¾Vdѳ³¸ŽžW…”ðÓ äÜÔ0EÌa^Ð¥âÚf\"bƒ4(õöLK ðR Äæ¸ÝRÚù"k(SE†¡¡j)H™ùƒßyðëïÿë{¿ðÁwçÿ¼ÿZð³üуv!·& C¢Þ›°)Au´´™­'O‚GçŠÃUð$à ‹!ÅÚ9æÈ\¡\rÂt¿ »¥Åjh·+óÒîCAjE–Ò&dÀÝÏÈÎÏÌ7b¦gæ¯~2Qž¶›Â¡O\|HÌ÷3åDÑÅÑÒRd9S< ºi—Ñ –ÀU‡4º8–©NÚ²T$æ*ø ¸ i[H×s ú”cpC»‡H )™ ž¾À½´gçÆU ÷æÁw@9Ëì?³Á2ÈWY‚:*ûB9t]Z€—{‚eÐ%‘o@ªc£€€äm X­NÞ:iÎHà*ÔQpáF‡Æ'u“stpiBÛuu_±¬ÔÓÆyLÔ|ÂÖ…kkétíéÓ "¼ñÆryyéççç²Ûí´”Rß~ï—Ù>JX¾MÀ–¡NÂþ3Pî: :7žV|pt¯¤+AM(-B¾jçÚR„áÒìH@¡Ž-ãµbIƒºQĽ!PÛùZ í „ù\‡qJ,yÃÎ3W>4ØË«À]^^~øöÕÕÕW€/ÿ«ŽÂr&Ô1Õ žÀò boTê¬È¾‘’<œ§Ê¼Ë”<€ vRÁ’’öBÚÍ{tßÙrlˆ´I ³"ʉ &¤ÜÒ§OŠ–Æ6óyã\Yвõ+›òÒü=ðÓÀW{À‡Àgf»y«œ ur< ,8uìÜïí)KÂæ±ûn8Ÿfží&.ü ¦³Ê’¨ŒxVìĨEpUthüÐÓ NŽçV— ÔkA©™5­"ËPÎZÄ î•\Ù& /MϹûSàÏEä‘»ÿXJé¿§ÓÓÏÛ6z0n»IË`#ÈX‡JRgGΧ™‡››vÑiÂ\8™Dœ%g®w «‚Y°ÒnL¬!¤#ÀµÏ´ îXjÕÑ*ø ØxÐ V½ÝSŒÈ†ö÷Ö¸~Y ˜ÙGÀGñïÇqðù÷×öaž© ‹àÙ±ÁÑlŒ¹PUAç|˜¹?î0WžL§˜ gÓLRc·»i , [I±E &ÄAC4ÝÀú÷zH,µA"€Å„d¡óœ'y.ÎýU`-‡Áü xmyêÉÑäädM¸ÕÉZ™´0¥Ò‚cÊ&†TÁ…”ïEËŠçVb{©\ÉæXÝÊ!D0\AR”å$ÚÏK°;â€3D„‡Ê“'OÜÝï¡ Ø$R@Á'çʘ*‹8æÔ™RaèAÈ•bÎiž™rA†¡2FÊQg´Õ}k³ÛµÆ:è^òž{Žd‡¾i¢àˆ \×€âª:>yòä×€¿¨µ~ÿnˆúïÙÁ/@rd¬ ¹¶™ Ø j R´2æ‚Ve“NÓ Œ¹²*9¸£ F ¼å²,ò‰™ôú\¯Ô“sÁs 47ôX”Éã\nwÝ}®Uõâââ⣠+¸j°(¨:I SACp¨´ç²ƒÖ5(S*TOäd¤ä$urª¤lÔÔTdç™6xCзCJö‘[z¶‹·j婽¾³›:¶¾,Ÿ<‘ÅÝÍÝ'w¿yuŽ (u‚òÈCG‚ø²‹8$±­$5aÔº$©!jˆ´ h2$ûÊ-ÇP_á¿å€{ë 8J8æš¹ ³«µÖð'wï"hƒýua|#'c±:Ƥr¢ ƒ LiaÐJ±JŽÁ·÷)’¬½SŽý†Ãàûaz;Äl[:Èt_9v–¹)-Û:ü`UÀ{ô³ã8¨âHƒ¿ƒ¶Ÿ-á.+ü;&±FˆR(šÈZQmšAÕIÉÐä†kº~éPþný>:zÝ—zà Úï¹æuà»úÉ᪈¼#ͬø‚ªÞ‘‰ÿßSÕÓ5êH6$P€xäCÁÚ̦H‹$¬Æ¨…QK¤¡ÚÑÓʨ¦öœ$_u‹íõ6ó{pA„žýŽå¦$gËlËÀ¶ ìÊð¢ ç§Tu~ÛÝß~&^û {-§Vš”m…£&»ExY ž6‹1騅AZIÜhaJ ›¼´€¥Ê” S. C#C²á„F¸~€{ˆ¢Þ#¸©ÿXvæšØÅà÷/@@¾hf_ À=h k»ÿ”yÝx“h CÅ ö!R’Úš£²f‚âlt&‹qžgv5Efª+÷†=›¡ £³<£8û’œ2&êèÈr¨çÇPoå6žOG•¢‹!mAëRx®‰}miÕß @Jé÷¦iªÀ_ÖZeY–¼Ùl–ívûôwÞÙ>ž¦íQs¡º²oª—œ¼­œ¤Â˜´òFÚq"3†žÉÄ(…sÝ“Åx0n9É I³¡Iäëe$©Q«²Û'¨ R ;¾È¡*d°!‘Úa©+ÂÐ+4¡Vª²_ÚÌ/å(¥”çHŽ¿·~áWÖÜRuܼû•¨8B;’XÜ_“£”–RÈ’ÉbŒº îŒRâ½=U¤dmàÚd2â‡r'‡ÜïeØ;?¥°Ò$ž`,{eŽ™ŸkúªÀZ‚é…N—ð$ïînÿP12›&p2•,ŒbŒZCšt^ Ž„˜á˜…Ž—Ç–žkªH! =µ&–%…—ši%öÍ7ßäòòRò]K ÒŽ„³ë´Á àÞq «Õ-â$l­"Î †cŒR[¾[Aj#S5TÃ=C]„¹¬• #£•Jo÷bðQHN­J èת>Ž£Îóü[~øá_ôÎPr†däT£%Œk©a€¹P½ûºG)L² ÑÝ R9Ó=gi&IÓðê0hE£BÀ(•3Y8•¥$Þ?Fpdm”P\Ž2X@L°äxÀ›* m¶]  49)U4TÚyý~Ý*Йu“ *¨ˆU©½hXß1°„×»ÃA*“T©möÅØháDg¦T(¦-Ͳ±t5E ^[—Ñu̵­ $ÃQª‚äÖ\ålh6¤ ²´L—"/”ÂÝý!ùªª¾!"?)"ï‹ÈºØÔ𛓴’5ròãõÉV_K`–ù”6àÈâM-æ…ó¼ã~ÚroØ3¥&‹§¡ c% •<d´f|d‡ÑÑ¡¢ÙV¸÷Á’[O1ísÆ¡€Œ\©¯¶Å¿æî_N¯u{óO<µœ¤’µ"Úìj÷v˜ …Du]{þLK3Ý7„Ge ô£Z[Z¤=§:S“0iaÈ­/HÑ -Ù°¬ Î)ú‘X •èHqZî'oƒÏ•e¨ÍÄí®såÓ<> üCø.}ºwúwžÚ‡çhm›ÉÑJ4A³¸RLÖz?Je#Ή,Œqe6"í¹0HZ#UÈZ£Yê]e;²f—ÜÐ8äBs¥sªM?W¹r2,l†åhö_wÿØÝÿØÝÿ»ÿðGîþ¿Á•èÝS´¯räØvI ‚¹6YLä<¬j°¯þ’/„ò³#ÏíØE’î‰1ºÇµ;2¤·äêèaÏIœ1ª“TAÚñ2øûw¾[ÏꇖW¡•Áºj—¬m#ÆF”I*:¡" ’Øh%õç\MŠFEµ¹Å„ªjHÏùtð4‚£Ú‰ù`Ñu3Fk#¿vðƒ9B}Q°³y¸o+“g©´aÆ,ÒØf»i„Å•zÔÓzÌ~·ÐzH“Cj¨ ¹Ý…N@¼£GŽ+…I›ƒ#NÓÜR x/À÷Ÿ¾ªªÿ<é½»ÿX½Þ¾}¼þG¸@5CU Õ„êʵm(Á Õ58 3»² T^ˆå4ÁY¬¡$G#Õ­÷î<§t0KzuH?ç°Ê4E×*´…Ö´´ãE)QD»ûºû™ˆüOw;žÿN:;ùÎAò¶=²nù*ÚfÖaÎÐÖæ(}Å•Ù;Ë삊%æjÌ–1š.˜-·š‚À:ÃwØ ;ò:"Ý‹ý?©°·¼Îþ§q@v÷?¿?zîµï<üÆ/­0«H«ë}G§7«ùFGfKTkƒ­³gnAoWi­fβ3˜TW–1 ­¬º¬àÖ•¥mã:B€"ØA LRÈâXhŽn’´–7­*°oµ)5EilBi]¬qåYú7SÚÂ/mÇíª€EŽy+3£r®ëlKì Òpp’ZcaH^×5Äb­+Ô#å¸.¦öWœ.L©Våb‹Mê×ëÍO¼§¥€µ/JE–%P^j‹¿ð8|w)š­}+ G»ÂÛzÚ†©k¹ñ1l/YÑbi-­IŒQJ3Zà ™tYW|mÂàˆ¦¬§d5ÁÃ\iu8AŒýË2—àÖvyàG¿~xøv/-¯5Jáñå¹f¨Z˽½e®c‹êìim‰·60j"Ö êšó ±ZÔötÔe9#z©µFšfpp+d5gª ,æè:_†€X˜€Ÿ¦è&çü­z³}«®x“½ÜjAí¨õ-ñÎv>¬¾AµÆ óÑ77œÛ¥Ôe=Ï{ƒ¥Qe:ìhMÂcA¶#µZ#ÆêŠ/Ÿ|žÛ·×^€ÏÇï?þ+ð·Ë²Ôtvò]bfwu`gÃú…­jºÖ[ó®çÓ*o¯mbkc+{Þ8àªNì,¯{újÕÂb«.,žWëͼ»Gù‡’ÜvºK¬J·s{óU,憂yùôp÷ÿü‡¾jz{›¸à¦«ZóP­MƒwÕÕÕbÌ–Y4ŬJ#AK Ñ6‘Óp°Öš™¢ëŒ®ýþ‘@ê¤×sß¾cyL¯ ¾ßGó6¿¾^_<Þû{ÿ£ž,<¹¸@7×mv/œ¹$>úøñY9Ù_ïkæêº¢ÓŽÓÓ§\—‰2l¹L;fÏ<¾xvµ¤ï>ΧewõdD¦=:mùöù Ý<áê"3n¶|pÿŠïÏðìûùÔ$ß<9{Ƹ¹àéuâj¾¢äwáÙ<±Ý,sÆ‹oY®žÜÔñôsáê£íÕžër³ºmµïzÿ—¯Jòà®Zbš&‘ó;/E¼Æg‹ÈÙ0 ŸT¶‰ŒpÇÉóã“» òÿëÇ«ðüñÞ{ïüûÐÓ?ÿèÑ#ùìg?+À?þ%ðæsúqàŸÿJU‡ÓÓS~xø7Ç÷ ª›xí À×ã¿ý¾ˆÜî³ß/yýÜýû÷EDNãÞ¾÷óÊñèëì›ßü&¡~¸üøã¿þøñ㼜Äͯqÿ&ž[Ü}sssóÏÂvû0Ÿkf;à™ˆ\ÇjõÛ"ò÷¡QÎÜýÍç`ÿ×ñš_^^Nî~Áz7tÌ–=^ëñî»ïü[ீ.€ïÅË„õ1Ïó¿ ·é¡»1<Èw€ÿÜn@'±Gá,êñž‡/úlwÿÅXåù\lzºÜOCÓ¼òñ?QÜHª8ÝgIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/actions/showpq.png0000644000175000017500000000405714507760372022307 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 2ªQ‘¸¼IDATxÚíÛ{ŒÜUðÏof·[K±, ”b)Py »ÐèSbšHÓŠ˜øy¨ `Áðjýµ yXy¥[lb$Fňµ ‰ò(mÑyhD ´´¥e¡lwÙ™ë÷7v2v·û˜-SØ“ü2¿™¹wî=ßû½çœ{Îü5"gq\Âèx ¥¸³ÆMj€™äG°*¡¸f$÷í òµÀjB3›çaF+g4±y «VÞ÷ (gÆæüoù_ \sw§t¾oPbA1cŽÄË4øÜ[|¥™p+ž ð¾>ËêVf¬cï3H¦ Ç+ìÞÁô"_n¢x4+WT5ÀÒÈ‚7 ÌÌc,Fá„2 Ú™^ÇW›(L晿öˆš cÁ³­Ìx…½Ç‘ É&ZÄ« ogú»œÓL~2O÷ˆš`iô ÌÊãàŠ Â‰${D1¬iœÛLî8–/ãÝ]Ò TÎíVÖqäåÙªoO:± ¿'´’$lÜÞÆÍwÓºK2 $M¬/2+Á!]´Éadƈ½ãÖÚÆÔ!œ×İŒí»"J,XQÇQݱ \ XG(n$—cS‘[:Y°˜Í»2¼^äóphÚç°_f,Ë1%Ï7eÄx–=ÅÖaÀùì_àèjþf ÉqkŽÑWôýý 6Dñv‘ÛñƒE¼QUÎæ¬„EņI8­}‹XŽßn3–­¸6g’þ¬V+ž¯If*î ,®«òÁâWqÕVu;«T2pSÜ ÜrÌnaioÇée0ïSqÏ7%ŒÀPLÊF±é‚j)! 9.3?•i37ÀÖâ¼ý9¾/Ê÷€0'[ý²ÏÆaÏ€¹\»W5x‡/öD®tXYƒ;°oDöÏëdL w¦ýHŸ÷b ¤S0™c°GÅyê䄟˜Ž+ñþÚ¾³(Ons48žÞvü¿«Ž9?æõ]¦KÈMá‚„Æí9~XÓIîæ¼Ð×wj¯ÇaX…K¸haL›WMz¸Ò1•£·£| ÇSB=…ï÷sB³eFni4xOæ˜ØÂ´j+ß’„î㱑8 f’NèËd¾Fs`jÆ©—pF ãïd@­ŽÇ´¸ú;²qÓ¸©QællÂ%CÛÂ}°,ÖS|/®þÄ4m‹¼Æ‘ÎèÍDÎe_¬ ÜÂM·v“ÇÛ‰Gìù͟䨤çgž­øQ‘ö—h<¬—ÁQ®lN¹ŠùËØP yû-;pƒÅy1 íÍ–Š 9ÍëàN1d,Õ7ê²+_ö¾?¹Žbv–½–î;²i×EѤ›çKqG&Ìèåœ ¸-°i wŸÆ‹oÖ@B©3ÆX6âÍØ€b𨇱JÁQ2œSϪ‘ŒZ]Fφ0 =&_‡'Ìì{"KKàµNž:™_-£|¾ŸÉ˜®,Q¿´Ê·ÀÖímƒ®&17‚3©Ÿöõ”„Åõ4ƒÏì‚*ù¬q¾âóòûBÅþ*¿eJWà Ì?ŠâJ>‘dõˆ.À^•¥"šñ¡n†¸Ï…˜4IŸPc²çD`&w¡øj, lÈÀûsàØ„*IåÁÑ (Þ¨”©(Í?‚p+‡f •+þ,<™ÐÖ†ú °óJ#OÖ'„ÝËúÖ„WdÊJ–þ£–¨ðÅ«âg“Ë ÷cýVÜB˜Za/&bU`!î ‘)¥¸e †cˆœ©Q®>³b!z¿,·º0pÖfŠ×&ý66TxÇH?C~ll÷r{ì¶ÀãY 41‡ƒbÔ[“æÆ÷ÃOð³’â7P`TüÊdYç¼ÛÕ„ëØÔÊÃXPŒ©!¤\7¢ÆHEæ¦ź6ÜHø8éw¹b}ï~öÊ×H/'ŒÄÅlY·=!ìÅÖËjWÄû¤ 7gT¿”´Ÿi§ômÒCr&Éòì‹‹HGÕˆ¼z …Ó±€p=éÚê“vŠÆäÒ“q ®Á—j€Â¾Ô´Ý’.ÁÒãGH;ÞcÒÇÞ›¡ÓÕ5|ðd€A`€A`€ªÔíœ!Y›ú2°ò<³×¶?…oú0>j[Zº(>²RÊËwòb&s·ìjÐí³¯í³ €Íb­+)ˆ…‰-Ùõ–*>÷W ÄgzñðĆV6.Œ÷kwôw˜¼˜†dŒxÎN*ïH’ìÚSÌg3pO‘Äâä›b2Ô •ïKÄú²«® ˜R)+W¶çC­ËKÔ™=(ÕæB­Ù€ÿxÿRM³>'IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/actions/showqq.png0000644000175000017500000000365314507760372022311 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 1 ºâ³8IDATxÚåÛmŒTÕÀñß½³°€Zlh¬X@DÀì.¢E±1©iRMlm“–FaÅ`¢`ÚOU´1ÆÖ–ÄZÞj4¦iüдiµ­`müR–7EjÁ6QäuåeYwgn?œ;2ÝÎnwwî,³öI&swçœ{ÎüÏsžó¼ÜÉ©YÀò&Æ}‘7v’ Ô¸¹ZÐÄ!¼0œo6pd;DÍha#Ó0'âÖá|«Ö›Ùù2…j©!YÀÔˆmCˆs$§ˆ"ö`Eij«éøÔjláÃ&¦æ¹|>ѼËyÜq{#…Ùl}ü§\Á›1w·Ý‚ÙDgã=Îiç¦<·7Q˜Î¶­t~êlå@#S0u2Fá"|)±³Û¹©Ž;É_Çö¿U¢æ@#oâîcD %-QÔˆ¹³‰ø:Zú¢&´p°‘É™6#»Lø¢tkœ‹½ŒhçÆ"ˆlÙÜcY“àJ¶',n%n,óyŒ±% ÞKA`Q#g]FËÚ-€ÍndÒ!¦OĹݴ+‚˜Et~°ÃÚ˜;4€‘jDû jÁŽž´ +ˆ Rq>Þ§¾¹‹>­[95¨læpqŜ׋>]A¤q}Ž{y5›7•€ÈÔlæN|>cWu4îO|W?ú‚Qµ‘äQÌG ×ñøÏ9’5€4TK#îM÷»~‚x<ý¯Ã17ÆϱjÑÛ £úÙ÷þ„OÏïùˆ9«i‰Ô¸,àË®Á×ú±ê¯‡/_8NñVÖñ‡b›:µ/K#’Ù}´W»ñ[’ý¡ß~ÀÃå Ü Ñœ0rnWu/~Ÿ8´áѳyä'áº_Rs¾A.fÉY‚kïhêÈ´„&X¬ Ç[ERsFr[Âøk„¬ÆŸñJ‰K¸ood5^] ªÿ²˜¤ƒèG§Sã›°t-¯d=^E±@3Óïcx†ÁÔ y¢hg]ÈÕÕøò™hÀ1ö4óX;O>É ­V gÕª^¤µ*Ô¸ŠWí9|=â`Gëy¢;·³'YÈå ›žì`ùÓ¡V8[.}[q;ENx¬ÀªõëÈ›Þ\☴9™ìÝ_ã¶«ñw’#ÁpMøqÌÏVÓZ¦[.Ý‚¹’¹Äe®K£Û¤Ìu>=óg ÀLɱc ñkÕÈ´0Ò›rV„ÏbfªòWE,idÜL¶l «—”yÕæ1XN &‘kîeŸÝx!ÍçEt$üË׆¸ª’yi¬?å¬Q¸ ãq€\+MKš˜8ƒí›9RÓŽPïpBÄ®‰äö£ÿ¿Bœì6¢¿ŠYþ þ‘9€fVƒ*Z¹Å¸¸Ÿ7ØñϰRx:⇫Óc™Mrê«¥b»+p‰PhÜòu˜‘î”ì$¼gð´U™ãî;c¯êç6+­ìÄ!õõ`k?Ÿnæ3#æõ+CޝOòžøÜ&w²Àª„•}‰,ÏxJ,æsúЧ58G^#IH"žøÞºàÉUM2Ðöè­“SøI™ÊÎF,]Ãöª¡÷!wm/¢“.¥ë]X¶–ç2!’)€»Cp³`,É„ìKoK׃@‹1âºn>ïkézPXBý)–Œ$™Öeõû[ºTN2/b̵%}¥¥ëÁ й¿žÂLâ¬J׃ÀB¾špÙ¬ÔéZº¾µUñg/g@’SÛ‚º‹8±²ƒŸ>UæñÔZ’Š]á¢ÛëtÄödÄëC>®æ¥b ˆY–^þß_ÃÛ‘Tà..îä ׯ ÿÿK¾ Ñ`þ=M~hš,)­á•¾§;à“{ÄÝÜ/_æºà?kz¥ï@—¸8áaB-cXúªWáÕ{ÕŸÔóN¤Ñr¡Z†âRµýã‰i®¤j …Äáéê5a ¡$é(®þ©TÚÏ„ (‚ÉucŠŸ÷TÓ/gŠUžÎnìÀ€Ê¿pÞV”!æ‹}IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/actions/showpp.png0000644000175000017500000000371414507760372022305 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 2 ÔàíYIDATxÚíÛkŒ\eðß™Ým»[Z*×^¸m¡ Z¡‰"WÅ P ÑŠJÅZ°ìž.´€\´5ÆD@%ƘH´H(ÆD‚€b Hl í^çõÃû.»Ó™½ÀÞžädvfÎyÏyþÿçyæyþç,ÃÖ6ŒgÍYý]¥0|xóRÂÜ4©?«Ô Oçóqd1®66=2Ú"à „W±vÚ(àö\Í„"ç 4ѱf°åÌdA#ñA¸”–¹£€u„•‘ýyé³3(Þ4 Ø|1fqbqé³ýqœÉšÓG0ëbî/c¿d§¡!n!/ŒPž½‡rB ݾ›„ùY …KF ëp ãŠßË> 0±H¶Ž›'Ž06_H8¬göK6 „il¿bÈVUf¿dÇbßkE>u¤DÀ„#8¾@c&bõH #»6VøùUr¥´1ÌXsa.Çg4ÕpÜ;ÍÑ ƒ@>“|Áe?¬ªý’MÛdg‘/¬XƒXüÎÆG™—1±Ç/F} «Øõ€ëÁŸ’|ú !pMtà„>>YLp4.`ºV¡^LÌ–AÈý³p\d¿?Y¶E²›È›€ü ²%XE¿HË1 @XÙ?±Â>oáOØVaŸ ¥æh:Ùå« |¬¼Ú®@öÏŒìÛ ûoã7Xx·~7zYoö 1¥ÖíÛýÛ5Áë¤øc¨ãTñÿ‡-³Xô8›^ì?‹î¡~ŸÎ_öù6ü^Í;Ѐ7ùw¼–ÅÜŸ²ë‰ÉÏŒ§«‘Mõ#:¿›îEeŸšFÑì–4´ô§òŸù“Å ¶ãáÄøèzšì3x>¥Ë£±÷ò÷.îÂí¿¢˜Ö8!»Œëï#k§Eéé€À‡zEÃ\6/é'ý×Rœ”ß„õECÇ3Ññæ£i¾¯p!¿„Âll`ËÄDGJ×PG×Ú>б2V•…Y…Qtm-£h·Ü? 'sXÆ“‰ñGÐñÙ9äG%ÇCïk|ç%òoà`4³õX/n+òf¹´œ\#ùT|™iÝØ/ESÙ¾¼ï•ž•šì<š¡ùW•×õ¾AÞ¤ƒÉ¾BÛ‹<Š”Îuk*UGÀU‘ýEY:®Ò(º²v¾e!NIož&» …úµ9ÞÝ–ï ùvœȼÇóÈ/¬€µûG§fWnÝ-Î’Nß\Û…W#帣iþeÿWDÉ$_@áDÜëÙ0¾ :V+³_²CKÍїȬò§uÙQÏk¾/^ì`ÚêÇÉÏÇÇÙzP}å×íMÇeì84«î§ãŽáF|²ŠÂÿ/üâ}Pš^¨"Ú¯ŒêÊÂ*Ø/EçÂ'v7Š+Tfß×ba›Sã²%Þ­µêôC€öå±×­…ý£ðùa@>…ìëìøp—>ME²{E‡r|“0¹oì—7G%ÞÀ| Ùì¨$ª¶â¿»Yþ8qìjòý†K,‹ìŸÒ û­i,ý^‘â§x¹Âò‹3±7òä“É–G¡ûómâp²>ð´b³öBˆ#èÍ=4psÒl’-%Ÿ3Ô#`aÏ]ÙoO-ô÷CO[_Ž·ªÞi¯Œ#èk;¸ÊFÐòæ(ÔáÆ! ÀÍcîO)FöË89n)f~^6ŽGÐ Óãñ[ÿGÐ[C|} 3$þì4öE¶]NØ;Þ}2 £õ•Žçwwö¼ÔÊ­4¯ç3±„¶çb$¬=Ä0˜V¿“ýí+bþþ.Ж‘½‚5QjêÍéžlYî&¿Ÿ¢k;‰§u>‚ÏâgU,–%ݯ!‘•í|-ÖÇ?;Ç%0$ , 3…p±J¶5²m/ã:¦ÞÃÒŽþ Œ[>Ÿ°‚Îs“7ßOÞZv@£x hbÔ4ì¼¾ž¬«!.ÕÞX’zzÚ)£¶¤ªnKZ[( o"|+É%k™ö“þ9Þ#OàòYXSÄ2|72Ûîï}w³­0þyÞÞ\a§º´MÀž¥ù/$Pd¬9?±y{•ÍÄKéÍò»kd²Ï~”ι/öJš bÊ·a+¶”Ò£'ë/‹ry 4¤žº>}W^v‘”Êj@1Հ޲­”½Ô€!cÅô»ùV•R¥³¡@-*äFµ0ÀcŒ0ÀcŒZ«ï¡¿nŸNjè¶ei«ã·3¢Î¯ÎïžËˆŽn[{šÃ‹C€,£“Å«ˆŠÖŒÎ¤…·î°ó?˜v×»·¦Açu»ª¦ï›eÉéYïq:üSïö½ç””“IioJóø@ý_q1¥@I’z;½7”è­@–t¹DÉw^»Òþå¯]eùß5”‹àÿ]Á YɈaIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/actions/showalternativeflags.png0000644000175000017500000000141514507760372025215 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ š(}ÔtEXtCommentCreated with GIMPWuIDATxÚíZQ²ƒ \ßô^¤' ž <ï£êK© ¨Ø¾šÉ´:0&Ë&P( …B¡P( …B‘pÂhæJ7oc˜Ÿ£.…ÀŒÂãó›ðsõܾíä…úo#ÀÂK äŒÏâ¦ÈÜQƒ»xðÉ! 8÷|,íDðÄM“m™;›<Eô|>>~'¬y×ÇÉÁ¯F‚–713Ð÷ȹÎ É:†jIzÞ÷k͹ÓH’cnJh”ìü‡ë" „´½eã¿ù™£p·Øå§(%üxΟ—¿Û•:ÃðêÎ,îp8Üï ifÀ{Ð÷ËçÃ[á *iÞgÀkŽlÍÿ–&Š°ÙŒ)çŸä8Ÿv£k{ôïºQ½]—¯µ^ÓØÞ?¾·ÒÿKrÛûE殳XÆ—0n«]!WZosm·ˆwŠÛŠXðüôô½o Ý‚|=Dè aøÛ÷EdY¸Å¡"JÊùÒûýYVn­+hûvº^Î'¿='nÎGŠ‘r]«¥BÁDÕËÄžLNt{\¢!»8^¢Ju´fìÖ¢JxÓÖ>q’?‰L4 b]!‘2\»ž£›¢ÙŠPä£ 7JhtÆèº—žÄ&¬¦€1¥SiýŽ•zÞ¥Ö“é58‘ÆÜ<&î,I‘ÂÒ™jº95k9½Ðu‹ýÇR:O nU\¢nGAîß½@YUl8ï½ ^Ú >1-#€ÚYï ¬Pz¾6]jçã»0”­–Ãêu€:àìéâ|…>éµùÖNÌ!Ù1+Àî*)äÐðo* …B¡P(-ñ ’dÒ‘ÌáHIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/actions/showoriginalvisibilities.png0000644000175000017500000000553314507760372026113 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß 2¶àF èIDATxÚíšytTÕÇ?w2“e+ˆDeQ¨ «P  €’F±Ôª€¥X©PQ «wÀÚ#RåPPìaQDÊ¢¢B  âQNÄJdI˜73·¼7“·Ü73, žÎïœIæÝíÝßïþÖïÈP†2”¡ eèÿ–DÚ#%‰Br50è ´°z·k€·Ì»í|ê£\28+;B^È@£|9¡œé“ê#îÿõS@0¨ë·R»ÍÐù È C0Ù†í4ñÜslý´ y ¸Ò¯»^~ 9„¼ ×èø„PÔrµV!É úLø$ ó7#y ØîÎÊZðÚPDMXÕy¢§’¼(è9RñáÌüsæFèMÀd®“Ïrç"ùàòþ£‘ã*ØÔšâêlÞ RÓÎ çBûÍ3 ÉpGn ‡  g±>bìë%T¥É|Kàv­Kfy äVàFŸå.DñUü!&êqp‚’¯2¸ÀÑ…Ò|S@.oX”lÿwÍ,/ (PŠîB0J@å¯/¦ Íó_éÓ~¹3 ˜IN{àß ’ Lt$0#ÜñTÁlk½M@7{ÿšvö¬{¶ßÎǶ @(®×…m%øp@oZ§8ýû€34=O#Ùåƒ$ÒºÉR{Cï+¸ZÞ^]ÇTÛÖ—%4&Â!ïâ QOŸ¥à‹’0ߘ¤éÙdŒ.øh7²É_5/¿Y#€%š,n‰?¬­á#FŸ„¡ E>ÑúWýø…O÷2Ÿö~^V$7}4ƒK‘ t7v»–\ƒ49åTŸÓ˜èÞ¡r3*i ¼¨ÙAÉoõ–$yÉRÿµ¶öÁHvê&Ä„×6•à‘4BR_%ØPŽyÄMØÊ&gEn Å}š÷ºUúS_Õ—zŠGƒHº7‹¼©Üe0÷ [Äx6˜T¸’ñ1×õ!ÐÆòLjH68ó €—6úF¨¸€K€&šž·‘|€Ô—àî<àU¤¾ði=œúÓûÍÙ—Ž"A¸ÛíOì¢/©5GuXg£ÏÖ¡’¹VØuO=„ä*€wë£M0ÝŒ2¯šå™ÕÎi§¥ŠrwSãý@`0áßmYyþ×-›f}Ýk׎€‚ ¿g p‘Ï»d?ˆ¨{˜QÁ}µïçS#a“ëZÀ´´pþM”l¡xÙ',ŽK*€üQÌAð'Ÿ,lÊŠwYx"ªUÈ9Â6@uÜœ°Ï•7–°‹jÞ5‚4öA˜âôG$wÛÔk¡p QæŸDXtàgcÌÆ&£Y¯C|˜_²ò-î<2b>‚'&Óƒ;›‹r£Gå -5&ˆâN¤bƒ=¬Ú߬²FÐèo×a¦K™X®ªµyý{8tò®ßY=Âã<ô2ovE=ÆsfË^ûޞτLÐU£þXnt£+Æ|üÆsÿ …Ë~ˆaD˜! ߣ›½î n°¼ç  »•.·XÕäÖ¸ý%¡íÀY®“÷ÁùZæMT#é¼í#€Ù¼H'+&£Ãvæ­ã¬£· çf·™ùú¤c~ ’] óÖš,»h|—úsèAÊødÓ9,Hv‘ˆ1äÁf®šH Á”©¾´ˆ~Å0 føEét×Ì«DšÙ¬^ Ô¢ö@…²¢‚ï­Ï´bþP™£_GÀ¢‡ÿË¢GË<9¼.Ek“c©Ò¸Æû¹É>>©È[ HΦû°s!°-mækÖì|áÙD”Àã*Àåt†ÓÆ—û\Åë(ôWÞB1nmG €^šÔn"¶Íî²2:]Róã „’-VÊìTü<6î¼—+ßÌå—£«˜—j™›:£ ›´;ÎHó+Ù8›H ôwŸBŠÎòa~þq3oR[«^p[b‡|ÉÌt˜·v;=ù] ;,æúÀ}ƒü@ÑÚ¢Ej.@ŽMª}P€>HžHg™¬jn³à)nX÷g!)uÑjËÁkañ–Àm®D¦'–Ê€v>}cÓö‘Ks3”ù0ÐÁïNðä À¤Ö5 ¸C+ÏC²>ó£Àé>Ì÷F²%•?'•}ótZ[|F$æÝþ~$­7ÈK²òÈ$×õ§ŒjÑ (9A«õA&n’ÒÈ­N ¬!Å/ÆÒ }˜?ã{ïh&P#ˆÂ$‰L2š‹¤øX^8Åð®…9¬NsÆ à‚ceþÔÓ§0:ÅÀu˜¿÷ `b«-ÄiŽ3”¡ e(CÊбÑÿ_rÖÂ=¯öIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/64x64/actions/showqp.png0000644000175000017500000000373514507760372022311 0ustar olesoles‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 1.]ªÏ´jIDATxÚåÚkŒ]Uðß>3¾Ôò(PäaJ@ û(¯ò›Š&‘™–—"Jo§¥M#~@bÀ¦íĘT? B-M•§Q" ”iƒ`„6”)íÌÜsü°Ï0—af:Ó{‡Î®äfß{Ï9;wÿ×­½Ö_ªÖ µÌ?£ÜY’ê \B¶‚¨rf©©^8œð>k×ïa ß!;‚·°hß=€•5d·P—r>²ÏÑ6wोq$'%LÆ!p5 ¾¸PH?‹Þ?1ÿ¸x Ì";†:“ÿÁø̤pÊp ÄØ‘RßíÒÙ¨Éð yf†fâËÔ'ŒévmoL ˜FaÖp `.#²®Øïn§cTŠ%ürä0`þ7p,Óc{¹gNM0‘ÍW 7ܽÒNn«Ç^)æõ·8ª ’MfJÞ/­ìÏJÈÆÑvÓpaÀ\jûáýN;‡d„k(Lªr ça “Ÿ@¾<'ÀÂjgÀÍq?y€Œ£à[4\¥Ì?ÓæýR;'Ï éí}GC€ì–èý黸üÞ"xN¤pQ•P8§pB`\óœ.6Náv uÕÄ€¹Ñû}õ6Ûñ"Úú¸g NKÈý¥Ì¡æýxœ¯à‚®ïÀ_°>¥-‰ÍÑ´$A=åŠÜ™²uKT‘ [ºWCÌf¬ ™È¬ÐÕòv.|=þñZ m‹:@ö-#y&ã½À>>^0%xytü°öÑ! @a:p|à¸ü»6<‡•)¯Š-¸‡aÆl²ýyçÈxïë9ûä$߯f|Pό߲vóPÍó yì·ãiÜ‘ò>܈ËÉ&QXЬ¸u.À ¸ME~‡_gü-¿õ£â¨iˆæ€¦“H×GuçP<•Òš6’-Ä %‹þ+ŽÇýŸÜæ cÒ WFÑtlÊ”„7Ð’‘Ôsë³b KçÅñe¼„°‰ÐÄ„{¹¼}€¡´?eñÚ® õž˜Ðåôôç˜Qn„Kc VÂûõ87/€Zs˜0‰y˾øR»i3ó³ÏD4^î* –Ë€¬–³˜¿”—áý¹h!,"kf^[eÙuÍŽBš™Ù Q9*ü±¬ÈX’söÛ4ײøn6 l–…Ññ ¾Yù…÷ô“ç=„‡(LÁ¤²“`cDöûypudÜ“²hEÜ‹sËì# ößÊÞS:ÆÆ¹ ¯4ÐÜÀ$CÜÊ ÷ô½­yzަ&pià_³Y9'o·%9 ší`bWG ’ŒY)ÿldÕìHÙáÀrÞ̸gƒ®­à 9?È|-å…FV͉Îð ŸhA }u·ïÍøŽ#ä@<×ȪÆx¼;<XkÌæ x­‡ëŸÇwq-ŽÍÀ³yhL­zòÉnCÛê>î90â:LŽ@œŸñL#k˜VÕ,¥+Þì…¥6ãDŽɱ†8+ðt#k{?Ú@‘E;cA©Ðøs#ë.㌪ ™Xþ&^Às@ü„P˜žðX#ë"(ƒbµQQÙ·’“fÔ![#¨9ì‹™±] áù¨‹?ÚÈZÌ_ÇÊ«(TrÒÎoÄÿ0~æŸ1а. 3Æ]È¥ðiM$pq„¨†f±&“‰JhÇÇU£ÞXâ)BE8ó@’ñ»¨:½[¶ì½¨‘½ó6wþ‰‡Û㪠Xßî?÷ô3täÚZ¶¡5?¦v—T:®¸_=sžÝ„}ÔJnß½Óün”…K¬õ9êÞ¦õ}qDþƒ½ºò´Ø2(šà¹ƒ–qŒ¿‘¤¿Yv Vã…èžb+÷?Í]¯ón%u·œoáÃAÑ·Å.pÿÓú¹Å|ˆÇñY‘Pdí& kb[Q—{°V”ðû3e1µ—¼:C`[÷¼PiBµ£H§îäÇEÿÒÖØ,½¸¾™'ú‘c;ç®É§R2x¨dì=ã¨é¹ëz³—ð@žàÿAÓA,+DŠö#Ç–·èA pCB6½—ܲ«DÑ0ak`Q;wü&žt™šqòŸ<¢,MpùÖ´"aîÝüww·Ã 寧~]Ì‘o ÓÅ~†¤di@§¡øøR¿ÂÓJ£¨ "ÉÀ\‡Ã!ùùùMÑ‹;0Ü ü"ŠN Ølí=Pïƒx£36Dt@Àø7×E¤,:±’<<toƒ~Ç€5`_EGÚ(«l‘òòòºkšvLDÖF'Ý o ð`(ç¦x[Ð  æ ÈëyŸÀ¦ú8Èâ·h`< êàÒ8É´ÂÀ,—â!ÌÒ"r°GDÊËxö8ó"01 Å€·¡ÃdøÓmò$("YÀÌ´´´ƒá»{ú™\xãÆBÃ'àéÓ!VGáIÀÔ‚‚‚ë®îàÛôµæi;ŽN z%Ç÷&'§ëÏÉÙàÛrukå·r L`àhíÀ‘0zt.×-äæ^¦S³¢â$K—î`åÊÏij2››¿ÛÍàÜë8?w€FÄæ™K¡á3ôËëºÆÒ¥#)(È Ë·uë!Æ{ƒ'~jn*‡‹~ ³OÅ4^ð1É +hÐð2 œön÷ðˆÆ z%o½u?IIgMÈ3aw†’’’†aÜÜv¶·ˆt†‰È'Ö"ŒGqµk%ìÆìÙ7GÍ?lX/òóonºŒ)VüJ)£¸¸8µ¹-xdišVŒå#° +¨ùQk× Ìœ™‹ÍÛ²ôÄ?Ÿ°j,H·`W𦭩¯¯ÿmsƒ½ùƒˆü;üP €Ëp<1bDìOVfæ¥de¥±oßÍMiÐ(ÀŒPüJ©5ÀÙŒR”î– `?³†QB×5аÛcORÝ~û«|øaEpSØûF;è"âž7o^¯0|“@ãLSok1áÌ™ÁbðþÁŠ¿´´4ID®‚sk@ž×ë=š]ìÀƒ­Ò,FìÝ{"æ>¦©‚§0~ÐÝ ÐE¤ðUs*:F—ǬY+°nÝ×1÷Ù±ã;Ž ™?éÚm¡œÆq¹Ü."uÀô0cŒŽY«V¢¤ä réÒ墨ûƦ0T5 øG(Š®ë%¦iF³Ênü—cÆä°nÝèzdÕ/ÞÁ“Oþ3Ë— ׆cÐ ÃÛœÞn éô¨I±~}9cǾÁ?ž±äñzM c3……aÒ1ƒ®”*“çË!ÌVérÝ—_Nãᇯ‰¤HLxçr²³K0ŒÍìÚuŒŸ~òâõšTTœdåÊϹ暈lBE¾vÑ@϶"ŠÈ+vÂ?Yá¤gdtfàÀn¤§§†ckNœø ‘Mˆlj£$3ØeAÌÐu]w†é·;¸öƒvIâºËåÚ†!IÍöFg+‚ˆL wPˆ;† éIóÞ{û¨«k<Ö³ggnº)ƒÝ»«Ù³§ºmüøþôëwº®QYYËÆlÝz¨Í:éÒÝum!……C(+›H÷î-׌AƒzRV6‘{ï=Ç:õ—ìÛWÀ²e£˜6íòó…H[¶LfýúßD;ÔXÜn÷-:p±u_­M×¶¢wï.¼ðÂLŸþ.½{/£GÅÜu×_9pà$wßÄ wé“VÓ4:þ(Ï* -ñ<¸'ÉÉ6JKw²bÅçÖaÚ5_òé§Gس§š ú3þ­L˜PÆÑ£µtíšÂêÕcC&A¾ø¢ŠQ£²˜3g(ϼ^“ŒŒÎ¸ÝÙ<ù:ÒÒRB Ù;ªU;©¯oâŽ;Ö°ÿ¹ç®]Çè×ïy¦O¿‘ÒñùÛ¶bõêÿPSӀͦ3fLÎYùœ,Ëj ë”:""ŸCÐ'p5¶ÿõ˜E‚T^Œhqûb2È+4MD6¥¤¤ÜÝ\„|7XÌv8aê†ä%à­øéwü-ŒñˆH.ð~pz+ޏÒø°L5µ¾rA,£¿Ph±™–––&¹Ýî!Ö]ä$Øo,.RÚGѱ!ŸŸï5Msn NÈE‡;ÊXLŽ‚>䀃Çãé'" BÑB§”Íf›DŽ(*+çŠÈ‘EÍ}¸ XŽÿ(oœÁÿXö‹Æx?oÞ¼ž‘ø":ÀápÀý†aŒ¬£™¿¾˜øD‘•À"HÊ) y Ã0JOO8~Ôåòv»=½¨(Öjí2üïvP£ñ—Ë_Ř ø/ð°ÁÒ†Žê,tµE‡c~4nÌ¡Àëp‡DÄúöÒºwG ´> Ò9ï… ­TPn•ÆŠ€(jCwŠ "r7ðG›Íöhä0úÂÀãñôóù|%©©©ã c{Û$æŠ$y˜âóù&ÅÚ7p»ÝC|>ßs6›í±X§ƒ¬SjñGàíÒd€²²2mHÛÇCiÍ4Í;€M†aŒ‰ƒØ`´`q­5äpyø~„©ˆãµÀQ‡Ûáݽ¸ÿ -Ïψt‚¢‹ƒÏ­„÷Ô~&G&yáÚ=¼û7÷ZîG¸¡îG–º°,5[ÓY™€DëØ²€ï(â#àRCk!ElaËöøöÀCK ÂiÞ¡ú¤ö3 ˜ðH ™ Œµ´>ŽÐŸ’¤Cl̵¥ ¡¡»)‡±; B8TíRàur(a62‰0B.x¬+R&!HàgZjÕ f=m-€ñ¡ž¸&üR`ˆ>àHी%®Ã¡³ö­ ­jŠ_jpœþÈWT÷7a­`NÇ[&½áE˸>À Ušî@ûzj,\¾ˆáÍ:a¥µªT‚£³ô´Ì1 a&ÂÀdCû5ÓBÏ€ïeïÊj  ð£¡-¨ÔOZæYœ`£Õ¿ØÈÕ­ >Ç~Â4“¼PÏŠIz#”Çi–í4¶·68ƈǩ À¾¼ ,NÆÇ(Ë=€pνÊBÑëIs(N¨ÆçžõÔƒ>E1ó¤ÂçhEÇ/›±€;OCÙÝå_”{o@ T V+:ñd¡vÓ5qý[ÖöºÁJÞ4…Xa ²Á,_[B¥= ´Š±¸éc".H„Û»,ýs-aO¢ÅÌ"õ'ÛeÀÀ 5çûS€_¤€ºŸç”å¹õ2—#Ô l©ЂÍóĈrÚ¹†~;€¶»R$Ck5õöËPvSÊäècòìÐ¥‘3|àóT«I,é£úÔ`žå†ó™m©#&þm ø¹³ ‘…D[®#”åã^Œ¤*w#Üá™ûgK&¹Û$a0ÂÐòÐ a7ÂT óުׯA è¢ÌÍ&ŸéÎu u…ˆÔSçîlµÌQ³K<@_ÍN;[ØtDz_-ØÉVÜ[¡èâ Ò‡1-5ÙJß×Ç¡Xbé× ,;ð6 úYzŒTåù†\3ÜI¹ÅDºÁ»/ÚÐ7 äÍ@à!\cªÆ×€ŸÔǹ:ðc-à§!T™.Ff¡¿]ßâºû·st€>«µßàK¿*`Šú¡}€ 1Þ<áz»µnš_þP Š"CãZ¾²¹pç3ˆè4Ìç¦ÚƒÓàl'DT±…ôýþ."„½dè0`]RüÏœ¹|—ù© ýþ¬|D¶m»ž¸ »œxù{[a_› Ifv;§nùÒˆ˜¸?ÿŒåTZ°¯§Æ#(Ø«P>ics™±[<( çáq±}§8y©6ÖÏrözš‹ µœ÷®*øhŠMØMóÔ/1Ýj~±Î¤¨Š¥ Íš«tÞñ£‰É[ºåŒGÛàL¨)g‰Í¹š'³Ô–’(Mj~F䌨A×€ƒ…Š¡¦’¡ÃãÞ¸œþ-ºŠ©cùªÑ&öÝn²\p`¦ÅͳMú>üT.=Ð'¼ÃùRƒç’Ë¢› Vòv XXphu_Ó*ÊRΉM ÉAK@oï%|w“­‘$- kj)ÍÊ¡šè~÷+•+^,*b“Ì}¨¤UhE);vؾÝ2§ê*^Ic11ˆÉjNχ}³†Û/†¨”%nËeº°øâON¢•¥„|Í H“š§JÏ+&IæÍZ°7¿¬ãÛ·}¶–¯÷”œÃœ !Т#+G¿¢mù:_†¨3ɼ6=ê(¤å}•1ó/#šdž½„™CP „èÎ$Ú¢§_µóGúïi ”Vs}Û<1ÕæÆÚ}<»ÎÜ‹ýÁˆ~Œýçm¯`ŸNñ;æ0µòóËÈV]KW"·*"ªX•]êâ<Îâ4>¿¶ßÿÇø‹Ö÷XDYIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/showoriginalflags.png0000644000175000017500000000132714507760372024471 0ustar olesoles‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ _ O;tEXtCommentCreated with GIMPW?IDAT8Ëí”OH“aÇ?ÛëkïëÑd5Â6gÅȽ„å@f%;¨‡tàPó,th·.yB&Š%5;t( ;I»íBÂD¦‡DF_‡sÿ”ž.ìå-Gô…ßáyžßóáùþ~?ø×$㮪¡]VQ•rÕ|T8FL„%ÙxXspÃ#l³mêÚj²çZþ”~̱Rɯù¸y”ÑOaÂÏÍìàÚé‚7î[aÂk@¯lî7‡ßžzàFOitTrG£D7{é}/#_í£ïž+ãŒKL¨Æ`í¢Ë»ÄÒ`¸äÇŒÜ L 2ø°HqPßc8p4{ñ¾[`¡ÇàæJÅå`’a†_¬²*:éüâÇÿ6GNì³/R¤Dž¼ˆ.\\¸æ×Y B ~Š]vE„ˆðâ}%*R¤„%CF8q²ÇeÊ´úV¢Dš4V¬´ÑF-µ¦MÌ’%C7njtô\uuiÒØ±œ8mY²ßuôœ„dk¢Ij 'NS¸; l-XJ¨¨÷—YηӞ"I’b†™o@†6"ô*HðÉC/ûéŸK’ÌKqk¬‰zê€F`˜n/²(f™ý (&Ž]Àkà†¶~z‰H@ЬTM  nþ|VâÄEœ¸H+¬>×Ï;+ËnºóÓL.Vcº€`GFn=äpk‹­P®öø•ø¯¿ª8tÓ†Ôm IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/spectrum.png0000644000175000017500000000322714507760372022612 0ustar olesoles‰PNG  IHDRÄ´l;„iCCPICC profile(‘}‘=HÃ@Å_[¥R*VqÈP,hqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâäè¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"€Ç„ÄL}NSð_÷ðñõ.Ƴ¼Ïý9z•¼ÉŸ@<ËtÃ"Þ žÞ´tÎûÄV’âsâ1ƒ.HüÈuÙå7ÎE‡ý<3bdÒóÄb¡ØÁr³’¡OGU£|Öe…ógµRc­{ò†óÚÊ2×i#‰E,A„5”Q…­)&Ò´Ÿðð9~‘\2¹Ê`äX@*$Çþ¿»5 “q7)œº_lûcîͺmÛvó<WZÛ_m3Ÿ¤×ÛZôèÛ.®Ûš¼\îƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}2ÔUê88F‹”½îñîžÎÞþ=Óêï¶rÂÛÑk.bKGDÿÿÿ ½§“ pHYs99ÂVtIMEä jR©tEXtCommentCreated with GIMPWoIDAT8ËU”M]G†Ÿªþ8÷εÇ6d  g‰B¬@ þ‹H,X !ĆÁ–¿•eÌ‚E²H„ÄÈ8&ãñõý8÷œî®bq).©Õz¥RuÕSÕ%îÎÿí7Ww!CLjsh­Á¿— "gmªüúÏ×}üä³Oÿ§›O"ß0ýðýà@¹Ì´A±,èì &#œz2<+éõ 8HixÞûùWxômù1ðIŒ1ÆÖÚGÀ郿üWáôŽQ6NXWìðñU&…x˰úOÎ<@˜–…ç~ÁTGâjµj»ÝîŸ"R¦o ®`ïT†GG¾·ÙñÕ~EJ—Ý=ÊI‰ÛóC:+­‡8%xn=ûòð\ýv»u3;´ÖN´*l†™ý‘Gë#ßßÜÒ],„{…::À#X<®#Ô^´žÏ—*"¾ÅØ#Xï¤ÜÓ ùăî@î ŒC—W, –<:/—žn¾oîþ‘ŸŠÈ{"òCφt›|b —ùȃt`H…±_Юáá\zËw÷àÔnjÏËi}f,"Ÿ*"³vFè]ªlÒÌ£4V.ãŽï¬ö80»°¬¸Bëq°ìlKBÚpflf3ÛµÖ‰NŠ U —ÊZƃ6ƸÐç ÁiÙ±äxt¬3èS‰ŠÈûo1NÑXåJ§ €Nœ1,ÜÓ™uhX(ôñØzÇÕñÎà„®R¾VÚ”lµZ}¦Ã0¨ˆüHDžt¹qÙÏ$5²£VûZX‡…ïv[6ý‰<|lȦ¢}#•Õj&èQÙï÷®OŸ>5`'"¯rn ©‚ ‹ÖZx&F6qaNÜË]Wб’‡Bê*)U.ljÑ8§EŸ={†»¿0³¯S0:mt¡¡@¯…µ8ÍP*]¬„®Ñw•œ*)ëTè›h!¾ÅXÔ∠͕ɕâÊì‰æBÄîzÑèreL…c ¨CÖFªxÄÜ}¥"òXU/Eä¡'ÄŠ 8ÂÞÅ…×-3ûù ÷¡ÐicÕ-ô©ùyI—TÒÞ1³­Þ%;‰ˆ5Dœ¥)SܶÌÁ/ëŠ]é8Yfn‘>6ƼœYŠa1Tlqòá\•ºû—fv2³ÛâBW&‹L–Ø{âùrÁdcËTK1¢ 0J  ”â®ùÅ[Œ+‚†F.TfW*°mˆ 'ÅJµ@P§™â€Ö…´“üKcŒQDÞ‘«jB •Œ¬âÊ›–ØÕLq¥×Ê u¨\¤Ã]h¦uAÞq÷zuuUNDŽs L0ª)ûÖqSWlKÇÉínJT Šá@mŠ5aª‰ZOøöÍy ]__| ðøoüÙ‹—¯ØnoófÓ–)8å=×·1j u_óß¹Ð\ÉqáõéÈnêØßJóîñT¾¸Ÿ–ãy»¿u€ÇÀ¯€ïô€Ÿ¿½ÓWÀïîôà—ÀGߌó?æÐ…ÞeȰIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/showpq.png0000644000175000017500000000126514507760372022271 0ustar olesoles‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 3'@’BIDAT8ËÝÔ[ˆÍQÇñÏœKî3Ìጔ'Œ[cBŠÞ(Jxó๔’¢Ô —JQ˜R.‰¼x@.I©iÜ"…Ô¸4Ì fÜçÆÌßÃÙ24gšÓ¼Yµûÿÿ{¯õ]ë¿×oï¸lÉiì›Ì‹;ÔwåË\Î~|Få®®§8›o\Ž6‰ŠA,^Ê”ˆ£™?–‡w©é¸’¶I ÁŒR J‘d^1sÇñ¸’·— °œÂS³,'‡s`#O´à OyüމÎãÊb e©vædKü•(êPY/Œ!¿Š¢>”v²§”{ºÚŽÕ”\à}QÑ ¢Ã¼ÚÂÁ%ôÎvôg^²{H6ð6®ÔÕ¢z+çV“½ã¹YÇ—ˆ#g;óXÁ°c¼¹HÃ6*Ö1¾=?r–(³}—kØ;ö_ÍœÜÊ“ Ìì¦vãFmE™å×ÿj)±•Ì+¯+Z/:ÍÜ $:,µÿÀ½f¤oRtŸï(ÂÐðLcp!iS€ì.æZM¦ÒöèÏv´E”?@>¢0Òa¤ÂÜ@ ªËëPñÂÌ+áy#竸UO}#C Hå3ê-—n‡Jeªþ¾›ÐŒV´ýþÿ ÙNá,ÞÀH6´t÷èLj/¢i¯'²ñ8ÚC«Þ±v ÏJh?ÄÇ9zfeÓ);ÞCHn÷ñÿ NÉõC2óþ*EQß þ6ü kÍâO÷§º™ºGÔEè#s &ð-ð/@¬³Þ‹«IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/showqq.png0000644000175000017500000000124014507760372022263 0ustar olesoles‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 3Ùú€ -IDAT8Ë­Õ]hÍqÀñÏÙ±Y¶¼´¸À\h Û k¤$åR^RnEs1Í…”y½R“pAD\¸ðv³ E+"oy™Ñ”)ÌÆv4¬m8û»8ÿé¤ógyêéßÿyùþŸžÿó{~qYH5ãæs¼’æût ›“ øŸ ¦sw×k)õ¿d5EGiý@pŽö:nUSñg\<[ðzgS:“9åV0%—e3YZFÓ=Ú ØÈ´$ó2ù(œAÝ:& Ú¾£‘ÄKšºØ:" œd4J2ùbÄ¿‘L·å¢ˆÜ€‘Aê5{ÙFÍ=ú ‚Ç|ßÏ󭬌1ðXÖ–0²‹à2¯Û¸ÔÊ®‹©Ž \Ãò2JxÿŠÆN6Ÿ ûŸ’×SQŨL¾ZÔqe-ÅC12ŽÛ\Šóy°ˆ¢©ÜyÊXEaÀÝÃzÌ×0<ˆøÁ™e7+Ypƒ·-Ünàh=ÑC$@?>¢;ò€”Ó4†•+˜XFéd—1¾‡kí|’êëg©1øìDï_{½‡›áH%^>äYNÒ:ìõXlj‚|ÙË£-,Ì&?ã¸U1ªˆ7£éL°·žóÙÕŠ%?9ÐÏÁúT'²–X/@^xUÅC…:¦ÉPûD–ßçIí…¼4`<üHNúœ“Qà_“q®¯uôÉIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/showpp.png0000644000175000017500000000125114507760372022263 0ustar olesoles‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 37 ÷ö6IDAT8˵Ô]hqðÏÙ9fÛζˆEäe^Ò/‘» E–7n¼–¢RFËÉkËË %’—ÒÒ$Ü(…W“·ÔJR\µaìϳΙ­ÙŒ_ýžz¾¿çÿ}~/ßߟaYS1M{ú‹ä xT’1 œó‰O¢¢Ž ã(?ÿ‰G6R;…bL®åÄ÷d×_’Éþ=ÃÅûÊ8B2>0qùaj§fßóQ=Ÿ3« >»ò+d[@E=•ÑÞø¢8ñcAbDûÜxi³™y—ûÆ×7²z-‘·Žšm,®àÕ,š¯öͶì2<ºÇ›}|Oð~+mˆ”ÐQÃÊ ¿µ¢äÕ%ÄHpvMïxt3ßžñ| ;ë‰}ð†§ìZÍã¥t=!µ#W—u´¦²“Ng¸ôœd^oíæÚñI$ï÷3‡üœCñF%½ÄaYe»³ØŽAʱ+$>³ŠyUH:Ñžðé…”íâ\áP• {{„¥Á”_¿åK!•ù,œÊŠ*nžÀþ¡çÑ´œ¯³¸q›Ö¥¤Ñý‚íóhÙÄ­‡tl!96'™BŒæe1é˜`¯‹ÂMéùèǺì}@G+ÃX†ƒÍhæÔ"sñ•Y‚»Ô\CÏv#…ö~Š8ZCòê ª†?Vé§ÇeÝ¡ûý€Ãû? {TŒAßÚ*˜HðHã'¾âËPˆ#l”f‰EC¼;Ç;ñ9PÊàì'ÔŠÝ*›ÃtIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/showalternativeflags.png0000644000175000017500000000131514507760372025200 0ustar olesoles‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ ;\$¤ftEXtCommentCreated with GIMPW5IDAT8Ëí•=H[QÇ~<ó‚‘ JR‡”T¥òQ!„VÚ"‚d°¸»—‚‹ƒÐE¤B¬  ‹tè$E:Hƒ‚Cë"¦#Òèà©VšÄGxÉé Ôb?hèÒþáw¸÷wÏ9÷Ü{á¿þ¶JÎ]PYzzxVWG °â¬±ÒÙ‰Ûáàà9wÕŸnÐàñðne…Ó`Y\<30ô“uª×K¤·—àÈ7Á "†ˆ\XÓØ^/g>ðô4Ÿææ  f{)੨@³Ù $çØ66h×ÖHŒsb±PžJSU®mm…x“É`r¹¸ÓÜÌÃÉIªúúØ( …ø"‚©¡ÕdÊŸo*‡‡ ª ë`6ÃÁétš„͆Åj¥x{›ÄÉ fMƒ½=’E"ˆ®Ãî.ÔÔ€Õz5<L\.È "…²2¨®> ‚pñû‘¦&ž#±Øå:‹ §§Èæ&ât2ãtò$@’I$FŽŽxéèàu{;¡õud`€Û€>F€)À\YÉðè(¼˜ ¶¼Œ÷¹…¾ºÝ´åfÜ“ îîfIQpuuöû`Àn§ªµ•§@ËØ罹àÐÜÊsÁ÷|>’³³éô¥>¾ Ôç)½âó±48ˆ\ÿQ×õ##|0Œ_º 7€Ž| l@TQÐãÖFÏ}å[ñ];;¤ççø\Ðg®¶»¦áÌÿÎñ Lç: ®øBIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/showoriginalvisibilities.png0000644000175000017500000000165014507760372026073 0ustar olesoles‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß kùbÓ5IDAT8ËíÔ]h–uÇñÏÿ~žM]¾=#±dº93(A|c&bö®YxPdu 1|«Ô4«[-Ã’p"T„'IF”X¦;°„X$+Ì´n©Kç6·=Ï}wàm¤†ÙaÐuöÿÃõåúqý®ÿµ —½b³°6¤ÆUpàÑF?W\pû NŸWt{eI·ÞëçÿÝŒ…0渖IÍ&ó&v÷£ÐáÎ\âÞ¹&-6+±;Ê>VeÐÃ#N0ö¨3(nëÀ¦zúòäK/õ/®5¼~œ¯Suz'æãH$6kpF¹iµÇT—rÆ#ï]˜oª>-‡ª‰Ú?e–|xKÐ<û^£²ážÅh|‚¦(ƒæQg•ߊe6J)EÖ£Kµ±m•º£”¹ÓÍ~u¸Ñô "$î·F[PÌK#<Œ b‡ÇÏ3% J"{:nОÒ9³Éóù„«mkmE6øÇg™!µ‘àî! bC"±¢ØwµÏšÛP*[ví‘^’ž+iMP8¯¨Ç…Rd?œâ T Ö ?mf±Lk`Q•KMì+×”µù¢e»÷øì2O¦:J9jŽÛ;¬]Wo™òÆÉ^ )!Õe·ýâƒ(±*¤~ ‰ÍQ~µ9Iξ”ê޼哌kÛ'v¤©®$P÷½#7ÒÞ—Wìê/ŸFžÐ ¶ (%Ë“µÎFmCý­=Xm!B¾Ûps§ß½ 3·î°~Þ.s25g'±–¿ÏãëƒÏĘŒf¼íÙ²ÿ¯«ë y$šk{IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/22x22/actions/showqp.png0000644000175000017500000000124614507760372022270 0ustar olesoles‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 39/i3IDAT8Ë­ÕYˆaðß9sÌ9s²ÔŒ²D„&K‘LJ.È…$)$®ˆ¦±DnŒN¦d»¢(K)kM¹pcW–’%¢i,adÛ0œù\œï|“9Íüë©÷ùÞ·ÿûÞgùh2Ù¼(j'Þ>âÒutßÀ¦²$Τé>™=)ÝÙÄ¥k7®è7ŽMåÚLŠÃ÷ ‚œ}Øs¦—®füÀ?~1†bÛ„v¨Ý‘äн?jó– Øw1(*œxò&M#çôKN6o¡gŠt7Ê8u»¨pµéý4ÿàòE-ãëpž/¤¾‰.|KÅîÈ7žÏˆ|H£qM¸>†ª)x–û¾ê‹&rs?êˆW&¢ˆÓT,çDœ ifh “tŒ¥{[hÍCL%“ŠTÜÀ2§³;I]5KgRÄÊOm,Ço‘ĵdß³« 2ƒ-#¨¯fy†D[¨[­ãÇì½À£å”,¦|5)ú$*¹dÔæSº?±Œé÷î}ÀÆÆ6?îqûö×ôõ€_Ü/6Ðõ==1t]Q«y@*°­‰H§R*nšæKóÀJ"q&ÖÙ`{{ŸRÉ&•J°¸øÇñøða—T*Áë×ïéíí`ié]Ù¶÷¿)ŠÈ·À?€ˆœ‘- ŒçmøIò€1'"¢b±X4›Í–€aå\.wÞ·“_A» ØÿtHƒ< äár¹ì¡ "`XD‚äâÁ˜ŽsrÌw€Gøk³øˆÈ ƒËƲ¬oLÓ\æ`KÄŸ(¿ù `¡Q(Q¡PhÀuÝ’ˆT[çóù¨mÛšRê‚išŸö–e]ô¬ÌÙLO{¿°ê·h¡ëPWLGuB¢³0ð+…m¿)ô áqQ˜ˆMhÂdáKö“ð ë„Eí¨]Žá8‰›á|¦]Š8Œ1hÄR\Ç ” B¸Ò´'^á;º_ BG ÁlìÎ¥Q™öNÔà>£\hh훇Æ<”ãF!ƒ+pÏ1Rx'tÂ}ŒÀ–´ã †â}¦~ }°³0S ÂXÔãÊ„Æjzã6b.ºàhFŸbPÚkr^‹:Ì,§P… ¸ƒ=˜ƒ'¹á6^'´ŸrMivAuÖ· ÝÐ[x]:äí?ÇeôO»_ªÙc¸…¯'…oÙ¯ºP蟧ßÃZ,ÃtÅ ¡$¡2£2ìÏ,jQQÈEõÙbK„šjzá*Faq¾ÔÃmİ´÷aeIF±*¡‡ZA›ÁM—8’\ŽkèŒ%¬ÆÞômÞŠÂúvÿ€ðVø$Œo#^-|N·ý»ý>9/é=† ¯Ò0_h& ïþ Ü ™Ÿç0%» Ó„g®ø'¼Û³Ö÷ó¨>ø?Ú?rš%Í4 IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/0000755000175000017500000000000014516225226016746 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/128x128/apps/0000755000175000017500000000000014516225226017711 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/128x128/apps/aoqplot.png0000644000175000017500000001203114507760372022101 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝ  Ãô¿õ¦IDATxÚíyœå™Ç¿ÕÕÓsÌ s3Œ ×80€Ü‡¢rˆ":¢"*ѬxF7²j´5c4Â~\c¼65Æh<Œë•5š5º&.É¢qUH$1‘û˜™é®üñVõTuõQÕS=Ý=]ÏçóÂTuWõ[ïó{Î÷yß—\rÉ%—\rÉ¥Ì$¯;‰“<ža5pØã²3;ée@q5Aö’¢¶?¹C‘}”§2?¨þ¿Ú’þ£¦4èC…Nhm°ËšäÓ àù4èǘ0æ£Ĺíò$xÝ·cÓ ÿg„K€xÒemÿ8^©¦ÍL€ÖNuÙ”úŽnǦ •¯É(@•Ë.çiŸn€¯Ja?Êô¸«å†bþè²ËYº2l€’¾ Ó`{=ŠÒ„2Òk2wºlsŽ>ÓI¿ü_ û2_ß—£Ç ‡¡(Í(^³?0Ýe]ߣ€ù@½êik”ÊH`‰Ö s@ò‚"ÃOêL~Â/]V÷¶‡I¿ÖêS¨@É%x,Š¢kí%&à-—…‰k€ 1Lú5Z”¢~‡€· $‘þQÛÓàÞkÈÌÖ¹,O o„g[t´ ý6(ùs+sº¦HðîhÓußFd1]² Íãfy9L.4Ø×á)èw­þ ½Â(ýÈB#ÔåÃ=¦kÿße»=¼«ü£ Ê )ý>NûC|>P¼´€ W4À©e†k«€×]Ö[Àqšô/„1¥0­Ôðy "ÿÞŸ2;>*ñ yAñÀ¦1¦¨`°Øe|<¢ ™pÿ(qÅñf+zF?÷{¡öGqƇƒ@òÂÿL4h-…ô˜ÍL{\¤I© SËƘpV?ö9ÈÕ–6ÛÿHmÊ øV³2ðy¶ VÝzÛÿüDzgÙeYw„T꘸¿äW›ø{°RµÇ¥ˆÊžC@ðWà%àütEqHC´¬KÕ€ pÃظ#ÔoÍ™Ü\“­¢œ—uÜ$€žEà‘zSo+? }7Pƒùˆr­EÀì¿«„}öb¾a=~ösð§?]°ËÓ p Ê^1ýÞ(àc×ôÒ\=@žœ¤¦ZUuªx`J¹áûQŸ‡Ÿû]ˆI™XÌÈ‘ÀÍÀ>üü”‰4“4–ç{Té—­5I†Ò|xm†Éøˆ,­"òDaÂËúKDH¥w¬&–›®›Rñ‚ù7À¥4Ž@œÉ>þÊ9\†Gœ/Ô˜ïµÑd˜W íõ&¼æšAmÀ´ƒ›[áÖVó— xŸ6œz¸?3ÿŽ¢Ò£0a¼·$›¿ ¨&£èYè˜BÞÍÙ®^ÔÜ8F•þ°&çAU®Á–žÌ­\¥2_IPâ­óU ŸÝ;ˆ¦…†;–šî|i¶›€Qè&Y7ˆ,[¤$ 8±6t‰Õ4äß’Êx½Þ Âï¡®:slšµçC7 àÇ‹_õqü±p¿Þ§Þträ«€9µjw+0$élH;¼PØ û|ö ya¹ª±i1^£ÿzð31z–ƒnyÕðøäœØ÷eÌ/¤1Ìæö|ƒlÖ*6%µž@ (ê8´hÅÏáxøŠvîð“z4ÐA J;ªðqwí„ › (x:i™7€¤ÿP!Óó~.×¼øRû¬<v¯Þ²K‡%(©ttaÀá°N&õª]»¡îµ” Ë4,~a<űB@ó®Ð_÷æ2áY‡;Šj7Ëf¾¢“²1@!~$üáGR=ŠJä¾oÝ9T ²:rbø/aí¶¦;MÉxé÷S¤2? %õ_٣ܒþ~« KœÖpˆ;8Ê_ì_ú[,òš«†Ã'‰n›kºô¤ UýØq¢ Ö¼8Ïhû/lñÂÊÄüñ-øi Së}¡:~l³á+ãLÛù^CÿOÏ@LV؉b<¦#ddH¨+[ð3ÎAæ÷t=m]6¯–`cP]mú8eÓØž1ÿ+¶|¥.Ö{LÎiªíI0¢÷3Å1æÌÔü®F$0±üܧDÖŠÎoÌ#2(ì»Q]dÄDýí¼aÒZ¬ÿÕØe7ÅÛÜÀr‡S)S4dú §>,‚ò@°¶K]#a^àºMWœ™!Ìo®·|Mð8@o"(I†7x Ëóµ m}èÌJ‡s”Ö›ají‘G†/JEæÈ.fuÂNy¹¸ ª‹ Oµ0CÔÿ&[ª3ð·H>€÷Àìƒ6%ßM/½E¢N'RB‹¼†©ó’d/¬Tk¹l¦&köCW¸c¨À˜:ƒAœ¸ h±¬úet•az v·Mæ+pKœ_–fŠÆ òEÚÁôfBe`’¼^Ø_¥fòl€@Q p·ptõ ¡Õ3M_—¶’ïÇ |ÓŽöãacžÇ€ì3¿=ü¥pöäˆ–Æ 2ÄãsZÌö»ÐÛkè­î³8švë—Ï1}óü4Výo[~b¦!ùG ëaûH{}hõÁÓ5b«ÍE¢3zTƒNm5‡pŠ ¹ðN}à³X²×¶Ö”æÌ4•þUˆ iË"ûby´<€Q °'ýhì5,+6}ãB‡7´´ª±&(‚¦Âklúl: ©:+Ç6(Í‘i*ý÷ÙyÒ§j¡Ì ˰WÕ„_7‚,÷¦Xó  (7)ªs¨öDZ :G&J;· ®.·‚¯} ¿R÷]i6—¤>@@–¿b´—q僇rtë­Iþ7k`V‰YÏ?Þ®\'ÐÚ¨s cÌìm¨ƒ…ÅöA0÷/ðI¦N@L”÷Ò¹i–ð±µ7Óöª–Œ€=ˆ¢Î]Ön6·nª5:NZ‘è…f¹°\‰nåßÔQ~7ʾ/6C[¾}Ÿ`ôV8Ø '‹EÛÒDöëÕ„eÇ`ÞlF4‡ïAÛV5›Cõÿ¬9zµPËPÓM}|`Ãv¯ÓZ¢”¨GÚ@†Í-Pkó5A`ø°p’átP“RÉ´-,ÔŽI>ÜÙVA´(˜³þ8{#`,¯¶@qnôÍò L÷_î$FŒÂVÉ·ä…-möãÑÝðh³éôõ)c¾h¿¶eRxl˜°æÄ@À-E°s*¬®RÅA¥eƒá¤ŠØXžYå®p ¨ ¯Ã4[iePy.lg3‘à÷] Ÿe¥ùkYvTÿY0¢0¬Â¡Ù@üG ¼Ú&Vàz€ÇF[°¿9°Ä5W÷1!T­©»‰£,8€Q4Ak <7Ö&€ÀxuØE†¦ˆùç÷ZVý Ôøà§ã¢ŒI\h¡æUBÇ\Ø1|9±«j´¶Ò<}Rчaíö}ÜÈø!`¬vF |k¸ÍÈ €ØH˜ƒ\“[V0»ï>àéêØðqˆ O„‹UÖ¤M‘a¡9o–è+\ZôãG“Ðú?}”rÃ8­Ê&ºÕ”–Ht}£0±SŠ-öÞQPšÃY¶bm’×–Ð*NÇσ}®z×úð³“Þ=%;Ì¿ \Ðl-Ežt'PØ‚b1S¨K¢L³94hlÉóÁ¹g9ËüPºØ+6¹¸¥V²?'‚Þï?Š¨Ïµ¿Ð^õ“àÒQ‘Só‰›rŒ{õÛÙJöWêÝ$€çtÎþG«#ð'ÕÙÀWð³-4Ž~KL¸ ?{U 'T?}Ë8¸f¬MæG€7¢à5ÔÂÖOC‡V—Yy4UØX N&ö•¤¯.‚áOÁ¶¶Yr ÀÏsÀÕuÛTµ€s¢Æ1á´.iÿ¤Èû7X‚mTH8ööíàÿ®áT%ñ'ß×wsÓ£{é8i:}ë¹P¾öv‘Ȱ.–âgð)°GÍV"ªŠdÞì3^õª?‡Ö$¸ƒ†dE84Ø«–›0<† êÿ@š<Ú&$_ú Pà“ó¡v#t¾U¹>‚±Æ Ì÷¿„í©‹wzîˆsN´Æ‘Gâo(½Yïoz2J>;‰MòBy!¼ÕŽí‰£¤Ú'ø<½r‹¬Íɤ. Ô9…Æz ù1s2bÒHXºªl:7:†“ëaÓ™i‚G`ø.h?ÓF¸—è €e%pà@èÌ‚*ñ]ý‰'6ªªÀ›º1_<^>æ?EâïXï‹Ô{€ˆO:A ôQõKý©d8Í8 T¤OîèÈ"^{5ä¥FúÃûÊpxãÓþAý·z™ÿÐ÷Å[Ð$ž)š ÀÚ‚{ïqî)Þ~f+…§ïèŽ}ˆ¡BÔsD,üL—}Ú ³†þ;ìê yRd'Gù>ùZ5Vs3lýCuVŸ”€q¶v±) PÜ5ú,Ó©±a¸\ïøÝwxrÅ…ô¡|¾ü:¬Ù¿§É!ÆK(èâþÆöÞ7¢È2lݪs†ûÊüxa`O: »òr`Ð ØÛ» ã,ÄŽ¤ ¶»[û 7V®Ò–®tÏB¸¸¦}O ZûNAàKàì`µšT ÑwA‡ƒã q]A(3àÝÇ·ë¿ûãgÒ›ùÕ5"¦ª4·vjȘÆÓ úσÀµÜÁÛáMĶt†ëÏ[_æ,?â&‚ºg5Àø‰ðçÐÔ¡uÍÀWµ“¥e0m¶ó¿ òè ³_^"ˆB.·²±/ÂtÄ¢Mö#^Ió8𠸕NÄÆÜÂÙSW¯ÿŠŠáp—³}·¦–ÂKà9ã›EZœç_ƒŽ£dI\|9<|¯Îs’(EìÒ±ÉÂ-îC¬5”Ã¥þ±çaºê4wv%¡ïX€ÓR8Û\Mƒ>)4tT7e†ôkƒ¸ú*4¶;Î¥ÇÏ© /Ã|Àêµpù:ðå&wâ 'à¼|PT‡„ìà =òø>BF‘G­{Tß=¤ f£­‚ò!öíÎøæQ°þr z’#õ¶|€@|€î¨¬@ÒweÒLðeŽô멲¾ü{èY΋€ï×FbÁíÁœEÐÓ ‡úIâúÝI0 ® >ýÄüÑm?pÞÑé/;pá5p÷õ&3 -Þ<QíS~éÒUpÙ7„ö8Ø™ûÕßN ÀÄ9ð›WçN>[¬¹èî&#iöp÷:ô«iªÇÿ#†\Ö°¸n= iN¡Ã7¤^â\(¶³ì…Kÿ53âþXš-'º» yÇÃí|ŽVß WÀ‘Îk¼¸ ¦U‰Züõá—\ ;Èx6>z/tØ>ÌÓ•àhì=L| ‡¬ç0T Ï·Anœ¶:g>–\w®2Ÿ<®¹Êk`ßÁô ac I>À‘¨h8ë:سo`¼•©a¬0gUhrraÙ:˜v:tMÃäVÏèé˜ ðç-0q Ò !¿íÖà¢;…™;˜¦Ï'Yr“€úñ°¸ öíg@Ѹ0ë|ðd€_cI$©®¨ ë’wÿTÑŒUbjïHOfö¿_ò.eˆè ffZÖ%'}Wd™Ã@Wd/AW¸>€«²×p5@– ;8ðât—ìønÝ>@Àõ²< TÜ00»pM@Ö‡®Èâ(@A¢Ù©J „oºd\.ûÄĶK˜öÆ@n‰;FÚˆ €± •KÙéâñÏÕÙ 9|Åî@e/\ ÛàÀÕáN k²\¸È&r£×¸& {Ïxs!¿Ô¨¬ÀËïÀ–?¹5PI‰göÍ¥¬!;.\r£@—\rÉ%—\rÉ%—²‰þ.ùx˜­IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/apps/aoflagger.png0000644000175000017500000001537014507760372022362 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝ(‚‰þ•…IDATxÚíwœTŲǿçÌ’sɈJPT \ñ¢ A”¤ bºú"A ØÊ Lèå*χŠ(b@EEEDDEň \’‚äØ9ýþèžÙÙÙ™î33 â©Ïg?³3sæœî®_WWUWU;” ý§þoÔvÛ€ßÏl)ò Yîû€ É)!¦÷z}€Ê)~¹x ˜Œàýø/ohN½P˜–®ÇÑ!j®GõG ×#òXòXI˜gÅfö©wl ˜| P˜\«?‘Ï“Hr7\Í˜ŽŸ³?äÑ;äÑÆõ ׃Wðªÿ—!G?Çõ¸nÄvVl.iîîöõ[ „ þZhóÔÞ Ò‰cxr¨ÿÃ`p=F ÛÉȇ+Àà]óýëÌrüÞªÂnèôTÉUïã™k€èg®ÇCvÑs|9´'`zfPÀü‰ÀM–¢¾€\hö+´]¦…@æú€~vë.XžI(%¯,ð9ÐÚ÷}\8f9´^®ß†³\.¼yÓÞCœ«‚òv}ZÌ?\›p­ÒioÓ_¡Å »YéÀ ‡4ó•$nìBpoö ˜°(í[’H¨´KÍ|ÏÍúð8@ÅÇJ1öLÕËðH»\ó] nt$°J+{þ—Nÿ2ë3?žnŸ¢Ú! €k€F1<)LE°8)\̯üªŒ5kæË˜ÿ—½‚9ù%?Nn9Eyàé¸1Žð§ °ÁÛ(ïk®%óËßëß9>ÿ-Ð!hÓd-m!”V¯›«ÂÏ `isXp<¬ª Ž4¾Íµ‡ è­ ,òYW`‚qäX ß}Ìüß«¼¹W—N ’žÙ}¤Öà¾<~jÛjžþ‹\·M†J»nXç)8Ö…ï¯94p.p¶«/dÁü÷õ:âXÌzxA;:ð s¹ZóoÌ WRÑ•8ŽWªœèukexáX[òÊhÆÇÏö0l¨'}¯{šâžŽ$ÌþÓÏü|c¸$K A{„â…k€GN–"ß®@Ð?vc¨S8»3§uMì¹äÍì¤$@*l¯j[ªσŒ:…®=–RZÐ0þóKÚf]ô?§—fǰçbuÇà!€§|0ÿ_$ºàìÎÌpÕæŽSÄÉãv•ßËy“úÒ‡±xÿ¾:-P³<á½cœEžKùë<ÒvßМáa—û=WY4žËº°Ë²pˆ¯=—;_ü‚ü,1¿-$ã$|ù Á‰æV€ ½f¾´d~ÛdÌ×õ1DìÖIß3‹{¹dò›ÅÇBéý†ŽIǧÒ0A5¡ÏMÍØ Ü÷Õ8t†{úJ€ þ–Q­àm Þ8@·x30§tU>ÆÜ·Ëüʼn.8« ¹8ª¼¥¦cÚ4A›:cŠûÁ®*°©:TÛatÿ3¯õ˜e;þC‚çp¬§6¾R1 ̸ s÷†èÔ»=ᙟdFM:3ºÁÆÔŽ t-Át™(¸®_2æ|øW;†¨u=ŽkÛXà±b”+ëÊY~Æÿ_«xO'Ú r<ÞÍóC-¤ò‰'N2<4¶4÷F!x¹¸ Ú÷&Gº‰¶úꔯٗ m7¯$ý¥«ŽP:€ï‡Cë#É>ÌáŽ=Ï`PÖþw-EWsW°ò_fÙ¬™F¦º(´«,ýôe'&5Iûêå)á/WÔSã“!jø`ÃH¿»9·G{¦o šZ€ïq?¤€ØFl&˜Š—oô1 à¼ÙðÞrêÞý¿%Åú%:hÏb‘ûm¯iµ¹ÔÒôÂõ`x=úãÿÃÑËß³>ò%ú«ãLÇØàÆâxãÆ­û ,•¾Í@›T¼í{@ûóh(¡Eª{Kuß)†Î©ÖÀš"âÁÆêÆCÛâ Ãø¥±kl1A’I·^Ý:R¹[GkÑÿ– G*ÞÄà  Ž¥Æ,ग़ýŸ¼À­†¦™ü»[£p*&Aú€Z 4\.î<œ²œH"©É]ï|`€þÀ©Ï~ÁÇ©x“£/h\o‰âsl²øÍ@Öï~qŸYˆÅ½¨Ý®õQ˜¿×PA&ý8ÖˆùuAÂ…tå\©ý&3¿TÌÒl¢@KàB“ÜŠÈJù¾¥X›ˆà“ Ûõ‚v=é…áÆ“t˜èC+Þ £G"•pÍü G˜\4z=ýdzâ?–K5»t6P@EÔä45ÉàRù&z™ ¼Š 0ýß"¸Å4kgÁkÊr²Ø#>mãUÀ€ƒƒÜRÅÌÌ-G3Q˰?ç8™ ¥—œÛ¥sʾ݌Úò1åÏg^4m‚ \‡Úã7¹ù~”ß(mëÔ>pjoŽÑKŒ‰ò÷Åô…E½U@ø¸pr+˜ÅÔÈE2‡Q1 Iéî:4·˜ÝžÁ4•@§wß+ÔM Z¿œk“Rç´Q2ÑÒ Øcú€…¯*Ç™IôÌß·]Úž²ÿ﨎Ùàä좰4°GÖìvCǰÌ!Y$uA;Zjý·!Øb}èh ,µr2‚OLoÞö8é|êç˜j®¯,àÅ—¤ Ü–_‘·Mž*ʹ8@K¯%êŸN6íd8çKŠæ4&¡VÅôa&PÃBôÿ‚ˆsJ€XúA]à‰8r‚klµèpÔfŽ4›“2²®FfÏítßY>õåP57ú¶'‚&¹ôlCf|àÀO¦ÖÔY])Ÿ W½,œqÐÅO6µ›ÄÁrp°[ß¼ƒMºö‰ýàľTE]˜*M#Î?=CÊ•ng™ý©C=*ï,lñ! ›{÷Ôæ0 ‚áÓçLùšÿ3@Ò ®í]€g°óõF°2}PˆÉ Qñ!øÞææK¦X‰£çgÎgÛŒùdš6˜*QšQÓÊÃ)jGg¿ýç[æk¶l1üIµ˜±ÿ*LÍÆû ¢Àrªr[ºˆ‚à%›!'jG‡) ëuÙ  & Jn¡ávôÀ.j‰Vë¬5µÍ°Uõ8Ì·d~pVìäõ¯ÍËd*ùY9·ÈGÞý¨_Mìp ̉y¿ÕX(so)v‰µŽö{røÌ¯Ïh`HÅ¡ä•Î¥ïð Kúöh}1OÕ-L—!=:džóc«F²UrŽ„£™³ '·N'ïËZÚI€ÍUi§f›U=ÁâókÝ5n¦awi`J™¬ô\NpîÉ2Z\•2uj&ÂæÎšËò7æf#¶™-w'z§þN3¶d>xz™•Û*1i•hÙ‚¿+öÃM‡™1mܯ!°ÐÉléP+^²g Ç\ÎßqxƱÓ^u?‹lÒf“‹Êç%þë ?dÄœmÿ^Æ.Ë%ÀÉÉG9¯Í™¿•ˆ76†jßD:&XÌ"ï;k§ßøXä¤;ÂÍÿšH¹jƸ3SÞþ¯É.m5@’²ÁcÆÌóóìRæãR›å€¼ëÞõ·ÃJxY¿ŒD>¿8OWkKOuä»4~p@"Y¹ïÎáÊ®à`@¹=I†- ×K³øpϰé Ç,§¹#vö¯VWa*PÚb£êêŒH€ý¥8Êõ¢š²±ö*¡[çÎ0û½¬ÀÈ/—d–ÍUõ v—5zV¼0[Ï1b¾ƒrÓoŒe~½ëAÂ)º€>EðQÚ:@ý´’.Oíuêœ÷˜ÿ^ö™çšI 8yE?l¸ò §È¤baFSkke*Ž&Ì?XËü`í“@A˜˜©À9?ö>¾$@½ëh‡Ç§Žeí? ß8›Ë:v…J -óŽ­ì}°’d¹<œÝå UÃõfÅ+¶WD2 0y@9öÃo5µÁ?"c{2‚â¿\ý4ÔÀCaÌ¢š5BîˆO1–µoV¯‡ä* Ÿb[ø6»ÇÙ½d˜oCù!œ*¹,‰_ÿ›¬1ëØúÚ8¨T÷rÑ5Ì~J ìš!Xÿe£«¡áÕ4†`þ˜Õ:±ÆÞPslœ‡ÝÈxà?Ž=óÃÎ!üÑ[%Îß©.»pß VÄŠÓ  +UZz|ˆabJ2Ù½¨ü’èË_'>’C|9‚ª †?ÆCÍ[x_:ÑÒ*¶5Zç»lž÷æ™àFzÀ®2ÔÔŠÖJ@¹¤Áô…aíaq#â£Äæ/D˜9A 7™+¾ÉUæÉ!ú¦z÷ñ£LP7,¥à9Ô¯v+‹ñ¨e a~»¯]ÃJ¶õ ¦H5Ýæ¦Àò&khšŸº|ûJÁΪ¨`9?À)4V!x)ÙÖûQÊçRÝ+HI¹?áHväÿ“›sî†üQ† ÜíêµâP.A•‚«‰?柰p¦aˆwöÈtW®Î„H’· Y«åf±‰kê$¶øK™¥¨K­dÎjEw^“ÌüŸ§Òú“CJß™˜ù PæØs?”Îó˜Ç¢Ò¨õõ-Íà«"ˆ"ïCˆ¥jDÆð»!`ëÞ’Wðܺ›¨m2ºkê]ÿq ´™‡Ï9l3£ušÛ©.>úrëä{Ç2oßèäYÂ5ËŒ`‰ô¢bÓª˜¾¸é’—Dã¨üþóôΪ$`øWÀg¨jB/G¿óˆ  vPUOx°MMÜx¡°@2-RQy—Ž!(¦-/ܽ›¾À&àH%°UBÏc¾à?¢NyèYˆù…© *Ki:‰`p²©ð :šb½4qݘÿ»š>cS­Äp2\¶§º`ÙTð\¦c^žÏ. !¿8æ+¨A-ƒ`0¿Õ¾á;jK—ß42þ&û5ëšÇ50U"Ôø\—œik„aªJÈzÃöÇà"k]íäW•ÎZ÷‡VýéàØ‰.È}È,’+€ €î>D~„^ûñ9Zí.CxÙóôÑgÿLĤN¾@0p,¤Á,TÿÿÔ‰,ÔÝÈh])àpTmà(.£b™ýÆ…¡ŠÀ7/ðŒ´H‘н²¡‹(GϨçuÑ…ž>4ý‘?OaT©;aåh@0 •D)ÓTq@ˆ´³;…C°’‘©¨0¿}M1kPS/øØ| ²a.d1hsHè†F†Û¬pëÎqÆ–OŒp$½PûÍÒàAÈ—pêŠg°¿5t~Þ…f|"*¼PÏ.NHÇVâðƯ`áø_Òëˆt’à+_ù¸a{¤?o}„ñ1½æpWæÉË€*ù9|®1cêS2iã]æg% ßÁÓ›N(KMÌJØIG&¯‡tek*™>óÃÙ‰pR_8¡ýÀ¸‘t­1(j5MBEˆ¼ûÀÅ’gèHÃGÖM¢µtÙ³v è|”†ò˜.uDðe SÑh=ö®±à´Á“NŪévj±‚×DÌýýþ1_7WÇ£ b¿‹`!è ¦"…#(ç.ÈÍõz=“E” ‡³7<Áàºab~w Šæ˜Ž‚eÉ@àÀZÃûÜi:àãVñÚÃ+“~mzAÒƒ¶çs©#9Ìp\½2<†ÉÓbúq2ð+‚gQ‘ÂÉÿOå Έ³ªo|T)]ëŸ R¡zVÌ—–Ÿ§¢Ñ ¦¢ 0=¬`èdù8Å5¦ ¸ª Ò1‹»bÐÚävâ–Ë{…€RÔ¼w ìËr‡hÙ7±õŽ)]#8xÓó#Ú¬—š³Qég!Ô)$o¤! ŽA° ¾Ê”¨ÑcÚÐâ3ª¥€Szs3PÝ1¬þ½áqÆê>W2Pï×&z„ˆÐî´Ü>N>´å‘¨rQégæç—!¨©‘:GŸkã!X‹ÊÉë¥gâ$Ÿá4oÆ cÐkü ­Î¼ø[Ohד*ŽyQ3£ß0äKUàuu‹ÝñÎ}ˆïbm[Ôqßað‚ʦÆÝ“ïw#¸^‹²u>xt.‚ÉY€t`οV§´,LPÈ^ÿôufIsÿ¾uOò/=v}0/%ã!XoV0›–®“ñ΢³±ŠágG‚YAª8úŸˆŸà¶]¬2qp¬Œ~dÊëÊÞ¯P(êéçÑ8Ý1gâ0=^Nœâ—Š'¸ a~`æ Ê±Ù0PSÿÖž ž}ð€;Ü¥—P;‹éTø’Àºû×2ïbb¯:Î {:t‡³ºràE &îùïÓLÐïŸ×Î1Sà\[SLD¥Ù V®Vì6§5ç ¼Z·÷ø`ÚãÜÃù¥òyI¦gªª<)èeo”ÆLƒÏ˜û„C¼‹ùIl‘ºŽ‚Ó0?ýD¢6ÖžOh&aÀe¨3m}‡fþ¶ vDN%¿×’i‡WnÍvÇ¿™)%cÖ×J0=Âe/À™Ý¬&˜¯šÌÿê÷¶yÝÍ’CÕÌo„Ú¿·)í¡R˜¶g”ùíØÕR ØÍ‚åõ™ìÓgá=ï>Üøú²†×åwꕎÝS'¨±§MNÓ> C°95 ”¾%ØŸrØ•*ó¡\Ì´Á£ÿà‚°ËzR`ȨßX7jƒñõ[ ŸÐ ó­Þ _ñ 袃-&æJDÑÊ!Å`Ž%º /‚o²ÆüŠa`¾öQåÁ«¨R&-Sì é †Þ»‘q–­4­V_œé[±|JôŒ‘ Ã,•>€ûŜ䑴GÕ呆ÃଫC…‰²³Œ²PŠûãÀÀ‘h;ÛŽ~Ît—e¤œêÿPìNt`y’}’"÷ñ>'3õŒ,Y*èа;Â¥l³Ÿ¾Ÿ½¹!zÆ÷y}.bèˆmþÊÖ^ÙšÊáÛáB÷,ú*æ;<ý½þìÞï¦"ÔÀ ‚8FjlGP-ÙF™›`ÝŸk©ô-³81$[h†Š¬1^KóÊÐõò1|90M½î4² gØN®yþk?ûy ‚!½þÝÔhomŠ;·¸­òx ð"*"Æ”ùûPnϼ€Â@¨ ÿ*…¦ßߦº¶)]~φ]®ð\ßÀE†C|»tÇé~^Š 7¥éñE/“@v¼mÙÏP§QxRmh„Îíóa¹d¬W´ép\ØeiK€ô\6å•¥ÎU‘¿× ¼v®Ù>AX›£áâú‰®-¯76Õª†"|)HÙÂßc–1S€:.gc&Á|ÉI¼ç¹t »8–a—|Ï¥ŽtÙòåK€`)ªº¸)ú¥:ÆOéªÃÍ=7ÿ d¾ÀǨRu6æ+Úše —žޤ™œñ´¨îzQæŽÃ®|ìË&Š(_é`‚q³"ÑÍst>(Ä~rüt94sT§˜3liêb˜º„<=kó-üÓΤ‘+É]Ô ´…Â5 –´óLûàÆÙÕ #E’4Ø!R›öànE^¶AK33Ù·|—o5¸–§XƒV8pâ‚×¹°]/ø\%‘ƒÊ¶ª½ˆ0wûEL*Á›Z'Xã,:¨™_ÐÝ((ÃjJ½ô¦SFèå… ]r_Y@sà(©¿^¬õ”·€14úø-š¹_,8¾Inº±$Qñ°D}qx-jãEkÔ?ègQË G;N*[š‡ýL×Ñ,µý1àKÑ_øÝ†?ŽACj£ŠBu"®TÙŸ‡k­yØ&ª”l›GY¬ûºX§åY‘IHØFÍþ”Ì/f((¬`l=3 Dû-äƒù¯øa>ØdކË!Ha*Z·µ18"7í»un²ÝùÍBƒÔGûÜ¿ž+ÿEÄ<ü*ëºÚL³e¾œšNÛþZ `°ß&UcN™ßñ,P¶‡aŸkq#‚ÇÓi‚ûd~$Êø'Kó°7Â*Ñ”ùÏiæÛNÈÙé2ÿ¯,@%Jn*YŽÃU:Ñ2Ý6®}- }üúsDz¢ÿ¯+ °ØÇÍ•ÂgtL¢ýà‹èëíÚ,mà£õßeŠù] P˜)§¢ÊÒÙ*_SuȼͳzO‡ùh©V!hœI…4@aóË–v lž\dm/x_•š}*hÅOR­D¼¬GŠýýþA0ó0ëxiÊoÿ=ª¸FyTÝÉ1b>: ÛQUÌödÚ PX#ŸM$òÖe£RÊZ qgeŠÜ€û…ÐÒ-’ 5_gGïÈ–*Eµô2À*­¨ˆñ‰H‘'Ümd€Ä (… .=¢„Ç(’»ßÁû%±õ 9B¨`’¦%8ë¢ÊÞí.©®:@r„õ6øø&e‹rž:×wIv5@jÅðV =*j:S@1¯÷!¨L¤:š(ÙnK€®EmÜTJÓäÛŽªt0þ@w-€?@\ô£ ‚ÚÄ'°•Öõ,"ë‡fSNÀM_ô|´ÎŽÚKhŽJ0ÑÚ¥×òµÀ¨Ý»ÝBÄÿ‰f•ü3K„?-9Yfê-ÀíW¾…p®få„é³/ÛK@ET¬z*ªpòLT²È¾W®E8-àУÔÔåR\—±à/N  (@@ P€€ äH¬Ty×¥ƒe3è„|!H¾’F DŽ (Ð P€€  (@@Y¢l;‚æ$Ceƒ2þÿe/Ëý¹ÏXrIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/0000755000175000017500000000000014516225226020406 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showresidualvisibilities.png0000644000175000017500000001057314507760372026261 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß (â´-¦IDATxÚíy˜ÅÝÇ?U={°Ë.—+x€r ( 1*5‘p©Ä€&žÑ˜Çëñ F_¯ƒ"¨ "шbŒ!¼_ÏG}£Qc¢ rH@@"×.,{LW½tÏîìîÕ3½»ÀÖçyšf»«»«¾õ«úýªº,‹Åb±X,‹Åb±X,‹Åb±X,‹Åb±X,‹Å² ö†‹¼t I—CM©8ÒQô•ŠƒE7Ç¥T*ÚIMµ£X+]IÅËRóÁÍ[ùÖñ^*€_~<¡¹ÉQ\'5¥Ž‹¤ Žò6ÿtAêúïŽÇ¡™=i;WÛbÞ‹pîq •Š©Rq’£Žò ×/ä ¤b=Š17ìdI‹ x0ÇiÉ÷•¤+Yï:,|欷HÁ™CéähîuÉ„BAñ¿ŸPÉÿµ@sõ W2GIÚ+”7þ)ù¯’LR‚ç_xV>ã‡ÑËÑ,‘švŽëZˆHøÞçš*V5Ç=\qRi>Ð’ã] ®åo @9à Ê•dðËcukç½lí øé ŒG² h×j_ò@!]š%m—¹Ž7¬R¥ÀN=™QmZcÄ©žkÁS:.†èUý8CÀEYúÆèÕ&pÚpºÍK-Ý 7'¸PÓÔÌÈöb„æ¥6'€Q#(Ö° pZúÜÚË÷hXé]Û‡sôÌ!‰CGŽdJ›€ÔÜthEáõ0¹›Þ ½‘À=!\Ï­ÃGµN~DZ¼ö¢Љèœkò2 Ë5¬G°E+FÇ™º>Bð"š^9ÞN™€2k¦0x~ŸÀG#´â±, ü­y ølÖWlL²Ëí·wãU§˜ˆK@ÏG¡÷%dï ÍyZ„“‡Zpé>/Ý XûßøýbƘì8y#§NÞŸ@±aÚ'BNqÛÃ4Žû|@Ázk0yîçf…_'2Åÿ¨u¿Îö^®?„ÂóçC«'ŸÂ û¬8y G `\ûÍûwðÞº<)÷›vâË`Wå5R‡œG5N#Êj¼ X‘oÉÚù[±¿%ü­¸Ñ>Ei>;#ˆòN«@ .bú»”3<›óD7³ýÎN,~fÒÜYÄÅLä¾5L· ÿ3ÚUþŸÖó=3í³£„‰ÀÄf,†ý[¯ ¸ÚTëºòÆS§s.í}õí_ñ…I>=µ îÛFÑõO˜kÍÁ̦ƃ„ÂI~ópëš(áS›çGdR£± ²§KzÜ…C5ûe@GßWïäv𠡸‘9Š›ŸÂ„ïþ–äº|¹Î°S¢`Ñ Fã2:[ÿpG{¨,„âªÌ³Ëvòä1ç¥Û¡cTf¶0;ÚC,* îÝõŽÑÍ'€²äˆr0êf¨øºnõFÅ•1@ÄŠCüŒUÙŸ3Šö™Ðy‡¡‰N(ÕÁ˽>1/ë=¿1KÚQ¯%8û¥òšmX²  …åJøôðÜ ?^³¿:Ø«Q™hW ]vËôÃWy×jÂÊî°;ßÐú5cÕO/ÁÒær2û~m¾ûÖRˆ…4:°ø0ˆ@ ü¥¹òk̽­Ô˃ê<ÏšXË–îx(aY³Ôþ*èTa¶¯ãÂÒÞá{Mc·‘«Ì#"…Õ í5I¦ÍeëX€ëP@mègÛîe° ;‹`C·P½þ[ffú¬5ìy 8`Kæ¾L¼ýÿ¶“—®ë˜˜/KÕØ¶ù?(À¤ìe½roûVmøfsÏ£È$äÀ€Lc]ß¡‹ °j¶)ÝÒ¹Û“™ˆ¬¥¶òØ” e!û?~ ^nVõJwy®c&QXÁª‰ú¦e[g æ ÷ÁOT’O•âÿ ¨¶[ým ð]&„æú¸ÙË„Œ=[ ›;AeQÈ@ÃwÍjŸJvÁÆ ³;l…‚Ø]`Ð9и@…ãñc(éóMQå(Î9l÷ p§Ÿ+1?üÔx‹5ø”ĸ 7H6Eš£ (¨õÜ+“¨†>9"cá»~¥Ö¿ÙÚF[ü7ÔīΧbrÍ}¿æ¹•=øÈ?¾ ¨Nت€ê ^›Ç$“ôú¬ã¼·oe>ÀáÇ0«&µn`õcwðÂ…!U…Òß0ÉoËgpFû‰ˆÓ›–F& Ì´$š¡øw(¶!ÙÚ{-'ø‘À̾¿ÃŠê|F»‰PI„J&Sq*&H®hQ rÌû|öÚ;LO·O¿¯Í¼Uá“øj%e†—›w*’WÀ„… :ßÈ›;ïN>Üœ(€€•~Ph5°É¯I5 µª¾¶ bhj‰6TÕñ Vÿ2n.³ÕdÖ4G§¼”o…yV0 ¶åÕÚksã–^C(žXÙÕ7O•ÎÁÈv7ñáî»8>µ¢ü)Œ“Ç"L2hi¨yù]l®.ïÄíÔÌ(!†Ù W?ƒ¾Í`ÃSW>þY‚Ìç?Ö†ÑÖ’©ÐäZ‡äßÂçµ’!z »“¹9sä9¤g)£æö{4õ¦8ýÓýñ¶ýé…ÁÃ+ÚûçÍF–£¨¥,@×k8]ÀM©ŠÈÑ,c^}È!4ýs„pŽ»Öü¹¹ àcË24¨&úùøcüËyÇ ðFEštöàÐ_Aót†ûì!ÖÔ7¹¡ ¡ÂØD<ùÊ»-òüþg¦;Î*äÀ4æÿ|-0šØ1wqýÔ7í‘g,™Ê®BÔÄøDxÃò™èA”r¢š´àï˜?è{õ¿F5?Ÿ°‡%û=Ú•] g/oôƒ `jD–ýÿ|—ŸƒRÌ EÏç·ºö$©$ÏÒRhVhs–"ýLÝZhâjþúZp ÐýrúK2˜þ$NpAÎèãµàæ ½2!¹¦¥Ê_B­ðÜX“Kë—¢VièI àÃ$0OVÁ8<¤IO¢ìÎIý.âX!XhKpçëo²™–ÃÅpÖ¯Ð),\PW”:cï6Õ ±œ/‡^ÂD¡P0Wrêöþjø(h hÁÂG{‘ʆ9Sv_I9kΨó2ˆý÷_ð@èy1¥¦ª€š‡Ôäú§³²@ÏK˜„à‰,üö›ljI Ì-P"܆ÙyÇ~ _ORÛ‚4 5 ¤ °Uˆ†±—Àèqw‰à³–¼ýzxe›r}E àõŒßÙ) êrú&౤ÔÆÞ‘±ú^ÄÙF°„à2¨v •‰¿?pÀ•œá(A_bÅŽ£õXc°Ÿ?‹¯Á`Ô°7’ºÊÄ„bQ Ð>@·>ˆ˜Èj¬™Öt•²ŒØïÊÍ4¡øUí𸿾ÆW­(€/!³5tPº‰ÒÀ¤f—ö&^4ìóhö ÐFgäy]ÈC ºióظûîäžWÚ& ó®‚o9¾fÖ{ÿË‹´.‹ÛU§>ž1µ …÷`L‚)K™Ék~·¬¡yõ5ÓÙ8¯DæI9.ààâ@ýnº©HjJnà Gs=nNKŸ aî—™@ëc,­8¼X¹PDµÓ¨?Ÿš‡R˜ÞÎÆÏÃjÊ3 Tñ’ë{Oïšžúþëw í—‘Žâ1s“Ô0÷ød(|®ÛųLÇãC€ww¤ÀŒmÚ™IÎìå)V“ $SUuÒ‚žÏeZpl€[ß\>ƒóÒí·‘‚;…âZù¹ÎMöŸ¶è¹”C’­E-ƒ2Ú[4½šXÈT^€æŸi4ÎS§Uܾ™n0ŸÿÆŒÉtà†ÁŠ´½}g¼`+|Ð|a$`¿† Í9MúH)AÞJ“¤éH ï<•ÚÆ :›…YLS³pû}ÌË(|!ßhAß=Ã3ì™,6Uñ=Å” ’Œo¤Ž¼’ÎÊæzáGŸÅO„`h€fY m61G*ŧ!LZQ×Ðãóù­êêejš>5ÝQK¦%õ’[}ÿJ>H“b,—ër&Ý ðb’Ø2ËlerÉÄÈ>>_«5g.}’qK„:«¿9š€å¦jFpyÊŽn²¦E—Ÿ9á´¦‹[)ÁÁš}Öl¾ßÜm—¾§xc@+ 5¼²bùËžlѵ~s±R«M-@J‡¯©p¥âwR4ûˆ¨†n Ï#è@“<@sUÝ%€;•*0žÊ½QCÏUs¹H{8[òYv›‚f³vÌþM†ñÚ BÖOMúSÆ!¸4àHßÜM³y5°|2EëViÁ9kæ€5ò5{w”£´faÈÉNùUú6^Á:ãÔ”±v:#DðE#w!‚O´©€aVª\¹á!ú|3'4¡µ:‚÷„˜Ü®{W3Ûà¤."s„Ïg؉cé/ƒ¬§X_ûÇl˜]?ß?¸&SŽ·kœoc4tßôsØÞýí)-S1Å c3á•¡`€Å:à0½PÌY÷0ïes‘F75Íoãçí¸‡÷ÙÇЂ©Y|/×¥v̆cçLìœãX‰0WÉfœ•Š‚uüR `÷4ރ씴7pu5zN„i[°J~9cu€ œ‚g0y#»#š!5³²äHÚWÄø š•9ôüW x*Èa^ÄãͱHˆÖŒ]9—m¹¤Ñæà7u¥ ¥f§ ½km¯‹Cäš›W=ÞpÝ_+C.S| á¾€‡¹Bñã»Ög7©UëP;Òϯx‚;ÃH¨M à2Ío4ÜÔÌ7¥Zk»ccÓ9¦üåCþ®á?!Ôü·TŒ3Ãʇ6+_“´×9[”"³+ÐÌDÐiÊ¦Ü O†è\×,øâ)F®øSxËi ,Jf°·1™ƒÐ À[j0Þ£ë¥þÖôádA´^\‘,/Bâà pMMÄ?¹ã§I˜“ð]&xñï&Ó¦_ÔKÛ¸~Ú±4BÔý]¡‚9NÂwK¬nv“ š&ès;N]šÄÁ%‚$‚"âß[bІŠÜsçS‰zOqEl`ŸæàMàm`5XË„†‘könªñÖÚŒ÷ÒJàŸÀGDùÒ$+€=ƒtñ½íÀWþ¶/Š·”K¹%÷åå/€°Í—xsç+ýÏÄ-þ[ ßÙ“øV‘˜¿Õ.«êºwú@vïĉ¿å4êÖÔÎ÷3ÏI¸—x:qFéÿ_ç+ñ™ý¼Fçhü·ø#¡ñtk© iNð¨¡é;â¿UûùWMòwUQÿ®¢* ’høïr´X,‹Åb±X,‹Åb±X,‹Åb±X,‹Åb±X,‹Åb±X,‹Åb±X,‹Åb±X,{+ÿ)n–t€ø IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showoriginalflags.png0000644000175000017500000000175214507760372024651 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ "E8øãtEXtCommentCreated with GIMPWRIDATxÚíÝÑ’â @ÑÄâÿ™yrJSJ äÜy[G:—nš »,îÅc…ó€ € €{„ ëºfm³ÆWিô¹€0qù<Á×eýù{“§ÿo_Ü"tæ Ðaý'€ € €ë¸ävð·¿< ƒ‹Hvy>F„tœZÆçÑûàÑ6>áª7þé®Xï·J•4%.ñüj‚ 3ͶªÃ¿>/\ôüçæH0ÒyÀ[ïXxÊY©xö…jy¦ÖªË#¤ênJÀ•©sïoõ–ÆG,+áÈ`rD³s†uÄãèÀJfç·ûúïÉT¿ù¢m¤¬Ü² hÕª=_k¤5E( ŽíÛôlmA© <™öGï BïÎùãêÖò±˜†ÙYÚ¡¬Ëzx_9û?fŸ/ã,™H?_îñÓãg_"Èë®·näÓ….Í¢¡õË Ô‘`¾µ¦=×ù׌wd2E xò)ÂUWë[‰Ú“>WÚpf7«¤.¡^öy½øgã]=ô²=z—Û½gÇù(M!%õðÎwÙz^X¿ —ºÿiPêŒÛ%3¢pA8¢¤©1–ާº½höìSkŒS € k@xïA¯ìwÑ2¾Ë’<{ö‚älV侦­åúçÑzöí½FÉß òbT§0Ë ·g¾eíêÞógœõo¿?ì— Ï9—– fék]ÉhlÈ9+  ˜´ää £ fïS©cáoÙhóZ{ÏŸâOõjtêñícŽ­]Ø`° °M‘w—àèø}:Ør\rkdnÝUJ*Jû]EræÖA( ŽL‚_e¾£!€6Ö˜ªÃ(ùp¬ póö2ŒúÆg¿Èg6’JMØ»‰cÆž“ F«Þ¼ÔØTBCA£¶ l…Ì·Í5¿BÐIæk!Ž}@è†m%›Hµ¾ S´}¬µ`#¨×ÙÑ·°À"@@@@@@@£ð2Љµ‚¿IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/spectrum.png0000644000175000017500000003725414507760372022777 0ustar olesoles‰PNG  IHDR€€Ã>aË„iCCPICC profile(‘}‘=HÃ@Å_[¥R*VqÈP,hqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâäè¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"€Ç„ÄL}NSð_÷ðñõ.Ƴ¼Ïý9z•¼ÉŸ@<ËtÃ"Þ žÞ´tÎûÄV’âsâ1ƒ.HüÈuÙå7ÎE‡ý<3bdÒóÄb¡ØÁr³’¡OGU£|Öe…ógµRc­{ò†óÚÊ2×i#‰E,A„5”Q…­)&Ò´Ÿðð9~‘\2¹Ê`äX@*$Çþ¿»5 “q7)œº_lûcîͺmÛvó<WZÛ_m3Ÿ¤×ÛZôèÛ.®Ûš¼\îƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}2ÔUê88F‹”½îñîžÎÞþ=Óêï¶rÂÛÑk.bKGDÿÿÿ ½§“ pHYs99ÂVtIMEä :ÛPÛ—tEXtCommentCreated with GIMPW IDATxÚí}}°mIUßo­î}î½ofd@>'òå`„-T¾‡Œ˜˜T$&J¨˜ˆ5  )%hü`±’˜ÄJb’"¥ &TµŒ&!ÈG©¥(£(ˆ€Ã›÷î9»×ʽº{uï}î»óæ¾g%ñTíº÷ž»Ï>{w¯^¿õ[«IUqO^D„{á¾ÿü3é_\εÄ\Ï/TQï".¿ädç ‚Ó?‡ºïßÿ¿ëu^ÿàÃ|¶ì4]î5âYÜÈ}é†GÞÈ~¼®ÝGZŽ;1hŠ " „þ3ªP@ Å0gaajr2ÏД€”òçªp¬Ý‡BEALñâýò{ýߥ©<Ûšð0wk…í½Æïчoÿˆ~îÉ܉€ ˆÜ¼î˜öPDš"c›Ôò¢ [ÙÄ&  LmPD€@ÀL@â&îúê'I$ßáÊ æïÚ£ ˆ"¥NPë1w}Vûî2>UNÇkŠºï§^Pë­Š]ëòäé @^ÉÝà)VÕ2• ¢ü9LS/eÄ&¬ŒVŒù|/(¢@JY+$3d7•ªQZÂ&/ è’f i1r‚Z¯;ŽIyNTšv¤=Vˆì:ùßn‚T• U¨¸Œéç¸~å†[U?pÅ€˜AqVîYLÔVF i¦ØTÊŠ5I7€É |¾¬º9)AE@¢SþŽÁ¥È“Úõ: É¥—Ô¼ØÊNmUÖïåPïCmâVå«ÜkÑvd`nZ@Äž³†Dý¯¹÷ëžø¸sOó— ðõw^àÕW^â::4ûI_L¾­Ž2™z°6jŽ ÙªÊ mÅNœ0$À,mõ93AmöËù"ÍL¨Ó³4àdiï+%PJy…W§•³ÏRVªjóQÆÉ'3]U¥iˆù™Ë˜Ì© Ê6;à}ë#ºK‡H8:"½*&@7z̓q“~@µL Àœ'ôpBÚ„,íe¢ªÐ@6M ÿDA³€R1öŒ*P^¨h.À@°[“¬mhv+pœ(u¾Kàü„|sJ69圲zü¿”-A¿Òi’"ô!dÍW^)™$ )°v*Ø¢wÀ£"ÏÇUñb„mò×*ÚÛ»ªjƒ$‡rÀyr‘•’æU j“ŠzŽr¶¡õ¼Ù~&­“¤Œ:IåšÏY44 åZÌYCPÒ½æKÙ&—‹4'`—ŠY40´h ûe墙@¥ÔL"t Uè1 h7›0)Hb~‚­Jw¯ªÖôÊk€ SÓ^õ î@A™¡#ÒA¦¬ZiVp*O³©ó!A#C8< °³ÏH!Ê«»jœ",€Îž)Ov¦YÀI I›£¶"åÞÁö¹ƒ)ûšÌ¬‚ƘŸ[³Ô1q«¿h«rš²3K"ù;b„nœ)ai¸‰° €;¶ƒÖ=²qF& › ä&;‹!Èì2!¯dò a@#a> ˜ 2Ù☠”lp¥…™ó! ‘ !_— DàòÊ–|ýÀUÓiC8¾Ž¡ä  þzhÈa¬@6„ùØ]ÈA¶áäVtÕØ]£Bƒ9ns‚pLà­ @dRø± h—MEØæsÓ&ŸKê` ÐàDUhHÑ]K9 QÕ0’¯)Q#.ªùD™È €ù*ªæC8Åiš³)âY³ mØ|²çPèÄàmvVÓ…h€±Õ! Ô¬î¶<á OÀ;ßùN„BJ)©*ˆÌ<‰ÈÎâùkUõÓéÓ˜… ª`nÎ×BªÒ¤#E:ä@²cµ#è@jjX ×t#@T¨t&ÐÎÂÉhhÛ´"’µŠnóŠ“ÏK“‚4O¶Ìyr9Ä/ _^ÝZÁ»—€ (Îá$²–(ãAŠ|¯¤Ù*q‰RÜ8™ †€l:æ,(icš5Tl)ûƒÌ ¤M~Ðݸ, ðÎw¾þfJéQþº7O‘¿ày¾SU/xýìeCÙÔÔ´ÐXÑ2ˆ 9ÈdL$04r&)A£B|ÀQ2F4çP+Ù ’f¯ؤN‘…%jlfªß] UŠÍ?ñš‡Ô©Ñ"E ”É%².ß4›D™P}e5üŠªPjÚ…ÊXqöÊ"IBÚd€@Y(ò}J$s¶ÃT À.×ü¯€££#ºpáÂcÛÿ>ÀßðÏüTY¡É¸ `v\©G]MKH´•¸Ñ<ù¦4h–pÉZ ߥ€âÁŒ8%ˆæ9 Y4$à|í¦"öÝBuò³áUÈh! Ee2sÚVe?ªf¾¢]ªØÛ™vY²É"¤ - ôÙËHùì"&»‡"L¦¦|m ¤L&ˆY„ @P\† (*¿¼.\¸ðLïðÅÍmÂ7¸·ýý“î"›¶:¤z½7m ³ªá…*è@giŽ("[Ll›£-Žw8œva\ÜE‡ˆclʼæëlˆK¶Œ Ê-A(’½/Ýd¢†ªs^Ì€¦¦´š)(á+ A¡“M X¦0µÈ¥ø,M(4™¦Ð¦ý4ô ƒ’BÝêW¦¬¨š€Iž  q!—¥Üä—_|€Ïð`"úUýl÷µÿÿm6ߨŸ]œ;ïaWªMÔ´s9 b0+ÒŒª65pvÒ¢à`J87ípwe°A„ó.ažì¼)!N l%ˆ f HÉlk²ìÆØ f±X›œÐ Lhš/¢æ*{¬YÔ˜õn~ƼÒÉ&¢€Nù™©S U Ú§ù¾ÇóEd! Y¸‹É`)z9N ½þ’ÝÚ³¼ÑÞû€ªê <„ˆ¾GD,»§¬\b|ç%§ö€E­*ûpM à œÑ zÉ8 À6!á0ÎyeØ¥€iÎH[‚Bhñ§eŸ!rFÕïõÙ;MÙ¹ôÙâ•¿Y៳ú4ÔÞ#¸ÿsË/i°H…û1¨cóW‚f•ûëä{4¡HZñ”ôSÉ—«Ì¼±L|ñô‰èß«*žúÔ§þ«‹/â]ïz×ÿv@OЊv•» œè2GJ«C+˜³”hq»M‚CDN˜BÂA˜3þ­ŒÉ&›Y¡d‚“ €"CÃ)2fΓ®õûµÅøæÍ+Ä”ÿ^äàý¤h»=×W”Ï€¸„¤0¡õ:â|*‰ÈǨ[LÎYK†úÿ p,ƒàËôü¤¯½÷Ö·¾uù?r«À#q¤yÒà –´Õ¯!<“‚YƒäÁ"†pöcH8˜f†y³@AØ¥€óA0ÇÆgL3&n²ŸLÎC¶l9ö, dÑ‚Rfãh2Õª4 gÝDwÆÒ="­Ó…£É»…àæÝ[°€ -Ò¨x×€&GI~¡Ùõg Ø  ]M$°S¥än°,’ád7Xœí/1êê϶›!ÚT8ƒ ’""rB ÁÄ)A° 9„Œ¬˜X0…”=i%̘ƒ€ƒæ²ö¡  ÷U;ž|ÝÂ.x.­Ð¨SZ=‚Xž·Øm7±ue«ÃLÝâW¾€µ(€•ï‘pÏ’C+B±Æ+ƒæ <ä†ú>eˆ¤`˜£F¦<‰9YV~7BF­*ç`?qßäÒpž.aí»5&´àµ÷uý|]9wqß{¢€ìüa@•xu¬3!Bæ5Û³ÝfÎ6>² )!2Õ0Ž(›†È‚‰’§˜9û›8ã83¦ ØpÂQÜI!JˆÂHˆ1ƒH)0ÈÏ"lÊ IDÊŽ {Zu¿žH² !ñ¾£ó Ôiµð±ú?Τò9ç”°tŸ `i"OD8<<䂞?^½‰ç3]öŽTœ¥êð9wZÉÐBSûÌŠÀ !õo[ͱ¬zä÷" ‚;7° Š™‡ 'Lö^51!çÕ‰ì»Í‰$»×z“áÕ.­L6†IuêlÔÀk×èËỸWÿÍ|dp«\–€íxh¬¹"ºïÅ‹¿óüùóßàœwàùŠ(í±ó"ÍG0Á 2`³ñÅ!¬?Y«ilç  E™ø*(,ˆ”°áž1…=›dÍ€¥jŸd¾ÊO'Àº²z»Ã9ÂàU½g­xxy û”N/L3;àDÉò8Ÿð2¿à1ïyÏ{r\ÿ©O­POk7Xw]²‹#ÆŒn"ýd2µÉ'˜òê ö{d1'Ò4Z`6 'œLªé‰&œ!äÆúcmò í¬_ý+Îà9†Ž>0:{¶ˆFmPÃ@ÉN`wHÄñ]éOø¢yžwöí7ѯˆqý×ýŒAk\ÙAÙjªP/åAAABÊ!`YÙ, a–ŽÔÀPL”ý€ÃÔ>å¸?Ìf@’M© CÄÄ L6ÄÑGª9¯Ÿb©j¦F£þYM(KÌ/ÆU„e€ÁÃX±¢L•¬ƒêWR9¡’bªPÆvÀ˜ ñpúïÀö݆î¾À¿{ØÃvWæ—&<ô¡=[ àü%ª4õl8Þ|r‡çš² ¡èµDÖNCt¦ƒFif£~—?Ø;kº_ð= }\Ý—pæ¥í³X×* ]5+³fBHwH°â,€‡øBÏÿ­ßú­Ï½ùæ›ñ¶·½ !„3Œhé(©svÔ¡'êÂ?íªmŠh§1KW°zíÍ„ ;ÿ€‹Ã Í+ª2Ùä¨Nº60‡°„Stx¦ÅÊ^&aéK¨™×Jý9ì ÃnðeåÏû¼Ï;ã0pŒ§Ýê)H1µ@aïfÚQ&kôú¦ òKùËùÁý]@5À¨M:Y%ÔH`Q·5@ºw;ôA¡=Ou…Sçý/¢‡¢YÅ£~KJ W(ø¤Êé3åTVY€Õ•‡:a‘rT4Ûå’qí"ó4#e¿LppÎ_0ï¡:Q  v@R‰:Ä1)ò3­T5CXAê=øÊú¥¥Ù1¿µˆ£‹6¸™€yÐDWò!^QÅv AI»¹®xd•_Vh„b&ÉÉáªÚKjƒ %D“«œÜ‰f÷²Ê‡aü¡ú VhãhÔ²øC«Õœ' Šèm|#‡øó´[Ý«˜C©/¥– СÂ,Œ­ €øTÕÃgž hjÊeÜŠj󚕚3FULX ʃs½°9x‘ AÄi©`Q0€¨ ~Ãzع X(ç%ˆ=¨íÞOŒ}éDaðv[¿ ´¢E=SÈ-(Pz“’”1¹R¾ülà=‚€ÝßTÒ¦ÜëjÙ7¯zAyrгU\XPÀ‡pVÛ М‰*¸Áèô«ßù…Ö>2¤ƒGGËÕ:d²{³0ú¼ô $˜jK¨uXñ%Õ…I»U ð‡‘ (ÄÎq¾‚ZXU~GñÀ3öú#gçN4û‰¸†iì:%4çlÒSÎü FÃâŒh™Åi†@–ÿ1D¬Lii‹W°ŽŒR7Ùê±~õ²Áþ¾“uÜG D€ry¡ö”õY³ €øT¬`&«k{Å+^Q"Â7}Ó7Õßo½õVÀK^ò’ú­¨Ån°,þ¯žõ°ˆ‹ƒV8“mugM ÕÓ÷_UC=( ¤2‘´4Tqæ,ÂG† RHäÍ—®gâV»Ñûïpüîó<ð&ï=ÉñöˆÖãƒ7œ­ú}è¬ënZ¸GÞ³/À’Â9'X/ªS5ª+ø ª¯ÃBГRÆ´6*Æ ·0˜úÜ &¥ó5Faãøsð5_ó5PÕ¿ àÏÚÿ¿œˆþ%€»Ï<–ˆþqáýûaa­)WÒѯª¨É±/«RÌH]íãcD#„D.ù€l ‚E¥îÈ)äœ:®y[ñÑ’E bÈyZ¢ˆj>ÀcêV·KQOôð!ž”¢êqþ¢-+ÌëÚJ§1'àˆ-„s(8z:‹ßD.0…­ìßP’WÕWx§ûŒ¨êëRJ_hfàAªr®‹ûÍ,éVâ•Ô!yh*¼7нk& ¨ö2Á¦î}R-}\Žš-…-y4QfÅPüAÚÀ!Ï'¬Ú@W“:«¬êddûÔÏpÉ”ÂÂæ¥ÙÀ #()aNaqœÆðp«/ð0Ÿà>@DÿÀãÝg^àEžkß_UÇ'±VÂæÂ ËÈ È]ÅîÙìu±ïÎþG6–ò-N_ì&¤çø8 (® qg8@ ˆ Íõƒâ€w`(fÌád“…%ÎÀX° S˜±áŠÀ$l%¹Á›­ÑI„&6Â(  °ž¨‹ìŽ`\êW¿RŸ1UÖ†ã×¶7Rñ …±­¶A„VàT ¥t¼ò~ñŽ|døß'Oön³1hª}Ö}àÓÁå `3“ù;ƒ}# fm¡cÅ *.Î` ©äÒÚy ª€SAE ³ƒˆEÜ|¡ÕG÷äöâüh‚@E“Œ‘LФGV“2æ4®"\"Zÿ`ùþ{c°ÎÁk“Lñë²u$`Hý³O]¼Ï)´sˆ“¦ŠøÐ–‡”;rŸu,I$ÖUÕ¾† ,8• ¹í!BÆ´óàwhóàDi8ÒK¿gŒ.¶ú¥æÚ÷§T¹û]ÁкúÙ“BÑ’?ä´IžüìDJ U[ýi%¤´’qBM ùsÈ;¢VǰH& “O{RÀºpµƒÍ•u™¶Å¥]„eÄ´ñ-D ½MÀUK­I=ÌÉnd‹QàßKÌÞU'RWs†©#‡’±„‰H˜)`¢F>­ƒfz†!`FÅ’²eàÔ5'×&¿Ôk²’é,ð˜ñìêÑ“`0 §­È:•Œ 6¥Îg Ó"´XVW/´¢mj;`Ú% Œn­“3-ù)Õ£‰ôŸph`ý¤ K±íšTbŠ™³M„ÿÛ›¤ˆ!´LðŒ‹Cé$¸PÙJ”µñà†ëkG R%¤…Ѐ—â¨o6Þn·rppÀóËÖA­û ØÒV° u€uª rÿ~ICuŒ¦Îa/Å£Fã²».s£’]’7h@éß´Ÿ/Pù€ì‰(Fè#ÏB!Ü@©€#U}Ùv»½À÷¿Àg¥”þÇ™Bû¤Fsð‚‚5ªtšÑØjºJ÷:¦¢æ¶‘Oér5‚ˆTA&6µ,&låúEK”› ,ޏZ¢½4ͻ֘`%Þ3… ˆV3ቨÜÀ³Æ³hfD”‡ Vpîܹ‹!„Wxxïü,3ÿ Ÿ© pà†¯ÖéX8®/yúö\_ódØeü&š‘Ã?@¡6² 1<¤i‡‰æÊ(V«®Ú}=Ã|‚!¹/èKÞ›£'4xˆ`y\á ¸G½@Qs#ààü*!ªÜ!€^Ø~)€Ç}úÓŸÖ”’o&üŸL"òø,M@£0©‹ÛµÒ³à äÃ>,Š7‹ ¨G´ù©N~µïƒ^*v}¢d(¡š ô…—E[±ËFòpô  áwÒ¾ª‡×8ÚAº>oÒ´€ ›«HªÚ„mûñTifÀt°ùYïzñ‹_<ò ÀO8¸"ÕÁmkŸ¢þ—mØ žI¥«fEö°±jî „Œ 7ë ˆ¢²¸ð÷ð:J1 PyŽe]€öÞ¼ ‡é4ìáàñ˜ÁŠ¿@n\U\h]´Ùä0T1Æà¥àѪú…à§ÎžH}âF F´XA¾ð³0süêÊ{†oqtƒ\!4QNçPR]ý%1tÄÛl†ÙÉ÷iHáP–ÖLT+VYÏÖ) =¿?WB›XÖbYí<ûBBQP5 ]/BTA®@öÆ©!’+¯”Ò à»Ý[¿zÿûßýèGqÅ4@©÷S¥fç=Ä3|<Ïß8¸¢´ºœJÜHUrÒÇÀ¡»kÎG ·pŸ ZXú¸È¡M¶Ý´ƒ§ ººb©k#«u7Ű¹ˆ÷†qèÆ„QžÜm¤S3ƒÊ™9ïW åŽj{B’+_€¥ûle)Q«ÌÔ`cõHòЊz†c J•7 HÝ…©B9ŒÈš úžsP#Šæú\ßÛÁoŠQÿ6„0óþz yçø…Dt(G#¸‰gêj,ª9’Á,)–€NŸ>; ÀýÍÜX=±0wiÍ–çÉÏŽÚœ 8:¯vÔíHÉ´¢l,] W킃€h‡‰SBq­D%•„:p -quƒ>¢´©qyÈý€:¢gay>WWDU½×$QuþJ¢°¨Ƶäµ8¼B¨W ò‘3 ‡I±± `ujrAaAdµð­Å÷°Ô˜_êϲÊýÓˆU%‹reqÚ&G ‰õ\i&©æ š0Ôf>µ† •‘S€AµøZ1€ ¹ã)¶‘lÕ–ÕÍÈô9RÝr®ùì(tDæå×¶üdmy$ðªiGj5Ï»tô(ÎUÇ®íðmZR¶è{ûxO½1ƒÑrõ¼ÊsÙúæN{RÅŒaTî!qie4·yU§ŽËD“ãHk2]AkLA¥Õ‹ïîÁ&oÈ9cq+ssJ}[Ýs|uM€ÝxUý–c–N}vpp)÷,_ZbO ‡óò–Ĺ˜>TŽ8¼¡o;S¨cÙ YÓ‰Á9¬”rÎ'Tk ûŸJ!Lklມh }kØF½z¯µ”LÇÒ¾Ómä:¢Òeú èq{ˆ!„‰ÜœÌ¼q5ŸIDxÿûßïR­¼šŒí3Q†rß>v¾ô’~d_\„#‡¶,àD’í;¥:É%­\…z’ -sgðG´³>„;„¹˜–.$SL#Èù'‡Ò^F*2WÙºÕ ¢­þЄ¦ƒsK×’Ò‡¥þ¿?ìz j|Ëfñ]YOé,àÝï~7¼DD¾ße’nVÕÿh§¼Àó|ýç~îçvœ·‚p1·ó­_ºÞxJc¥L]RF*a ¨jb"&#ydPÒ.“C©QËÉÈÞ#}Ähô³žqH3MŽÂÎ(ç©rs¡BUp̬3i ¹ó¢¶Žç¡‡{«ý.‡+§R¹TÙÈ\ƒ`s_ÄML˜¬µMçŽÇåh€—¼ä%ðÚBýÚl6 àÑȽ‚³•ÛÈ~æš(HAß‚9j4Ð¥K;´ºÅ°eæÔvºHÊ­’Š\‰8Z¡g€bBj„AìÉ΋]ÔàÄŽ‘œ£VnæT?šVí±¯0b£¾³‡q}Oë†F®fÒ×%æ]qËu}¿€füb*ÏŠÇO‰úCNÇZÀm·ÝÖý½Ýno𿜻ùæ›à"€¯ð!;åËd·{0ÖÊèå÷»®R—ýó‰Ü¼ß›† þ⇸L_Cñ"§³÷æ#ï/]jüg=+×°ÑÌ"5 Zï…÷åeìJÊÖÚáTaa4! fÛ½01ù¦ þm“Þùˆí‘xIDAT(í5c)mó«z¤Ë4®æ¯üï¼Õ <ämo{Ûg¸À?ðXûÿâƒévõY-ïÔ¹z¿®BH[ª·¬ú,œÍ@ÍzÄÐ&¥˜Ö2qÈGp(^1‘Ô× ¸È„½`!U40Ôb’VX:¶–i|Œ:VÛ=P½‰`ý]Wß;ÁqÿZ÷h¸J1IÅ,­`IXM]ÜÍ(àVwø È5€p'€øaßà_9\ŸkçëBÓ*]¸*+“ß.ªeÇˬ<„ŠêY%]+WÍ‚˜L˜@aC!’М™Âµ#¹^y*·]åµ o´·LO'î?µínà|€Pbxc8y¯4Ç„Ëv…E¶â=˜;$ðòÂÀ…PU¨ê¨ê·ªê›ìo¨ê Sþ/þÞßøÆ_Q½´?ï•þÞ(’Nºo]&Ñho¿ÆKSèôí~i,b¥}çõ æSãåXæFÖ2Œ =u¥å{Måw‡Ü3 °ÿÖuO»4v]¼JϾZÂÝT¨8ÝTz"§Ï½{ 6haàdÀS4'“WvÊcBÕ%Þ÷P|ŽDö¤¦Æ(Ãê÷=Š& s5 oko~[ج¢ÔÕO]‘l¦¤ÓÊü7MY°±Ìh€5$𪶈 `r‰>è³YÐ:ZºX\(¨ˆ”ó†Åqã!‰”,à#"¸Â½cͬ*!µâðÊD Ž*ܱè]Øu±rx±H@›XÑÌúeçKô­rx4âÔ4 £E´æUiÈÊt\uЦ–Z~[™´VéàëºCÿ<°“A©€Ò¢EÕ°›"¢ê”vWÖñŽ Ò¥Š=A”\á A{SAêZâôãÁ]Äõ@$täYO¤ñRpÝÔf“˸ª¹€µÅ®Z‡VI2ZwO®\€>aÖ%Žë7P!} SÿÅ‘ÔJ"YZ$Ë< ]ù‚Ô·‘)Å.•…ävé£H©c0ùÏw+|˜üq½À•¹,­Õ JØ·Â2¿ÛNà™L¾Ã÷k>}%,”Tl0‹êàÇÒÅDˆ˜JöÏØG‚\ØYø„IÛªNNTF¶q0ЊZé†QÒŠ™J5ö.`NÏC¤N­÷&µamƒÏý³ò¢[Ê2,)öàÆk/¬}hODˆ1†±µ_) Àhv{Ý™¢Õ. E=k^¯kÜü²'c)-ö|Öˆƒ”‘N‰új q,öw¹„E‹uÚˆŽºÆÔ£]¶’—¤MŒ)e`hUëÌæZ;Û.Úú ' È©8":àÕ)¥¿ ?þã?~å ²iÖ<m6x mŠ]VÖ[¬[™¾êMÓhõèÍX󧕺ª iæ’b-~DT·ÙV°Ý³uHŸ£kuØû‹Pp5]÷™ºmpdtà 7àAzÐ]¾¹üàwÜqÇ•ñ<#˜"è¥p -«oØwºKfµ.]×p«žAÙ-Ër º¿Š>:ÚDÉøh%k‹¦äiÑœÚAºXúcÉ|påïÁX_ø:”Åy`jÝnŸòáü±ªú‹k]Ýn¿ýö³Òº\*£ÖVè>Ð\2—6<*B¡Þ%3i€¿Ê°ÌZj†2Äüûü"ŸgèÍP3ìË×=&àÛݳ‡„ Ò×<z&øðolZ9ò"}[ýîÿ{LM›·©ê/>ûÙÏÆýîw? >ðPU|ò“ŸÄ7Þˆ3¬ Ò¾.ð’€Òz3Åú†‡~U‹ÓÉí’-JØi€X—,qkЏê“LÞëDRK8éý„>"èŠF}¨çýF×ÃiYOPÄ2 ;¥€ÆXÖ19ÙxÓ›Þ?ö±}€Ã;î¸ã¦g=ëYøÐ‡>„iš®D»x­êX=’µR+Ã÷%5¬{&9ÄN ¶3­VeX²ˆÉ&¿œÛO1¸œ/푸ªvW&¡â÷¤`¥–í£^pRéYìEžÐ5Ì> dîoð¹Ž\ðšò÷ 7Ü€n¸áÊ „!Žé€ŒÞ(ÖûÇTïß©ÙL{kZ ©t4Ô9~ÙL°«…¿k+Ûi€Õ^ 4Qß²{ÃZßyÔS¹Ù5·àUuUì$TÇW2e`¸·ñÅUÙ/ à-ýYì6»¦Îäûõ;gϯO©Þ_šlo<c§„dÌA_Yœj£Ä€„À¬)“pKʹ㈠û¼0ª²¤@Á|ümUÆÖvÕ=L q™ÀXJhĄɊ3íǨð Gq?¬W“Ú7ˆÌUºd tv³µ]m¨¯.áyŒÞŽå Õ߉ÛAc«;vÌmƒÅÜ@±át‚ʵ6vœ 5©jyy)CSÛâ6ÕŽuw²Ê=È\„Äì&²ÈNVAìø€VÑd)r†ÖmñN‚‚O_1(xMHè”wUT0í)­œZ-9uΤÿÙLËåF:Þ;BÖ‰ÜcÃÉÑÖA'§ÇOíw{ÃÀÓòÏD|Ùu6¡¦qƒI¼;.u¥[AHR F[ Ø…¹ÃÊà òfÊ;)(Dsq 6PPÒñ‰á(cè(d¥Ó(“V~ãôµgÔÚ!Ý+²`'¾ê‹*ÎÊp³ è¡ÔÉ?àGa×…—“ ªíâ_úÒ—v¸ñÓŸþôEkø½èEûÛÅÓ2¦eÏèõÛ²¡µ„);„­Xte®¤9ÆO•ûÛg }ÄPÃF ÚAÁ>[™ßïB~cŠºk)å¶²cC‹Êið4³ÒÛ·¯éBE]4Àñ‹‚†fÚ‹Ú ±0šO^J< À5¯}ík_ÿ¥_ú¥@îüçßüæ7ÿ 2÷/x;ý„}æë<Ĩa¿¼PÜÔ×4Ž "ïÛÕ&MÝòÊvÑ4„¹x÷Õ_7ûÎàÇý“êjŽˆêÕüZf²äâËþÆjݺÆL^ëq<°‰úVNÓDC¹ ÚBó-ò/qâLpÉ&@s5RgqOgÀ»ü xÆ3žÏðT8::úv?à~î37ÆÿÁCúÐ_^ç\a±];¹>žF¤‹¼AÃë×ì§ÚªžAÆû[ÎJßÏ `\²¬®‰ßHbÌ—€©T¨!‰ãýq¯H]Û4øñ°kšQzT°F ;e:øw\8ýÙpíã/\¸ žOD?êbÉ»æyþÇ·ß~û-fnÔ”>þ;ÌRÛ± æõ¥3Ix‘°IN9ʸú•q,ŽuÂì>'ðdÒ ç00GC@£›Ï’™Ç; –<⎎­@Ý}#IèúvUÈÜó˜´UBíKê Ø? øQÛËÝvx­1æÐ!m ¸;Q@™Ýø4€/ð fþ=™TõNgó¿Í~¾À[ºŒb·»†Ž6 n÷ȱ2ÈÇ预0¬ï¤\7GN¶²3ðÓV|²Õ,JY”1«k@eÚ£œ[0qýÜTó><¹=­«NrÜE¸äNYIe²’r­ðéø‡J.6Á¢ãˆT|³¼~3míò&ûMÀé}€¿b*ÿéDô†=À‡EäOø‰÷¾÷½¸é¦›nAn!ÿ\ç¼Í®ñÂ`Pu4âîÝF’=¡NqWâY5-Õ0#tÙ¾¢Æ‹ãWB9îçºú“+:IÊÝa­ªÿ‘´‘)QíÐMcV¯n‹³ÂìÒ¾´WxçUµ/š¡!ÙTÞ-»‚ìØôÔ&à?"yü„ˆ\ø®ïú® ¾êo|#üWo~Ô£[í¿BDßFD/ðÃû FT·gÚyqײ‹m×¶:‹c$2N¶z“†¼jk†ÍÖ·¢’úìêõs_ý¦af' -Ÿ[¯7ai (êR¹}§s = GŠ—îÃFüÜÚä ø?õMH¶a´íF pÒî8--œïð-ßò-PUÜzë­Ýûåw9‘‹«ôð¡ Œ÷ÄiO‚g¶®v±•ˆ„®áaÒP+†JÂg§Ç°5Ä/,Ûõ¼•zñŽuÂź«¶ EÊ,\¡hŽâ#¨îÃ#® vŸ Vëf¢)…1ÆùŽ_°h}×´b] ÖøY¤˜ÈÖ-iòc™p,S‰—N`Ò«Ì ¶ªÐ²’’…l%ñ„ ]!€ìŒ/ï{z×é4ÔH ;y€š€¦ú…q,e±ƼZý$ ®¾(j‰-\œ5 åæŽCÐ UѺ™wû¹&S¾KjÆÍÊÊÖ¡Å”‰pƒ˜Ëæ—ð”õ ‘'èé*:UÀ‡œ%¥[$žiTþCVÍ™©ý{mp”šjôLžæð‘#z óàl5T˜­ý#i53„ lôt=ˆWÙN t¡·‡}†q©¤ [´ÈU[  zñÆÒ0¢«­VêÊ¿uxª–Z>ÎٽƵ¦6[Ú·xíìø~Tí†lVŒ(â ;*yn/]´ BЯÉÖŠp7ö"0uD×q‚O±`Cx8\£ø4% àE:øô@ГÂÊ*åî&»<õ„¨m’„Ac´L`ádDZx÷͉TÏ ’<ù5›q֡˜ÑüYJxÈ«yx_C ]R¨gôŽð´ ^¾ÏhÕ(`E xÍÔ„´1k( ÇܯºßÿÐýPçdz[󣇿ÏóÅž¶é%ôÃÞ½nÔ­òv1]å÷ "^mñß“Pȱ‹¨ƒf›Õê›×ÓžpÚ‚Õý&`É›ô÷<&²Wqg Ãy€û?÷¹Ïý·ž„¼SÜ{Î,è z{ Ò%ßg T‰ÑÕšìCÞöûÒ¯Ü{µ&}ÆÉßš#¸µ•¬+q¸:P…H3©} ˜CÖ¬÷’»«®$݇‚#áE÷ð љʖdÒ=©ònü×A}ZúAà}†í<‘ˆþ)€íRÂz¯¸0xY38¸þ7]_ÒdL._A†ÝFÀVÇq,±b#PRÀGUõÛüϳc-ŸE víðñaû8ø¶­nž–¦]f}Ð ãÂéË6€/ð ¯zÕ«ÊÛ÷ðÒŸÿùŸr›ØÛ<ÿ™Ï|æ‰É A¬v»óçÞ=Æð…É»s!Þ®L°ƒ‚ ‡p–ÌÊ™=Z5ÅÉcWÌ"‹rZûïÛOØïfÒõú®&µ2ë§_ùªK¿Êó&R—UDïøc>]·è}aàp£ˆ/ðö¿¿àîs: ·“LÌÐ!UZ·éPÄeû˜Ñ‹/y€dûA&\Ô .ê„ݰv¡tÍZJIJ™À C¯t %ô¾G]J¯P4•H¥k%teq—tân[\UÎ  ÎhÚ§nríH+ÉXMI¹‹V ;äò{ø˜¥Gø r›øòz!• $þ‚lwg¯+Ìܳò|& :¸ºªy·™ZÙóŽöåqÚ›ŠÆÊ½¬¹94ä-}öð~.µŸC5wIðhaŸ¢®æ6 4¥îÈNáeh€üÁŸ÷/#ÓÆŸàFfÞØ©êù7¼á ð&>Ø|Àìr$ÇFÄ“)û ªýä–]DK d6í²µ•]hâÐ)“> c—23xg5ºÂ•?xÊÙèƒt £€Ô[ZÏR‚–|†E*Y鞀#Œz­Ú«4%èåà/xÁ à+‘ËÅžsýõ׿ú“Ÿü¤"ï;û›"òoíXÁN4Es}üNŽSĆbktPjaæÂáü%o_lÜìúýÐ,Ç–ç/çŒÌ¢25â¢L˜jécrÈìÌ„Ó ”Ÿ'^…”eÏäy˜X\ÚwíüÊv«¾ÏøÂ®!êÞ0—I {ÚÓžÿÀüÐ-·Ü¢Ÿó9Ÿ/¼é¦›àÐöhJO UêH¡ 냦Ž_=ôàèjü”;8¡y÷#í¬cü:, Ô.³–®¤.Ñ$-»¸àò)­ªõž<ªøu4rá®iƒ®Æ™€9uÇR N©~îç~î²1f•Õz -#ONÑ“I« ôU@E ’$[]½/Ìb±ú¿YW²‚h,Ü.bÑfÎrïavåæëBÐßà h–üÉ*ê7vT´^q€å„+ä*ABìT•0œ¼:A¾T‹‰+ùӫ׺‹5ZØìÔ çîK P-ñabY¡ê€•Y‰Z½¡ïXª–1LýL×V÷‰9Óe¬ï'_‡ñ¡AKÙ´vš1>k€e:ðjåÐ9KœÌ MŠyfgá䟚R~Án&¤ì”BîûSÎÓ”÷á›g@bî¡)¯øDÀ–©‚@I€”2çïb»™° ÄŒy&HÊ6SSþV`;3v3aŒ4Sþ^QH"çóæD˜‰P´«Š¢F)·­âD ’ÓÖ)’" R…’äâhbû¿@%o«VÉ£6žsfË8Hî@žK×I´a=’°Ü:ô* ÀùŸç›¶ïÿí÷©òI 3bÈ+sŽI·°'Ì€0 >“òöø¦é0¼7P.Ù¦)W )Y±á„CÞÔü…²Õ+wݽsdp1Mئˆn¶zß‘ÜNPìRÀ]ó&k›Ð¶¶(áñ" .Ê„;wG8NÙÁ,5½'l1!aÆ…t€»Žù¾II8ðï—mò~-î0Ñ ã8e>¢u­b‹+uŠª&Å< »ùáâD¸¢àwmƒ¨²!i9÷øw}ü6ò)ù½? Õßï§Ÿ°»pŠ4®Þ£ÃºŠÜÓןÆx1ó!€Çáʼ†Ü)åJ¼žDD×Ý FÎ},JëÂ5—š¿{,÷ôø†oøÀë_ÿú3¿öY ùÿK×RUüÑëÿßÿÑü‘\ñ×£ýhLÓ˜ùš’Jfæëùñ|=ïÉO~2bŒáÚk¯¥c`棆è¤nžf>`æ#¿5ʽï}ïú¡'>ñ‰kßoºÄ&vÞ5e'uÛU=>øÁ^¤ÎËv,!„ 3Åã)®ý‡‡‡üð‡?¼^ûk¿ökÇkßçÚk¯¥›nºéÔ÷}w^WÅØ ýùfK.}-€MŒñ›çyNªŠk¯½–Ο?ÿÓ^àñÈKÞà ûϩêßG.€ø>ä2¨oðÃ!$'>ÿSžòѽ<êúë¯ÿ5?q!„‹ÞºÂoy-€¨êwŸ¤ªŸô¤'Á„›Ü1hµOÑÛm’¿ÄBÚ#ÿWùD„yž¿À¿Ž1~Ào©êC|ò†Ôרê‘MÒx$ð«.ªêÞû|Ík^¬Ðñ¶išŽJ¡Nœç™Ù?Ì´Íoˆ›Í†/5oûÛUõ;|ïññ1¦iÊÛC«F͘îÑñ@-<àÝc|7€ëOºö;ÞñŽ{øf"úÞë®»ŽbŒ Üu×]ѾãÈ„ïM~ÅÆ+ž5„5£€ûxÖ<Ï·јºþ€šzý˜­žï#¢ŸRÕ'øn?."Û}çyc+ð«·Ûíc¶Ûí#\à9Ûí6x$€ ÷?|*3ÿ$€ïßn·¯ðúK˜Çûø€¯¿páÂCæy¾Ù|çªjðÈ·¼å-žàáùÈG>KU¿ržçï0mwÒµoð)U}éwÞyßyžŸ ŠÈsTõÀWÕ‡Ùüruï¿ðÅœÅëÿ6Äœ&!ÿ”IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showpq.png0000644000175000017500000001032014507760372022437 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 9Ä­E†]IDATxÚí}|Tՙǿw’L¯Ö@¡¸A@’ðb‘­€µÖj»+ö³+KÝ ÔOUdEËJ07Á¨ÚªmÕ†­Ú‹¶ý´ÚnݺR+­«¥@`SÞÖpQ0!“™»<çÎܹs'™™Ì—äü>Ÿùpg†;™9Ïs~ç÷<çœç€†ÆõpÍMPÞ~l@Û;–#[aß"øÆ2¨èÑÞ®íˆЯÞïð-¾Ó÷´ßZ¢ÍˆfUKÛÌús,¸¾ ¬ó ¹Bšz 8ñ>ð½|»ŽjèÁ,P%d®ë­¾ÀlÅe“aëh× Ð»XÀÙ€EàÑ ¬}Žhèy,`óì×ú‘ Ê ˜%UP1¶ýÚ4ô,ƒŠc°8 àlàràeà¯Þ·Ö÷4Â!ÍEŽ× £Z./Q}“Tx0FYûýø[‚ÀtàkU0t"lÝ*ÿM3@±â+ЧþÛfÀŽ÷÷/;‘ñÂ…@SÖ4ÀAÍEˆ­ÐQà³6 ŒNWï*óLÑ»Œ`ÁUðÉÉð—-pL3@q²À^`Àpà¦$ xP1ÂvoF8 ü êƒÿÕ P\,Ð\ð‘‹œLÎG‡â¡¨Ž(F˜Û¶ÊÇi(Ø£ Spâ°Ø‚Œ#.´ðŒu ¢342 TBÈ€ÏÙ,ðIàŒ.îëLHÎ%À$ n¨†ÑSaÇfø@3@â&(o-0%nN³!+FxÛBü¸kìÖ P`xÂÕ"ä.‘óÃS`'úã*$«xЃ€¯WÄÉмE|F3@¡àj„]üM¦,àÄàÀkˆÊt!bÀsÔ6&M>jÈ)Z ^þâýö~`Áp¸¹T›Éœ¡DA®Ñ¡BÄ—¼áQ`ÍxèÛêí‚vîÎ,›±`©ýäâ<¬DÝöö‹õÀî½ : Ìž`}µR¨?pG{×eø·¼ßþËš`G2½Ô]å„G{‚ñÃØˆZ2paŽö}àßHºúøÏ,_¿ïì3ò ÍXß„¶=¥÷[p›Ý–eÀ9x¿¾4'ÿ°d8LïÊøyÌùÀ3®–Ž…š}ENýCûö±{ÿ•> ¼×€÷xÇ:`ÍilNÍõ`5êºtÜ,(f0`©¥ŒfúÃ0l~ã-ðBÀ㥰걄MI©$—½ÿKÀsŽ"˜wn.Fã«úû€Ó@6ƒ\›å¿±x>¹À{^ ¼½™~~iŽ{ÿ‰$ò0» ÙƘåƒÀkö~û –7É:‘n%W½ÿ*àçI¾Æ öWÅd|5¸5Y5øZ>÷¢Ü^Ås=à~`U#<å-üÓG ‡½¿&öt²ƒ.:Ê­³¨²’§ÀÕ8f*»Ûû;”Ñ×"³y.ã1`EœÛOfËø9ÌË‘UÏ 3•ïE;ý80Qè·Ì¾îNÚ×x¿Æs?Xx< 5Ã{~üŽ\õºU±ËþÀdd1ÒÄ–¸[u`þÌ Ýøÿ ‹,È2OûîEÒ‡Ið=€[üÞ0šƒ! î2gcÁEÊï àç<I¨<°ÜéÎUiÞÿð4Ðàmü×YpE.v çÀ¬•ñ½ßÙ\ç «Û¢¸Ì…lüÅ0– Ó¾'€_x«û}ÀÂF¸ QÖ{æÊ™}ûç©6rŒýîæšë$Ð  ® ·“fÚ7¤„ÝZ%ô\;‚?0`E…¯Â@óÅùH…½¥ªÙÜø%R>¡°“Cé¦}m÷ž$ÛÇ: ö Ù –ø(ë.ë¢Øó “DSíP}…Dî>S€p )¦}÷(eï1Æ[<†ë¥ i¾õŒoc¿Cù÷0YÁæôós…dùBa‹ìçp¤=Þ:oã¿fÁEë`~!ßG0g«èHa]¯»P‰Ä(î/¤äPWiß.Þn æ7ÂŒ&Y°[Hßq05…[‚¸¦Æq]!4ÒÕ’´¸É~>©–‚À;¬ÞÄ&Øk—'0gÄß©ô~UÄo­´î‚µòÝHƒ`>®´¯¥zúýj¬oKx`Ô:XûÙ³Q¨9ì{@|fP2ÇùÂ`h½µ@Ä ÙªRà!5ÖIx€±°´”Èrh^€ìNr¨ûL¦IžÂ¡‘Z¡ô\¨9§Ðo6Ž]¶åxwg^¶à¶lTí(f¨“Miõ~'æ¹’Cµyl£¸ô´‡ñwY0|¦ØŒŸe¨¯F•T|Ú™3Àd}M×A}e®g‘gº,ÉÛ‡ ¸a8LP¯(‘Å0+Rë¶åH=‹îàd«C49t/Ž|.`Á­Ãd«—À½=áШ,i€úJˆlŽ}Þ,5þwÿk^äR0_ÌEÃ,†3#RXÁ>A4bÁ“†¬Èy›‚, 3fü`z¿™îäÐ}ðÓœìhŽHíGÛø/Y0¥ ®ëIÆÏ’˜“Q¥ÒÓ‘Ôo6tG¡e¡ßâHûîT¼9MŽÙ*íñXëý~ì‹™‚«ïj¸¯ŸŸR_4`õp8¿˜^4@ýyiŽ9Ò…îDN–° ) í 7ÍzŸÛÅ¢ › ©}F®½,â\T-FGl~÷™>¾D=‚Jôu=ú#Ó—=ú¹î©PŸt|~±‡æxàïâ©ÚOfž‡¬¢³#„L`I§.S¿­Ôq]âx<žç«ZJX4'aë0²BÜ~„×Vž€U±F+õ±÷ÛŠÌÂo·_ø*\û4<ý¦£w)¾Ú‡¶–¥y_™t:©þmGöŒ¶¥ã6ÖêÑ`=s€iÈ~c’m¨žÞçØô ’r,Ëc/ΗãÕðÒÙms:’F¤^·èâ¨û à⇉–Á+þÞ2û¬Ï9‰l(;oƒÿz §Ž)SÚãTdKI¶ŒgÐcÌs€kbÏ«ˆßæå7f¹´Æ9Ë LW;KŽ²Î ”IÃÕÄ´C q«¾s‚ Ñ…Æò| ,¸\Û9H9½È¦ÒläV‚ðΘLEÕEÊ1"À#ÄÊ%„ß…†+áP[/4tÄ%[‘*2í>DaGñ«ù«â@f jK™Ápý<¸ûAWèçËpÑUh=Ô]Á"î::v]àW:3)xÜÉnÇ€1`¾“Âovçì<€‘äÚyo º)Ùùz¸‹<@¡%‚:VÆŒïW5œL’Cö“*7ñõ.n²ð¬½Ð;‘¢7›#Ç,Ü$à”nüÙÙÙî> Y´Åb0Çj³fŸþ5Öûnôþ0°)‚r )>9'Óy©9ȉ-aû÷¬Å¿Jm=2iÐUï®B‰òXï¿*ƒˆd3²uâ¸Çûƒ• œ@f¹©‰[Œ,[Ë6jóvZ{ö=Dý’õë›FߢÔzK'‘É Õ‹7«ÿ3„ôRãÃÂèÑ¡}2Ì^-mân9€yðDl¨˜Hjõ0ÂʘÉ›ö¿N©“ð† gO'µ•Åv”-¨1Œ=°q»6q÷Dàí1 Ägà’å$¶ßC6L¹ËýX;=nÚ¦,î@»¢ô‡€“Ú1xS‘Ôwôo­³¯6qÆ `~ãâóI¾Å;‚ì”Û D^›‡‘›!òs0$¾g^ ³_RbÀ¥+z™85‰t ¨H°Å~a Ç`ã&mæÌà¶Ø`ŸLù;{ü/ð¨ƒÑ Æ|0+¡v:“ÍWÁ¼BÆo½è€bƒïÿ™$”OüCÖJ¸{ˆ6sÚ`ž.1µ³awbø„ wÛ•á'‹áÓY½b6ƒ¹YV—èU ETD6f»ëf_ê|2B+µ™Óg€Û‰[oý–¢Ø¤†ß¡ ?)}Ã'8Â;`šPq6·0£eU}P9ÄQGD·8åX=N›:åDÐ=§A»£ìí8Õû[:‡½>gõPû,Y_Mûc¢¿ÿ¼sX·Wq¢] ¯+ù0K%‡v9’Cá»/is§äíˉ[@pŠw?ðº;uPû3|_F½$¤Tæ³`ÎEŠ5ÎuŒ÷Híf»~óäœm¾õÁÐ&ït0O%a2åO^ÆoÂøJ¨}ŽÜ®¡·d 9IK6°kûM§ñmÝr?ú¬.5À2:_ßÕÆ—%&4Ÿ„ùáü~}[0–ŽFê3uVgx˜×h“'u€{?£’ ãÄðµÏ€)¬ŸQsÌåÐg·“|ç=ðp¹6»§œ\Š,'vb×Âøó¡öÇ…gx7V…ÚûÄ I¬Øö)8r£6{ jL\3ÚÞ"6É¿ŒÕ0îGÙ¥ysrè•¿ó³þý¾ºy`-'¶iñGǵù£ жTÿ-d»Õx¨}*ÿc|6cíoUÔ0 ©>ÕÚk´é£`Dö÷_'´Ùf\2e6ƒùOP: hs°6¿äpæ g÷Ô ñô²Þìæ‡ºt ¡@C;€†v íÚ4´hhÐР¡@C;€†v íÚ4´hhÐР¡@C;€†v íÚ4´hhÐ(>drjXR7¸L=JˆÕå·K°\×jêŽQRÖ‰ÖHe0Bv¹ôˆëÚ®•o×ÐÏJ½|íÉ$vè¡}ða9þVÙpܘ*,bǧµ:'µyÓw€þÈ.áD«ƒ< å˜åê{ÛhGJ’¨þÕèÄÊø{ôg®DŽL; 9Cg?IŽNëͰéü,â+Aúø÷ºX§#ç¢Á{¤Vt¸W:@ r6ëi=02°â†ÉáY<ÅæÎ!a zô§{g ça5îC*‡éH!EðGí( œØÍeòýCŽpдkÓfÇ’!àˆýK\×äy€è½ö0cÇút’°Ÿ‡ˆ?G/äºW#ü?בÑÙÿ‰“IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showqq.png0000644000175000017500000000737014507760372022453 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 9 ÆíF…IDATxÚí{tÕÇ?³y’ø$–G_‚U ˜ Š¢ˆZ±¶çÔþÑÚÖR‘G@|ÑZÔWÕÚ‚P+'$ˆíÑS«==­bÅj+¾%¨¨"(‘‡@²Ùé¿;°™ìf³3;³¹ßsöìÎÎìîìÜï|ïï÷»¿{q¨» ø¢/ÌŸ ­ùþ t“Çc4™ð×6˜Q £`å h×è!X{ªa 08ß„©Õ`Ž‚UùHC7y2¦Ãà(¬ŠcÞþ x°ù=´hÈsÃéá`|\†>ªk8¨ O1ˆ ôr8¤Ù€yûaþã°W+@ž¡öVÁñœêpHà¼"¸º ÊN‡ï­ùåDT à8 h²?|0ß„yõð¹V€<@ì­† à4 ÀàÄ Üx 0΀«ÂPQ 05RÇM¸(2 ÆUÀPE„æø£CpEú+÷±E ¸AKXÔ4Àv`Ð(WDìW~b"L˜†þ§Àê•ð…¶ˆIPQÿS†# 6Çm^ÖfòîƒÀc…pçBØ¢ XAKŽNGÝé– Ä¢P©öµÛâwÕQ¸: ƒÂÐØà÷Q+@†*P ü4Åg¶ÿVÑäÝmß ¼¼c¯íü ¸{¬Ó àO؆£1;”Ð/ÍÏ÷NÂȰâVE®ª†áÊkhÖ à3L‡c¢ðQ¦*‹]À«À›@$ywÔ€¿p{-| À?qýa883ˆEoàD¥ŸÆw 0Ì„+Ãpj5¼ßäXhÈ¥ l°Ú}801 ß»øO'Š<‚;j¡A+@ŽU  Ê 8ËRoeÝüÞ¥£Õ¹9Y†š0= £Â°®AÌ­¹ÀD8ºXl~¨nà²,ÿF‹R„×pÌE[fÀ-‹Ä±Ð à%VAkµ4þXKNB†‹³…b`HŒ"lIv¿L ÃY£`ÝŠ BÌZº©½`ƒ©Úýd`’‹¿·x]y™'Ë€ÛêÄŒÐ à… „Å<;›¶@gŠðu$9¡Xy ‘dE¨ Ãø0ll.J+€›˜å…r¡ËQÝÀd~ÛR„å8Î`yÍ„;êeR+€h„aÉ’%ä¦ Ø)ÂSØœ¬ƒ ˜†ñU°c¥MˆÙ· 0j ¨ ]Ëåü=ǥˑ•D˜°Ü€;ëàEß+@5| ’yB³"A™Ç׬Pg ¹ì[ÜG—†á[U°e%4…´ˆ»ƒ·søÛ½”U:ÆAâ [T] Å…º©ÜAeŽ~×DRÒþíPbĄژó¨8-ø–¦Œ†™A´*TÇk|<‹£ï·Ì„ëêá¿Ú Ì2¦Á·MxÞÚþ‘Ø0ža7ð2BdsǬfÕI.Š­Ý Ñ}µºÁz]ŠduxýH«.Çvôp3p×@¨›c›€¤ L‘ö>ÏÚëÁE ±Þí@-Ào"pß’4æ*jt!˜mu¥%¨Ù#¹1ðÚG á¶…IsT4\š7à˜·ÀÃõ5ºö=7Öò/L4¬žCæzeàid!¸‰.†}×+ËÞ&aß4ài~žË"4Ò„ ûþÀÚNöíÌÀ3á­˜U+=BN¡ &Ò ûîCr°_'y ÖAøE=*C¢½Sº,·ÖÂ[nËd8¹ìñSU¼'À4X`ÆdÚC¬CÇziî\ o ‘HT*à"R¯‚Ü^'ƒpéØ;!d47öR×Áz.HØ&f»+ˆr8ÐeªíhÌû±Ï6³G@y×Z'v’u{™,ñ²Lx£æ?)CñEÊ€+Lx´µ,bDÑæHÌëv%ŽÕ1ùA€I)ªsD4߉íÐø),yQ’n{ : 3ÊZÕs4ûj•°TÕ¹ ¯ Ù8}+­-þÏT”Ã…ÃáŒã`×ǹyçÊ©®³8 ©sØWí;ØYwâ»eâ*aUHUêI±ª´9éÁÈrh}‘ñx;"T¹°§Éçcò.uí½$–2’ªÜú˜]©Î•Š!8¦Æ÷`"´©KØ ÆϨ:W; xûèMÖoƒEKeUm3¼#ÆØ£486@Œ dTËR„1HÒæbÌpt)Œ ß­AS4xDˆª¿µ_ñ|·’ømJw!5ŠÛç$ÄâªseR—'‚ÄŽ—a?fÛMͰx)<×&DypMÌ„x@G'±€ˆÍ#šÍ“ñµo\7Z'ú32›‡V)"4Û_„µ&Ü?ž˜#‡‡l‚A‰%§»3êÐàf¶/ï íê\Ò½ð’³Y¼!Ââ9¶wó¾®íê\!¥ §#nÆv’–U?øî^YQ»õ"XõŠïÚ£ànu.kRÇ ØOË5acæ•ÀB¿Íèé îVç2€þÊk¨Pfô¾øýåÀ…˜X f%¬j̳®!%c†Cc¡¤õBù8§dYû«€Ò@E²/â). ÁeÕ«ßÌ"‚^Uç2ˆÑ)ˆÐ5ÕP0‚N„À ‘NÊAu.x_y ŸØò™¿5`A­}™­ÙB.ªsÅ*ÂW•×b>8_Õó=â$hX0c1PIÓ¡LE„ÜTçjBVëvP„ÀÃ!˜” #ÆT8ÊHPPbƒ I„ƒsp"‘ÅMÎD˜…‹“ÌŸ@EÛvP %·Å×#ëún´ßý90/óýª/·ûø¾W\‚ãÅQ|?š»"b)øõ*¨\ IG~ [_p pÛxlŽÃÉ'ÀÙ9°d;€w‘rKòî}&ü΄{üÞÿò®<œwé{´ÃßL5m»¸Ùc¯EÖ²MŒðx;Ì^"QeíºàŽˆÊо²|Ç9ýöfÕðîÒ2à†:Çeƒü‹@u¦$‡(?p´¿™¢(ã{Àì Ï fÀ€ˆåà4RÏ$í®÷2eÜõOusfŽ&@ú†×Ld%B¨ ‘xÀƒýàþ¹¤Zkdj©ÖiÖöHT,Øïû¸BXŒLDÝN!è —3îsv–¿?“ªÛšÞYþqº† ëËe»?3©º­ à]ßÿc#f¼'w6ªnkx¨8´Tk2ø“)²Yu[ÀL ˆIÿË4ìëFÕmMJ¨Ð•I"¨[U·5Ü7þFDá|kû¬.ž¬ÛU·5\Ff“AØ×«ªÛš.B…}hm§öõºê¶&€‹ˆÈai…}sUu[À%L{ïPš_gaß\VÝÖp é„}ýPu[ÀË¿( ×XÛ'öí¬(#WÝÖpÇò¿dm‹1ðüVu[À\g½°Â¾«ñgÕí|or§À!éÚ¨¶b_”Ñ”Ò2·Ôõ¼uÿòWBj1( +ì]>ßTÝÖ EÔÈÌ™F§óñcÕí|AÈ',œåÐø;M¸¦†ÕÃSºñóP&àY"¾(æí&<ô¢ŒÚHï®57¾ <‚[jů×ÈgPº>F"ªº­ (‘•¿¶™0Mõñ=¬ x ŸÓC–eÕÐèQ6€]y6ëa$<‡b>ãä®t¾â¶5GÏ©4›õH\’] ‹]F±zX%ÙË´…Ðòs^¯?±4›õܦ‘žD« UõÜK5z¨ß,Q×ê³J³µ’feŽ  I¾)'f6”8ˆ,#°‹æZ(GJòit›°¹ö/,Io% Sb\/8Ñ(VjÐWõýEº]Ñ®nœÕ´å£P”`÷0ƒ0ÖðkK0Ûóáv'rp °/ÓnW–Ý ÄÆ:Nn`ÞOÏå`PͳÑÉq‰¾»]Cw$ìïñžTø?Q€Z׆bnIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showpp.png0000644000175000017500000000753714507760372022456 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 9) ÐìIDATxÚíypUÕÇ?/ÉKa‘})‹R+XÖ KuTZ7ŠãÒM‡MAQi%7al+Ö"nXi­¶c;ííÔ±±­ÝÐ)ÕZœ¢d”M $!ïõs^Þ9çÝ—¼å¾5ç;sçåÞÜ÷ró~ßß9¿ó»¿ß÷‚E†P;&®¢À"ØÐ¯‹WK€vˆ¦•@hªÉô•ø¬1Ò §7pè4CÁ8Xû®Ú¾-P-vh?sÿEÐtèh˜aTÿÖŽù?÷?i|€àVp ,ò{ Ãûeê/ÇwZä5Ô­~ÐS=a=l-³ÈOïï, ïúW©'õƒ³÷[ä§÷/:‡÷§È×K€!Æ Áém _ëþ®ÀâðþÅ@_å÷3Õ“;Õ–ù…å@×ðî4ã×ý€KÕwCíhK€¼Àæ.À½áý†÷«£@Qh§›,ò ÷µîý!t&¨®g–%@nÏýå\Þ&‡ûh˜Š‘#JKrÈ uX tÓ ÜJÍâ2ðÝf ›Þß P¼ÿsÀÀÞwP¡ì7ÓÑ çà»èÑöÜïfŽYÆÁ·Ì §°µ ‚÷…÷‡ƒâxÿHc´®w-rg—½â÷~sÔÎдÆ 7æþŽÀáýÀà>§ å‚€3Ê û±P÷þI|Ô, 0´SlHÅZ›yæý¥ÀK´Üôéq·/N”çC.Ê?@ÝA;dgä¿-Ï[éÁgN#\>À6¯“C–ž`{ Òçð¡|n)Fi0ß ëpün´#À‘8J¥.G—L fD2ÍJKV§H»µ~?ð”4þ'æ €0j 8/@0Š+¯ý;8w"n2m‘‚£ÀÏíÀ›ˆž·äÐ#9¤ÞµLvúÑR¦m•J`ˆ%õ…sË3ìýW£ÉvLE‘q1 ÿci ¥áG€óÌkŽñï§ ¾ûdP`Œ¯ß‹0BHÑ´`¬šf$R*u1ºdZpE†õôWéÞ?Þ0üÓmž8 A„ÓPý˜Ì˜} ø—þûà¯rDxPWÏsŒäPóº4À,•êIì¥RZr¨4e(9T3[_WM–Þ@1üóM‡tÃ;<‰ÅÔ጑K_EŒï;”€±B!,óÁ™”&˜¥R3ˆývioŒüú]àd áTæþ29ì^t3üð}SÌq^Þ-Øp^çz(˜ ctù@’óiDB‘lJ^.ÔçþDJ¥f¡K¦±9ÍÞ?­ëð³(C½ï.ès TïJ¡áÝÆÝàÌ““ýãÀYà e| ]Ò4p¾’bì»]@)•*«—0®M—dšt´êÈ(_ÃaœUŒ„êgaASÕà,A³[À-2@O¼,•š‚!™¶-=zúÎ4ÉZ7ßB1ÔW?K²'W +†w#n0¸aY"ì›g¥R’icÛÓ1¶ºû|‹¥áwŠ ,[±´œgD2É7ø½ûÿ¸¹‹Çp ¨$¼(•º½zŒ©•L«l$#>ß=P1ªwd·á#ì€ê_‚3]ΧjÀØÎWy=ÌÃóR©ˆäP?´‚R¯yÿ1‘š-ÕOd×PŸþ&ÆÂá2ipV|ëyE Ü.õ²TÊ”L£*5zúµÊœUP>ª·Àòzò k‚³LŒUpaè¹ÍD—M7CÐÃR)·äÐ3¡Îˆüü¿ Âðùfôh#I]ƒ¤-僠’2íBâ¥RÑÉ´µo·ãkDhô€Î hå1^{¿š*T“C±ðÉZk¥îýcSt™zú_†š™Ö|%€3­Wy*©­03%Ó2÷°EK8K¥’EDrhønµ&Ìj®Edj$¦ÑÑ=ýÍ©ÖÓ·p…šóV*• DH¦õ—Úüé#€s5šBÁoÒ 1c4ºdZp8½¬)Ó7¥R—gà²M=}õš,RH€h¥RéFŒ[Í‹ÀaÍ™r¨ ’eòþ´äŸ(%Ož f†¾›„Ò×—tÓ"p#ÔNµ&M‚J±D ½º a:zr(°ô ö´ÔNEk웄Ð"H7íÑÉ £+6)É4K€¨TëÞ?!Á?wxAnuˆî³©!^LÄLÛœ¨dš%€ûºZiÎðþ÷ç]ÒûCP›~„è­ˆnzú'õnX«¹âôøJã¿ßƹïÉsŸBtÃÆ#›2½g?¸ œ kÞ¤ P;øRxÿJ„¨C[ø@ó»bðjŸÑÝrшñ8ð„€D[píŠ]cÍ›4Š÷—`4l¸àCDkÒsÆP¥„ç]Voº75œ$>Ù”]Hžèé·c8ãktï/mÃðÏ"š# _¥C¡À…\H¼ ÖÄ”äP14o°&N|pÂkêhÞÿ1¢äÜÕðÇÆw¨:ÕF°™@¬Ù¶Õ #;yK²zúùŽ(‰|ç2à:my­%\>F4ìu{ógq›ÍàœLàšd,¯Aí8Üܪ_k¨ ¶·™Æ(\žŽ]k)çß&—.AkîØG€ê°÷ûå—Œ~_žt3þgi“Bá"!ã› U6%ÔÔ ÀM6%B2m¢Tù´ˆµ£¹z¢åŒ4üŽV _2È;ÃGŒH‡”¦†dSF!ŠT[•-69óptb¼üÑí½²Á ä»°òDz.7ÔÔ°ýI8~°íQZ¡€ñ-D­B †ÀñE’!Ñ àŒnŒ\Ók8<<ÎñÌ\öÒD»Ð³àÌ–é1K3"[°V™^]³_.9ŠäÏEr¿@y-Pœ©@L«g»DŠ?þ¯7áÇe¬Y¾†~¾`lM^Ä5E‘_RÔ¸àŒÈÎ? š%VÆ+ ð$°[…j7Dãƒq|~¡\ûv¯ÅÊ–`=eÀåÚšŠiÑRŽ M2SÖ ·óIÒÆ°n$4ßârÎY¹ÎÛÎÑìÌÖîæ3¡N¾Ðî…u;`M4)ZŸœ;Êå–íqƒ_ne‘¹ÎÈøì†VL” °yµÁê³ÀV("°l6~DÀX%K¾Õ(rä29´>Ê+d<1!n”ËAc¢jâFIÿ(£bh©ç CH™!T‘žÿfXuÄÛëª:ãàërO!ŠùÀ ùeÅ:Ñù“rR©yè¯ *C÷žú±÷À;©žV?u 芔¹¿Y¤ØüŽ÷†ÏèˆÐˆ¸3õ¢0nCT´†‚¨zDæ2 wë‘Ø}ïdp [I€õýàÂ1`pî ó^Œz+D î]“Áb9Æã9säRý”Û’H!Àê⌌ókw·â)Gäæ—$è€H/–$ý§MrP/·s¸«IÇ’²P¾Ô&"ïCû%ü.¹·<@¼M“cýßZ Qn ç,'F"(lÅè¹Ye ^4gÛY…vKK K K K K K K K K K K K K K K K K K K K‹<@QÄ)&R ÁMA©…ß7@{Â< e€ú°‡ÖÔ‰dêó-b €ÑGµF'Nœ†’('Ñ' wÇ4H¨' kðs%„ÅÊr`Š‘ÔX „ÓòÕÊĵB€b /BT …8}ν¡;·?E,DŒrª8Šè‘·0<„Lky;ø÷#:g-$ •á²#™}P*@$œ°&wB(G+u&¹gÂd‚„…’NØClPQLX ¡Ù/`®ê‰ï©–qŽÅÊÚ_ÝLaU(±-¡µGÞÌpHÞFøí„|ãÿ&tyx¹aÒåIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showalternativeflags.png0000644000175000017500000000173414507760372025363 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ 0ÒíL¯tEXtCommentCreated with GIMPWDIDATxÚíÝÛrƒ @Qqøÿ_¦O™ØÄK$B@ÖžéC'F6‡bRJÆeV@@@@@@@ýKœ4„ðöÊqJ)¨îöW½¾Öè$dø¤ñχÎxíÙ)ýÿ$@ k_0w*h ¡a–ZjÚBHw’ •…3C@£ÿM´,òÃ÷4…B KÉHK7~é¡¡w¶ê¥–øsÂàI`J)ÔHö`@sü*ü/¯•“ˆ†’}M{šCמNµ^'[e7t0=Ükào•æÞ*ƒ¹Œ´’¸VGËò¯ ƒ†€¥è: ,™@½/v½'NÏ_ý4éª_¾ý{Š£6ö'Ÿ“|õ2똯¨8 dÇbš¦4B¥n%ƒÿ§[Ïߎßz¼}6éܫ˜öõ|G爣ô¨Oî{yÌÑñw‰,ó™ N¯í 5$;:GHiÒ¬‡Z&{ÇÆÆB@@€Ì9èsú[–ëì:À^EÜéAke|ÜçÕ×#÷‚œòÔ\Ý[»Ïܸõ½yÔÆ¿£¤[Çî#kCÈr£Ã]öÜmÞh¡œG»Š{•²õlÜÄò¢ž‘âõû17¬œ ?w`ÙûJ%d¿ žÏ‚Ÿ•IWŽ¥èÿ†ËëgMG:«¯¬ÝD Cxÿ9Ÿ@}'òÚµŽ®ßBbsýêq©öTnÙÏ|ñZŽ~§ðç×ê ­Îœº~/`kŒô:øMx$v¥ò†Äµh?÷V°+¿F–Ý:sïV·Ôxk3‘ã|à{9sõns€Þzkû}$¤g¯5kü²÷Só~s®5ìëáWæ=çQC=ÓØÿ‹ öÔƒ?m¨OV謀þX€ÒT5pCìÃ6†çìòmI ÜGýÄ_Ò»gýlÕE I ƒGëƒC€ € üÛ¹À>C h`A bk #p&¤ ÿ£o’j‹ € €€»ñ£«….Ëz-JIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showoriginalvisibilities.png0000644000175000017500000001374214507760372026256 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß  L,DoIDATxÚíyœŵǿÕ÷Î  ì"¢¬ŠQ¶¸BÄ —˜‡ Ä$Šq‰‰H\P˜šÁ ×à\¢ÊÃÝ #›,O@@@dß—fæNw½?ºgæÞ¹KWõÜø`ÿ>>s¹·«»ºÎ©Sçœ:ç„"Dˆ!B„"Dˆ!B„"Dˆ!B„âð„¨³'I:Ý€³S@ï×ÝÀ·À"`°É×~·¼£GF૜¼`ÙÝÌά‡ Hò€ÁÀàHÃÖeÀ¯©Ç¿Œpr¨q…åp™¥è±iq â€ðþFl°Dlž¶òsmvýq*$óÁ`ÉSÀ/†Ú[Ðdô™Ç¾–;‰YŠf¶T×þ´#Ü—»Ÿ¥e9¬Ž÷c€í¼e@EpÞpøWÐñÿ݉X¤£mÇë×Êýû‹^`Gn ^~ã¿Ô†§c¢áõƒÌA®­ÿ[ÇìÅ¢kF¥@p±¦ò°pò–”=€ t¾ók³ù(w{XÓ¢¸¸&£Q¬F0ZU×x½,EB°éggÑ4˳ÿZà§-žG²@Ÿ$ýØú»°hÅJÓÊÝ‹¸IWü+×8Ñ3#Óß!ËNÐîï©AÇÿŽLÐNóò&B°åÊs´¯×Á_ ¯¿9Õ—Vâ7ðÌ=×ü~ +c؟ÀÚ÷¬LÖ÷9Ø•iøâ×rÐ@Ç #?²=€ë ›å(ÁÚËûÐ2 ³ÿm ±A‹‹‘©'¥•v ‡˜¹ŠÏC²1ãíP_@+­Ù¯ø×Ëó«­›…d;‚!Íšª`Íq ôzÞ6Èø xà £ÚK˚׿`‘áìøÿÕúcÜ]C ª¶}(ª·š ÅȬq‚‹.ìï¯U.xfzÙ¤Þþ€…¤-0Ù°óý‘þN™J{…¾ß] ±•† ×* ¥¶ˆ.'¢ù”²hÇ[ÂÒ ª¤30Úà¾;€ñÚ ÞÙ¢‡)ä»Oµ·*•âãØÇ×_€»e¬ã (Ë¡aïÜèwÝ}ÇÒ)Ë1ôB¹Ž-?|dÆVüØsš¡+îGÐ!­]ˆÅH®2éÏ™WÐ8Ms]\0忬«áÀž «<(ÕЗ#6”æò4Ò×­Ú#½Z]U‚O5%é †~ÙÐWñcXmÆ/î ³7šdŒO‡}çJðž¶½,j`W Z A¥Åõõ¦aÄ/ÿ@Ò3ÃuRi…)®[€â-M†á=†¿0ý’_¯Cq,G2Öó²¥Ê¢B>Ln~úÏh…à$?sÌÇí6|“ášÏnšÐ{=QX^æÍçéÈ´9ŒjÏBÁ*ÍkONCüv`ì1¼2"’bðV!éÜ'ä¾DšÇÑ9Oƒ¶‚Uôö¬,FêÞÂ’–;ù·¯Ðd @#`‰Î–üÖD€ÖšöÝ¿p3µìÊó/¬æ‘y¤Ò;HÿwÕc€ªŽ<Œ 0 8ÇôÆ=ÓÍ€+Ëþ1“{É2”›vîw Íö&ˆóF(>K SŒŸê¯bl°„¾…$ÇVûÊ4‡q0$èE}Ei O›Ö‹ ÒÞöN#k5îaš%³É™Hþ‚äIt“IöOZ€a=´»Ù¼Z’Ù˜ïPö÷s÷“5@÷!\n¢0*Å£µÑ”¿hº'¥Bw3Òu½ 2¸Äáõ8æÛ¢Ù¦¹Güx%=<‚d^»Œ oÑúÛTµÂ† ̤©34×Lsl×Y'šï%ÝÎÞx¢§P—výHÄsq?­×é`N9õ½=>†ï¶É] Ä¿–ÀåûÓߨŽfs´»\‹•£X©i+Š‚±Ô¶iI€ô @äs#6ÊŽ¤7_<Øåe|ž`–i˜ K:R`};/i6+ ÁEþÈ…Žåf\Uüµ# üZ¸Éœ¬2€eQ„㸙ˆ·ß›®¯0¤¾sA@ãâô¿ü B -‘ºåù OÛ§©§˜ßÌgoü—-nãl…A¨»§¨fm è<Œßhè%ïÿ3˜íšm Qq à´å ôFisµÿïÑ¡¾ežy2ÙÛ'/ÜcùlÊtºŽB÷6{ŒÚÇ.NÌ-÷æUÒúÇop#Œ|=Y*Éÿ^Kjš1ÀÉ1ÇÜÊ8”‘õ0,kJ`ÇßpF»Uó>úظ1 ܵ1š"¸¬A‰>¼QC¨9F!“³~½™¦þhpŸ¯â#¸jÄn`$˜mß*×f?"Go PòR0@ý½E¡`â²D `)Í" zlò,’‡Ò4߀Ùl"‰N½ÀJ`»áü¸-@Ó>Ÿ~Èšº`€o[²»Ãz=È-ƒïë'ŽlÛÍzÏ)nÀ^áFöÚáü¥ 9£Óº¬¼Ædê˜þ672L™æ¼ÊèÄIˆZßħ8 0 ‹VP8ýƒZΗ‹¹¥¨Giˆ$Üú‰öt[¡÷œïŽ¡%qiZÊ­r¢+3à6¯Þb:áñ¢Òüu$ï-­n£^«[˜A¦mÌô˜:cZbØVÁñÁ±(t[™îÕEcg](ØÒ<ù)Ñr=ê;é)0$ñÛçSC=#eЋ6õ{Z:ð ÂØcðÅÌ©­8Ó)8øcæ!ª‚\Ú^'±mÄ­Í’™J‹HÉ».™v_O¸ž3 'á;ª€3@³Û9 ÁFHÚ¹ÒÁ¦c÷qæA">¶ê\W’Kòùoß¿Íf°£þ7·Ø–"íS›çðHš"Ó×bèø+³ ¦¾B¥eôe€F#yÁ—,Å7¶¢Ý”Ô‚Í[u´pUQÌZò9ôi¿åhŒòææ R$¡ä镪‰—W!ý: žÔ¦…®*¿?ýžHZ¯?І‘S\pàçÏ}“^|lÔYD|mã{™yV#Å¢>±Œ ¾îBËð¬ DmfxÄ÷•T']G?ÇÀÛ*`~éC¼™ñù©¾ÌEá°‹\‚•o›3ÿòIcMQôzmpQ÷+Yæ¡(Ff¥¬ëÍÉrt‚Áli² XÕ&µš™§ÁŽ€.«ypÝD½eJÀ &ZŸþ“7‰rîc4 ÔI¤à…¯§ˆ°•Ü<4De,+{ @²ÁäóŸÚfWg\c®ÐY³Ò¤väÅ <ªE$-—ñÉCù› í lŸÆùïHVuq,-¬ èdÅ€RÜ¿äÕ8ïò°˜€›ÖÀðv €®(f#Y!y GnÐÔâ%€VU”ò”ä¥6h Üd¤·^~¢ÍI*³¨ªáh€Gb)誱‹LIÓ±˜‹CGªò*K#ål³-®Óìâ^_ÅÏf®1(­ô^+à’7ÀÐGïΞ2GpÊÊXáI’#±YKE¨SvÑøÉ,Üš:ªÖ UQ¿Q4òðШ˜{ëÿ6ì4šê2€™·»]ÃFy“v?înõj1KÜ}5ÊÌG¯Ü¢MÇ®|Þ#¾älvÖñãq°©•Ðú½¦kãÍžk4õŸïŸü&™øBè“ËË,,e´Ù¶z×fõ­j³á—+Àkk‹h»ê9OÑLŠ€êM¥¾Ù0"}Í¢TÒP‘z×-…äX–^ÿÒ< KÁgï’ÖcÐýjzyüœ¸<χô–Œ„‹ìBf ÿuÛVpë·Ïr'ò-$ÿÁ¼œ\¶ð"2Ã~¸ò ÍŠ[žl@fá•1_¿a–ÞÍ$Zzüöñ^ùÉI”êym“¸ÄQÜAÜé84ß0Á+Q&±°Y ÏÕëádêÒ³#‹õbó<Œ0¸öù,0@Z3­ç`: NÈW îæ]ÜŒ˜R`øŽ?U‹õ—| é³i5°˜‡[Sx®#¦ nÍžÆïy/’½H©Fé¸P5P䳬èJ€-iÚŸe0±J­2Ï÷"i‚ª MÓ©í¼8­«bÿÃ\qä]ÌÙó(?NáÕ{›`1àf_†Ì0ƒÜB®¥ã¬A&Q~?›  ”ïáSZýN•=tñ%X;”~ÐŒRLÛPD,€Î’G2jŠÅãR4f… +P† ’މï>ão𓦼©Þ  *q¢<Æÿ¦ÕkÌC7‹]Ç—>×è&Æ$-»r¹× Kå&ð?Þ˜ Ĭzé_ÁÔß_Àµ@a‚¼´$Ÿ%Ú-ò‰y¦åÐL³Jû’ŸÜUF ²v¨´Nõ-Ýs’¶iϹ”Ž–Ò_‘x6Ð_ Þ¡œ\×j³ ÄEw”qA€ BêEè¦xî2ܓƗhý ²²RæzG¾(­š=º °»šM¦}R`çy¹®ÎÓÆà=†0ÊÍ„Ðc€'± P0çH~]ã9çV/é¾¢7æ3–úf_Üh•ɬ×HÅVÚµ+ ï ŠNº]±àªõã‰!ieh¾®GV•°ñg€|rØÃFÌsØ ‘Ü‘UCOÒ4 0U¡6[þP˜æ¤3¥MüíltëøŠf¡]%pÞÅôÕþ*‰8 ž'Käû3€àU0.qþ8²–"€€ñáU )eNiÓj îÒï¢öÒj¸Âð}„¢çÆI8Þù­ šN$?Qò;1ä`°á`ÿÛÛ¶­àx¾‚MFíÊéü§¡œ V…èýÂÍFE¢5CBii)æ ³ ðáªçXî³29¿ñ;dr"•a {bžÀ¹’óÖ³IÌãü-&Í6ÃQ¯]¤Mœ ì,w¸Ì°Í-Z þ GÉ(ö¯x±2tÝ´(ÔoÒèiöOìº"©›C`ÝçüÍ:@@Å©bÑY=(ËQ>:€;-Zåwÿ6ÃêeJ»œžÑäÊ‹ ’ü³ªåEé‚hÒ33w¬Âõ ÖÝ Àn?w½ D.¯\Nî´³ù<ªXŸ’Šm(ÆŒÚI÷{w8íKd©Þa5ÇͲ—˜FM€¿´‹‘AÁŒ¦Ô_Q8·ÂÝ|XÍÁ€ä$q¹Ñ‹Â+‡·ÎçÌ·®¡÷ÄÛÈÅ i¬U‚×îÜkt*Gªi½(«‰ŠíJxõ–•‘Ã``¦èjQm0{BbÕ)·½…|ƒúþµ…|z#ü­Ib…#iÂH½È\ ëÁ6'ÂQ uz,p"` ï¯åFW|®^ÓDZÀì+Éãèå“)A2x೑™kã#úq >‡)WC;úÑ˜Ï n ŠÑ´Ä2V\íøÌx—ó&ªfØL -¸žm?A…u-æGÓ^€ ~֢ŧe†mеXÙ¼€³pØ€øãkBü¦pgÛ±8¬ °fÝaËbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 9#hIDATxÚíy”ÕÆÕ³± " ÈbDT4 ¸KM5'¢'‰ Ѓ+»,² ÙÜñ¨9$9 ÇD4QY—£bâE‚ d›…YºòÇ{Õýª¦zfz¦»«»ç}çÔé©¥«kê}÷¾{ï»ï>Ðð f§TxŠ€n?0§5P,?5šÊGÝ |¼ßObèÆðCúËwm€rÈ> &ïÒ ÉàØpÙøÍ j¦ÖMÇð;Ø´UZèS7j ñ0†¹_ ah¾Ö™/ýùRúOû9@¥zÁ`¾ª5@æJÿý‘Æø-pœzÁ<0³52óZ‚5:²ßè üB½è, ¨ ‘(¹hÙ·¾—ó0L—†¢&@õýÍEú&5€m‚õW/nŒÕȬ¾ÿ^ cd¿Àu¾+p†z` ˜§hdŒô[c"û'§{\×_uÈš‹®@ 0è]úmœœ¯¸ÌÞši%yÎþ¼cé·q•Œ „Ûe¾&@ZãÀ©ó%úQ{Ü­p©z Lÿ•&@Zâ™`œSú»Öã{—ùʾõh¢ƒCš ÁƒS~}¢î¹n;¡ƒ4ÒNú-%Ñ£pf ßï œ¨j‡an+M€´Á÷w§Å.ýá¸pz =”ÑH ¬Ìröý'ÝpŸ3ÝÃ80OÖHyl¾èæôû:â~-®àÐ4M€”—~k‚Sú{4â~'ç©ÃŒ^š©+ý¿sZ{}i|¾ÍÕ8ƒC¡Ùñ~ê,Ýpñ’þÿJ8á£-0 ÈCd }kè @ñ7Z¤6Ýê´ö ˆ_¶Ý@KõÀ0Ø„Åw‰tZt$À“btm‘½¿Ø®œ?UáIÃÙ’C«ti¤rE`(¬Öz\sŠ$ÂDE£¦û8<$‰0:é&N#H-°@µ¢eÔwB¤ÖŽô&B `x¶á™{+wi¤,ŽÁcˆÜ+Þ¨ãúŽ’£é‘®(Z%‰¬=§Z ð'(±Ä@;¥&¨ €[£!‘,ñM!¼0ÔµT§&@Š¡žPµÀ›1|÷¤:ˆ`Áí!Ø\/ÜíXÜA Õ´ÀOÕ[âto›ã¢`ÀÆ ¬ê5¨¦I€*1k°âxÿã%&"²R\D0€!ø$«7®0&@#´@ØØG- "1Ð&BŽðqÖ:*…j$C ,E)€o-àE„‡€þÔœ\cÁGAX3Ô³˜ƒ&@B´€%f¼€dÂ× þÍ|I€ñµ!aÃ`Q:D ‘hËT-ðfµ€Š–."xä«_€õAØ„«ÒÙA˜@ ’ÈòÛígÝlÆ5 > D¸øx gID áuAxÏ‚¹E°:-`ÀmVò–»ˆ+Öà™’PØ9ì²–K "ðJÞ±`FQ$¹IwñÆ¢TçIšKðbÐÉ} XT<˜”ÔénÅæùøÛG¥ú—ǹì<³_…|~¸²üš–ÄÞ”k@”õÉ­Zù¬NQøXÓ&@gÄôWÜRÞ‘vÀ1×9 €eoÀÊRÑ`í\ßö˜_Þ¢æuuÂ&D…|Œ D̤L>bý`ÁÃFxÕë”GOKdŠ®u“ Q%è5<§2U•Àß߇'vEŸéOdÉÍÃC¥Q×àbneÔiuÙËEÍò´@PÔCD·g{›lxÙ£V9¬ý–|¦¸©>#1{ªµÒ[}¨r’ž]€ŒÃ‡…þJ’3³õGDäñso1ûb',|ÛÛ ˆ‚í«¡«~ï¶DO Í—½å·Ó’6ˆܰ+–è`| Â{ßÃÚª‚o€Ç_™ë1Æ£^þgÅŽd¡Ä«+H Ü]ª”w—FéøâJà=`½´¨ÜÞAx~ ¬8œÐéêqCµ´öËÏôôª`´ý¬Yˆµ5’làU–ÀÊbxæû(/2’Þ@™ÜJåf¥µx/´©“‘™ï¹áÛÅs˜^|*aËsBIT|dˆ pHYsØØÉò¶tEXtSoftwarewww.inkscape.org›î<JIDATxœíyx”ÕÕÀï,!!ìa ›€„M¤¨ ¢Á °JÝ×bKÅ2g&ˆ –J,j\ª¸ASPù `‹@DP´)jÂ"²†°H@¶@–¹ßïm2óΛ™IÌïyæyÈÌ{Ϲ̽s—sÏ9W£–#"®Z1ž×v‰¯àÙyÀp ØìvˆÈÛÁªo°±…º2cÆŒ¶………æ"òr\tÀQ`wE²4MÛª”j ´ú·;€·Ë>›œœÜÃf³œ6mÚ13þ¡B uŒàr¹®r»Ýw#€®ž·÷ˆHG³uÍ;7jòäÉyeß‘/~èj ðIÏž=?;vl‘Ùu¨N,¡®€”RC€€ï4M{Ôb±ô‘NÕ¡«¢Æ÷0AÓ´iÀàÀêÌÌÌ·«£ÕIXOÉÉÉq‘‘‘¦L™rúÂ÷•R/sD¤0DUCD¾¾õÔ# 䆪>F Ë)Àét^¯”š ŒÔ4mœÃáx3Ôu2Jrrr\QQÑ `¾ˆ¬ u}ÊN#€æt:G+¥’”R}€=š¦M±Û퇺bPTTt10+"4Ms8ŽÕ¡®×yÂjðüBjš6K)µ$”C¼™¤¦¦ÚÛª  `%Ð!**ªÓÔ©SOš)¿<³ÃÙ;€»€@½êÕWÌY`ð°äDôšŽi 99¹SQQÑ* ¹Åb•””ô™Y²K“f…¬ îF‘Õ£Çgò€÷ ç¿ fù˜Ò<¿üõ@C`„ˆd˜!·4Ü <t3_¾)ìm¨T³¡®Œ/˜²2/((xha±Xn0¿ñ¥>ÈD`'°€ðm|€N ^¶ƒó1}]Þ˜5h"ÒID~2Ižç- ^.2WnÐÈžy'Ô©Œ0ÝJgà%àÆP×Ä$VƒuLßꊔÅê ”F,?ÝlÜ#Ôµ1‘ΠøHòöØ;†Ö"ÒÓG™-€åÀs„~e_D³AV´ueÎã÷àq½Þß(==}9Õp]…«€ËÍ‘Ötîƒø H7yÍä?~©©©và}to–Tsª Á½hc޼A+`%ÈC]¿:€ç<¿?ðˆì \½s*0°[‹0dV(+áó<îñäùÝ~j`jÓ¬9˜œZÃÛÀ¸P8ùì`±XòÜn÷G±±±‰©L³BæBàŽÀä„MšDß‘öíѺu5ªÇ¡C§Ù¿ÿ?üp˜Í› ªvÿ|¨iwÛ”l;€’ Œ ²^S±Z5î¹§7÷Ý×›ë®ëˆÝ^ùLš}’¥K·òâ‹_±cG•C¯uT rgÑmù5–‘#»ðüóÃèÕ«¥_å ܼöÚ78é9rÆÛ£.G@•ôƒ vçc R‚§Ï\4 ŽxŽë’“}’Ñ£±yóoM€ CÝM§ª aJƒë:ÏV¯F®ö#"¬,^<–[néZõÃ>pútwÞ¹˜åË·WöH!X†@Òç¦(ô‚·m &"ëDdb`*f¶÷ÔÐÆøë_o4­ñ¢£í¤¥ÝAß¾•š>lúw&ÍMRYé½Ò "c€k¯c•wÄùïRƒ<“&]Ÿqæ(£¢l,Y2–æÍëWöH;àý;4†ˆ´‘N§sDeÏx>È‘%F+<Ü@ùÒ²e4ÉÉCªM~‡«ZSŒ&•ß³gÏC@S¥Ô´Êž©°ˆÈP úÁŒÁ5@òÅ@ÐV³ÕÓOÆÕªcüø¾ÄÅ5óöˆËs<î7žt5σ\.×ÀŠž©lxØ|hD±NÑÜzkð\Û¶mÈå—ÇòÍ79Þ›òo#Φ6›ío………{•R?—ûÌ_aU£ÕÞ|¹ÁåÒK[]_ #ð0à·(!!!x·¢ÏLãRí  ¯ZÃ‰ØØU?d"mÚø”/ãi{¼i˜Ü>t0Wfð‰Œ´Ñ¨Q°‚ŒtZ·ö©Ãµí3õw€”””z"²Èårõ3&*Í ê)³*JÎ+¤ ÀT'NœóñI5Mÿ®Í¡x ››;øÛí~Õ˜¨¬è9ykÀŦ ø»7£TŸÇDpðà)ÆŒù;gΘ›×réÒm$%ôã¾û;@ª¸"ÐJ„;›7`àÀ¿™fxão;öFæý²ô è@Ïât:‘ÿ¦¤¤XÄîŒy©ØÂšŒŒƒ\}õ¬^½Ë°Œ“'ó™0aãÆ-#?ß” zè§„†±)¥zm'Nœè«1úŠ šwêÔ—«d ËÍÍcÒ$¿­›A%'çC‡¾ÃÈ‘]˜5k(½{ûvdœŸ_Äk¯}Crò:>]u¿ÐºaÀwCD^~°¡çßñË uÝ –£yóúÜ{oï⿳³O†}8ÏÊ•?²råôéÓšQ£º1thg:vlBË–ÑDDX9~ü,œäûïóñÇ[Y¹òG =þÐø§rWõmè7j2¨<œ3vU;ÉÈ8ˆÓY’1*ÊF^^0ƒ|•Ñ68 ´´ _¥ZÎUÈGb –«µ·ñã1‡€V6`µ¦ißRwíKè1ÚGf6™€òàúMÕQF;ÀN`k N¡u#@è1Ô"ò"ðb –Àº ôô# ·{kv»…öíEãÆ‘üòËYŽ?ËÎÇ̰þ•% v€Sè)ÏÂŽÚóÀ¿)þ{Þ¼dfñ©ìøñWpùåúÇíVüáUo³##m<ø`n¿½'ýû·£~ýòÒ3g ذaï¿¿…÷ßÿŽÂBSOº“Á&"éÀÇž9!¨Ê«“nÝbøýïKŽ)–,Éò¹ Ú™Ûoï @a¡»Ê0lXg,Se,Aýúv† ḛ̈ayòÉŒµ]»ŽûT'/Ö€®€ÑïS(¯ ÜuW/Þyg 6›Ë©K/mIzúƒôîý ¿übÀ _‚¡ "zØÐ÷ƒ1ÁT^[hݺ¯¿~k©Æ?vì,¯¼²‰¯¾ÚOvöIΜ) eËhââš1vì% ~qñ³:4æ©§’PÆ]£m0Oøã €ì!5Ÿ‡êCttÉ\¿}ûQ^À¥ÛdëÖŸY·no¾ù&N¼ŠyóJvÜv[@;€Ñ6ˆ~¶GÐÏ  …]þû`2hPé{,&LXQ®ñË’’²‘-[JŽ^:wnZUhxUmƒx:@:ð•1êWÝ.º¨Ä5?77Õ«}sïºÐÛ8"ÂJ½zlÆ ÿ;{m"å£ žó|r狉ˆÐÃôòò }I è/¾ ¿Û`îܹQ'NœØ|¨à'ôp£êM¤¦‰ˆŒ´qå•mͪÂ9è¶ÛßB“'OÎC¿È;PŸ@)¾ LƯƒ6mrûí=ùôÓûéÒÅkR(Øhri3LÁkÐïøÕc³Y¸ôÒ–tíC—.͈‹‹!.®]»ÆxËߨbBÐÖ‚J\NÍ¥{÷æ$$ bôèî4hÔÙ0`¿r[…ž:ŠˆŸjµý.Ý›Î(V«ÆsÏ åñǯöšQ¬¨H±k×122òÑG[3¦{±©9Îbx÷V‚ @Ó´CJ©ö@OÀOï 9 ²¸>ÐÊ„ V«oK£ùóobüøÒaùùElÚt€÷³qc6YYGؾý(çΕLÕÆÊûX–uF2†‰HoàM‹ÅòpRRÒw6¥Ôù¤×àwЂª5 I“ª³Ú—kü—_Þ„Ëõ‡™íú]Ú ^ ôµZ­‡Á³ ‘è¥á^ zAýðz BMâBOe<ôPŸRÏž½ V©ñ9‘F³¸~HHH8¥·ŸCEŒ¤!“Àÿ¬PPðÕøÒºu:wnZås=z´(þ·RŠ9s|ϬðÚû#˜ê÷!§m+Ï¿W\‹Åò¾R*G)nÜñ—wѯwKš6õ-É…Á*ÞhÛ¶ÄëÔ©Žõ-L_Ó(v61ŽVaÒG¸h iZqNqHJJÚl2^©žÿ‚Ìè©fBÎÙ³¥ýóãã;²h‘÷åM³fQüïÿðIþéÓ%ÑÂÑÑv7®çÓ¹þ“O kW£‡¯l‡Ÿ)h±X޹Ýîw•RÅ™`Lô [ÎÙ Þ0RÚf³T•6Ý+gÎ]2*–ä½ÿþß’R¹[XT”… K«VÑ>éËÊ:Â%—èӀŢ1~|_ž¾òiÀbÑHH„Ó_î3«Õ¯ÃçŒZÿ’’’¾î¿ð=“B[¿9ÓÑã ý¢U«h¶o̰æµkw3dȂ⿿þ:›ÜÜ<š5Ó‡þ¨(kÖ<Àc­àó(*ÒOn,ë¯ïÄ / /öüüó½ ä=áé’%Y¥öò3g^Å¢1þלÉW¼Fbâµ<úh_7.Ÿc£°ÐÍš5»p:?ã‹/öz¢ˆ„„Õ<ûìõ~ÌÿÚ$pŠ1w:7X,–½Ó§OÏ*'µ¢"²øMlllgc™Cdp³±²æ£iúÞ½oß6ÄÄDQXè&;û$;v5%`½zVúõkK÷îÍiÖ,ª8GÀ† {9v¬âvëÖ-†þýÛÓ¢E}²³O²qã~vîmñbccÏ¡G“Î7æ0r!=ŸÒ“Q+ù;ôœˆÏÍoËDä_ËøÔ<ÖÀ è‰!g¬Ÿ‡±EÐónÀàídµ’·€{ òÈÍÍ}¸Ñb±ø¼¸÷y žž¾;>>>xrðàÁééé†þCAú?aðY`¨q9µ‚Ù Az@ùbDäf`0Ëápø|hä—•/666øR)5Ëce Çlô‘%èé5ÀBÐy:PA3f̸ýšøõ€ÃŸ²~uÏTð;àú±c®J—Ñ׻͑W#Ø Gª w‹ˆ_?¦ ‚|Aš €C]“jæS°ß FtW„&"DÄïûg¨ < ¸¨e÷¢ÇML÷ØöMOhSnŸ={¶Y)cÈ è™Ë›$3X\â1ð„Mム@Däååí‘xês^ê~;@»•š½6ØÜr Èn³„&''ÇaÒèpˆŠŠú½‘>‘>U<î'Že趇0p-JÙÚãШ+ˆ©#™Ë庬¨¨h³ˆL3Cž)½HDZ¢oA#D¤¼'fÀ¤Ú!ç.`\USÍüZ 4}ŒÜÁä—Ëu™Ûí^ üqÍ3Ï<°{“i‹@éˆ~1qKàr#+RßH³BÖpP÷¢_ƒêÅâà#=\K­ó+ø†ˆ ÑõpÐf³ OLL4ÅóÚÔ]€g$xXDf™)׋ÆF ýÔÝè¡íÁJR‘|,„¨%F5ýaöìÙ óòò~vGDDÜhÆ/ÿ<á¶ ‰­?¨!è°ý0/{Y>zÜäýÕìËêâ½ár¹®r»Ý?ˆˆ©ù™kQ(‹ØÐ“!v×ïÖSÝÐ/Xjày5ÎžŽ¡'¿>dƒ¶ØêI†¹Û“­h"òœˆx¶«£sÎY|ÃC7’““»ã€o='VuxÁétŽÊÌÌÌ‘vÁД)`ÆŒí ¡çœ <#"F’PÔZRRRêyÎóÖÛl¶»³«[oµ‰‰‰ûÐ}ç“EÁÐ[Sp:Ãrss·“€YÀ`4>ÑMÛsL9Õår­p»ÝA]A‡;J©Û€s‹%¾²ž:j1sæÌ‰‘ÄL„Í6ÐétN+¥þî¶ÒšˆXìv{‹ó)ÚÂp‰ÔÑ”R£xà§Ó9«uëÖiÆCÓà 'õÀÔ‚‚‚\`Pˆ«TLP> Dd°¦i·g•Rïåääì‘í0:sæÌN§s*ú½ ÐLÏ…¶V¥ —‡Ã± Xæñ-˜lµZÃ"ÕŒQ nUJÍþ‰î¯·.Ôu*Kج|ED®Ô4­¡Rêóp±%¤¤¤ÔËËË‹˜:µô¡Ðœ9s¢OŸ>ݪúNF§&v€…èóé)`µ¦i«”RŸ‰ˆ$ׯHKK³nݺµ—Ûí †hš6Óáp„Õðî á²ð‡4M¼Ä)¥þêùw9D¤:އµÌÌÌÝn·;x ¸HUJ­ª]ÕNX­|Á3ì¯ò¼ž‘Ö@e)í¾‘‹€}@ú-©Ÿ‹H¹°4§Óù„Rªú…ŠÍÖžòeƒ5ð,pØn·o§-j\(‹ˆVòñK@ ú-ç—¢_”YÏ6´ úMªGL`K%:kM\ãÿD-Ü—F±IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/128x128/actions/showsmoothedvisibilities.png0000644000175000017500000001113614507760372026267 0ustar olesoles‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß  g+CëIDATxÚí{œVU¹Ç¿ûeï\ä¦ Š\Aåbfž5±’¬ oe¦˜¦ÒÑÊKÂû ¨y<¦ ŠJ~R³0”´<^"=¨Ç‰7(戊 \rAå6ÌÛk 3Ìì½ßý¬÷ ³~ÿÁ¼k¯µ÷ïYÏZë¹-ðððððððððððððððððððððððððððØ=­'¡/p8p,ppÐÞþu=ð0xX€°ÈÓ³« €Ð Ü ì£l½8xa›§jWa*ð=`ߟô)ð„ó=]»‚gS©÷|a0á>O[9 €°'p7pNÇüp&ÂO_¹€ÐøØ£Hãþ艰ÆS˜Ry ÿT`eÉØX…ð-Oa3>RT%ç5•cgßþ T”H{=Šp‘g}'ÜHšºÂ/·”ÉK_Šp»Ÿý|èÌJ0¹k6Ž~Uf¯.Âý-\6ÌÞƒÞ ¥ì‰†ù>pð:ð/û€!ÀÅ@Ïž}:ÂC-”üi XÅhÿ@ÙÉ0`žãÿ¸á©,}œÜôwÜŒ ÍÓ-Šü*:“QˆîD¸X'“èH5ÃË—#Ê%£Šqd˜´rè±U¼×"ÈŸLŠí¬:+ZuCX­;Ôñ¶Ãð¶½Õ䤙NÀAÀ:+D-PнEÀvNS’a=ùÉ4@š€€jàPåÐÞ†!lÌqmk<ñ jPk…ïƒÝxÝï d&À?ÔÙ¦9ÿB¿œÉ7/ù10Ôn5¨æ1™¶»ñü¿Kùû‘Mÿ#•à¬ÿCe'H10Ï’¾è ,S¶ìÌöÝ4®@8 ø¶¢ÅoÞ;Fu0xV9¬u¤¨d"Ÿè¥ÛÕ˜`Í æÀHr Ù. ëvŠ{ lI¦„½ìY_³ùú X0ò ¶GÛ¡a7r# *ÉÿzùÑ@X  ÖѯéÜÛ‘ +Ð; ~‰ð“]üÌ?ŒŒÊó>B¯¨?¦BÈŸì@þ‰E#ßœLÖPi5‚W \µK @†—¿Þ ˆûAª ù#kÕ I˜Sô‘¦ø’CË_ »‹ªþ)@E‹IQª¿ùp=lã#åÚò„¯•ø£ŒþGÝ. 7iïBä÷±¶•¤˜pdöÏ` ÑÙßW"|Ný"“¨#°};)7¨C”V?3þÓ€?*[m¡{2Þ¡¿â“ßÊ5Kó@„…Ù~T¿œƒÞùò忥?Âtê¨VØü'˜ð® À`1³ç)?Ð#@Z9þ¶¬ã­]dþ§•ä_ž„|£„ƒ@i. 8tAÈppÐÍáÅîFøkBA˜œ¡ìãq„o”ñì?ãIMŠ «5ž‘D|W9¤‡³’/ì‹pþLp$à4`6›Y”íc üMÙÇH„•ñ쟭úuŠÏ'%ßü\¸Ž€C€Í ~¿aL–Yÿà#àçyü=€·žOðÛ/Ù¥EƒÛ•YµX³ÿà E‹ß2Qç3 uV\ LŠùu%iV„ 4°Úä/ÀW üY6ç!1›¾*Ú“a¨AÃ^/òÏ~«RýB'm7©FÖ"L& „nŽÆ†’oÐXUòöf!\³eZ*Û˜ƒ¨s AþÁJòë—K‡Ópô ®n°¿yaHÄlB¦d³fÂè˜w8˜¡Ö0I«­Œù"o‡%ìO;–°*Ziju ù@n$ #ð8ð¿ù6^+á\«²…KÔ&Ãs%|'íÑt#0¶‘›Bëâä\L/“íÒ$&bÈD V>sZÑOÂKÀ•­ŽBì$Ù£ómY¸­×ê/¸æœb5C>6tÛ1©^mr|Ö<öâh~aÙþê@•Ëlš{1Èø²²ÕMW6zÆÀà„m/A¸CŸVÅà±^µ8!@h‡Ð¡-½GsxîQ|ã0³C¢6…*>_ò_u ÿ&äÿ\A>`–¹äàZ*艮qÑÕÀiYK¿í ?ç#߉Þ^dÂÅ’NfZu ¿—ˆ€v¤¥È ›ÇÞ9'êÀD ¾ƒÎ[XŸ"ܬü0=ì2s˜C;Bž{\½ô+P‹IG_–Gâ`ê!uP¶4ñ‘ÒÈà#¼ £xFÄL„dKÀu¤0Aû)»8@M¾y©¥í¦F‹‹~³Ö^­|^0¡užÈñ¾vph}nò‡¢sÌÝ_O~r üÃa&.§+qQÜ­îɨ?²9saϼSÃHƒ¬@×:½ÇTjx}ŽC=~ŒpÛŽÝ@[U´ÖaEÛ²Û>Ô¯ÈèŸòÍnƒ•;g—p.ú@’NÀª”EBÂ]ÔP›ù×ìD>ÀVõ¤8¿iŵ ËÀÏPv²“á»É)¸#~<ÿüLÙ*cÏÊÍ FiZ°f®Å½˜ Ó…c 0Ïg—çøæw#Mò3ŒeVc}aDrCI!Z¡èÇ@‡¼ß\#whÙaIÈóZc‚Q\«šmŘ›ßÀ·ôNB0£ÝК”7§°;Âr¬º(&•1£| ÁTô&ÞZ ³M¨hzú§—=Ñ„=ï%‚G87û#ÌŒøûSÊçwj š|— 3‘FÞ¨bCxè­líFNƶ”CböÂÕ}R<y ŠÐZÿë%%ß`0¨óGÙÌç°<½]>“…ü}•ä/ÏFþÎ <Ž.ôø#ô®ËBh€O8d1qKd¡IáL”S1G·Æ™‡³üîåsÏN¶?tWýƒ‡¸z¡Èp0 èì…ñÔ½ ¼HÀkdøQDÆL¢u¬@_üò„U1ãŒÁ¥VQ<–'# B¾MغF;ÿÞÚpÀ$:PÇZåàOE”V4@r=¦||¶¬Þ ° xŸ€ IórÂ>NžQ¾ËF;7eQ¿3!/›Ä¹¤8ø€‰ ì%&ûj¹Ò.ÑáÓd ô·FŒ¤©Ö³¾šè—iKŠ;Óí,wŇÀt„ë|°s1V: ³ý¸*K<½9‚}S¯¯âùÏ¿ž 3ÆdéóuˆˆÇ ÇWþ7¹‰ ¡£!ë†.Y> Ée»˜R€#Ò$K@7káC§+ˆi œ‚±øõ¤ÁM¾cŸ¼¼#\Ëm£5}?e y¢Óa?« öŠøõ0ÒYìϓهí,ö/àÆéELM‚­1ïôæØie“%TÅád˜¯jÓ†6\£»^§i}€E´ƒÐ#Òø¬ä °µ&L”ò*»|EåL„­Æ/q± %/õÉfo2j#×X-ù„î˜ÓÔ6r×WýXY‚#…;1QÂŲ§wª‘XŸþñ ¾YdF’¼ú’¿'&òJSþfn3Ëá/’†âòªŽ.'``¤‡o2)’ôÃ}²û~ñë 8ÔÕÁÞDœZsŰs1Ç,ØDÓJ)B?¶${F£´¦0.ƒUsçé×Ó¡ ,«u­¤\gÿ³Àpe«oX#^½=$E¯ØÉ[px Sų\p=QãHoGx Q…Zçò-ÿЉ#Ðà~{ìm,ìß"ÃLLlF¿­€'sÉ zLh±#–`ܳïXcLgLxô±¸E×ãJ„›"Æ|ú8À?"Œ* ñ)kdÒöѼü› ©×ÔP¼Ò53èQp¾°i1Æ’Xóü31up]/i[wó^›È¥ÿŽ­0.m­­*Wý¶Ïû5(.Ø‚”à'8’¿•€ÃzÇ’oú˜AÀþ¸‚£NUd€Ç‘èë ^‡pEžÉïh F.Kèa!äP‘÷ÄŸÂ7SgW@"~gÛ•4OÜ"Í6{´Jó)@†9HH½c#ïŽÞ…|sÞ\߯]ãh/9 -wJƒ´1§6MfÐ`h^m:îUWýjÞw…í{ãl©yæ ÜfÞ§ <éø=1>/8 ¡*äo‚ˆ£p8FÕWXI&·’âc6`²x5¸%¯ªS—ýZÍ´¢#B¼}¦ÞÑL‡‘Üi{w[̵ºßËáíoEBÂËÍQuÉÝÕËߦ’äÆÖ,º*< Q×îKò1ŸF_Šf#P llfÐ.ƒ& É°Æ ÂÇŒu$ìÈÚÍåâŠæy },³ï–ÛèFºÁý$øà.Å W•;MŠ€¹˜@ºc“Y6‡¼cOh^µ§›ÍVKöÊ£}ävÆ6enªø„† £¾µ‰ÿg3p i4i)n©µÔ½‚D„±¹h(4ÒHĦÛ³ÒÔ;Xf‹‚î„TÌŽ¨ùoSŒøz“ßV‰îÂ$€cˆÔp#´Ëˈü‘ä×O4~öŸ©˜c”v‡¼S ¸8ײ˜~ ¿=ä8›Y~bÐWèÊ7>Ž—µf3<=êyQ™AóЙc3³pqïäÖÚ½€6]ûÒP7²°Vt‚"e85ÇZÓ-2yÅhæöèJßmƒè“Xò¾áyd1䉰 dsÆV|ý5ö_¶!àaÏ\„.î/l!`éÅ!…YQ'ÇG.{4ª$.))ùfÜqÊQ˜ÃäˆÊ &<îÆ"Œ~&°BòG+É)Žü°%àaåàŸ$Q£Ø¨b¨-ŽlgYdéãB!iå¹ã1Lmâ±IC¸­1))jIà^nœt/ºB Ëm½Àòy‡‰ÊVí‰K2ž·&ÜËò k1™@}¾©*LmRÖ45…ÎÍuØiPEW2¬Dçêá”(ApqWßc“W²išJ2Üœj÷?A–ýQ€©J6Á¦Ý»h7íUqÕH²²>57 ÃÜšÄÞ?Qçç[ wÝ` .&y~ øœ•]¬]¢•ÝÐ-'C °Ž€Õ¤õѺúéüS19뀛¹‹L€Ââýð¡µfÊTÞG_ÿçkHÉÒÃÃÞa.$‹ï³P¯DÝÚ“|ÑÔt¸Q;…J‡It¡ŽUècû4®¥WBò§C‚e©ñE³† edèÍ:£Ø•0‘5¸Å¼[ò‹#Ì~äU›@©ç È ü’€^˜Üô›#&å½ ,´6-æ•lÌU A_Šÿ'¤õ§”€–ረ "{Mº[µ²ÕbDè ä¿èAùâ9f3œAd¹L¹ f8íxNyu›+&Е”zoæ9·òµ-G4̰%˜bŽŒ³!×…Þ°.öT¶<9ñÅšª=Àî‹AèçÛû‰ µæ‘:V;?%ò[¦0³í@êøÐa ÌÿñP8 øÓ&Ur¿Í$Õ"`"+ÑyÕÎÙ“òx<þìHþÈOØ]ËÔ \êK¡6`œ9«û­â2<†®Ø34ϪDÔ‘P^"„@—Og°øª­‹ é«süùŽ£Ý ÉšZç@-. '·bòÖÇ<»梉‰¸ç:Ö#ïw{h j¡ÒFÐxVVcœhs0ž»ŽÎ`$°¹Û\úÚÌf¼FöÃD6w(³‘m†&ª(ê çóx%–R>Ò•–üU…êÀ @S¤éAÀ{e ‹-t')Ïx3-°”@}aF¾qu1È÷ ~Op,8Æð¹c檘¢õë ^ö «Ûç‚:àáR\¾á—€x¨Á{þ®€½Ì'`¿Rݼâ5@raˆIÌÈ×-)³0ŧæ—òµ¼èáÌM '¡¯gø¦`Öí…<Úy(ž0ŒF`rÚÚeµsð‰ÝH>ˆð'ÿÁ<<<<<<<<<<<<<<<<<<<<<<<<<<<Ї]ܦIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/0000755000175000017500000000000014516225226016574 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/24x24/actions/0000755000175000017500000000000014516225226020234 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showresidualvisibilities.png0000644000175000017500000000157614507760372026112 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß ×è˜ IDATHÇíÕ[ˆVUðß>çŒ3ã\BGÇJ £˜ BCRº=>hݳ›EƒÕ‹ÁHdAV‚¤PPôàƒIÄÂKB“6y×/ß7ó]ÎÙ=8…Ù ôô 6lþk±ÖÚ‹ÿúo.Úma<ÇýóÍi±¦í¬›ÛÊZ[ËÞlªXÝ3¬üGÌ“×én²´Ôdë‡[í+O2¸ä6‹‹ÔÜ!³I´2Ë­8?.Ë}ØT¤v/Zäú±rec‘ !Ê›F¬êÝçíítîjócRxë`ÕL³ÏDÝâ¹1Ô¬µÞ³†LC+šðIÐça,A› õòc¦ÍþIW–óùN䉖 5Ÿø˜vñÜ Nç¦ï˜»›CÔ2ŽNbÛ\äéuf†xBAûY²œ_.3œ7h”«Ô2¥ÁKLÌi¹ögƒg9~õWæ©d¨ÕÉæªÉY®"±e´@>:r‚ Xˆ§,|š"phª9¢y˜›Íïê·©ž²ð[Ÿ5Z<í¤¡é²9ÍU«êµ8D÷4V-o/›ØX3#Ógç0ýAï'õÔK'^·ïü·Nj±3E{ÉÔž÷´H4ŠN‡Â$â9vÅ5ÊSž²¶Ôì–zê ¦ô˜Ñ^öb,»/2Pmðê|>%ªaVCnv-ÑØž§‘†à\ó˜[Ë…žÈà„ºG’Æ^«%¶ÅàÑ”òIJ-Ÿ:1¹ª1è˜P·BôAMBŠc !Ú‘Õ½2¼Öþ$D]˜‰í W|ó‘­cQ·à*‚ޤp'ÔƒwBü“êÝ+õ&tö¤ÖC’ÖÕËû7š÷Ãf'ÇÛì§KDý4)lzk¯ Ž R·7Ô=É“ÂC¥u†!+½l'vþ]I Ë«¼¢Ã u« ¹ä«‘&«’(o¨¹wÿ»¾_‹údHHBŸb¼ÂÝËLmªxüÀ¥öþÖ)G7îÆ]AŸEøò_‘Íø7ô™ Ç1‚_1ŒÊ ŸŽžì¼{:êËGãK¢aœÆŽ¢ß_ü°þö;¶z€iDÔIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showoriginalflags.png0000644000175000017500000000155014507760372024473 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ 36“éPtEXtCommentCreated with GIMPWÐIDATHÇí•OHÓaÇ?¿m¿¹6ÿ¬P×tfK&¢ƒS”0Œ‚†BžºÒ¡òÐ!DBA`SÑðB)B[¤ˆA¤äE[Ø&ŒEîw˜ÚþôvHCWÚA<åÞËû<Ï÷yžïû¼pˆF¶ —·žz´üÍA³Ï¦Fít˜"22Ò®öÔ’ Û9'Î.À¶KŒHÛ~¡C‡‚r6¼j@ދБfšû@+`”mö3 4<¬¢ª 8VHá©^zWUT1ˆh¡Åä¤Vp¸Üô,GË(p¸qß/¦øÍ6ÿºÛÜn«§þ P§EÛcÅjÎ$“óœ'Ÿü?ë*¨(¸Îõ;=ô¼›evÈŒÙâÀÇÅjä0aëí~ü½@¡'ù¨TRùà/”tÒõö׎+(¾ó}†­Ù€¡€VZŸM2)np#|•«O†'IŠ A±ÊªPQ…ZJ©§„’ñDœ¸H’ñû$Hˆ9æDM¢–Ú‰1Æ„¿Â„E¬³NŒFŒl±ÚB”(!BhÐ`ÅŠ¼ÇC„ˆÇ‚Šº&!VXÑ1® Dš£v‰¥DŒXRAÑkÑJYd!#£¢’Ai;…ô,D‰Še–cRBëÁ“È%·²Ÿ~}m75hNVQ•mÇþ¶¾ÇQ¢‰i¦^òòà 3Ë㌿—‘O8pèw«Â‡/ZKí£nº‡Ð¡³Ø±?Í!ǘÛi!"€ÁMÍgo*-8œ¶aó¹p͸qÏM0±c!F n]‚DÈÿòÖ; -²(€$¾¦ü P WGÝërÊó%$L˜˜f:>Ìð Цÿˆ‰N1õé _^‹ÿØÚ±¬yæ½x?¯±VÔIçk/Þ[ÀÒ&Á}Ë).¿Æ5QDÑàA­np 8uø‹ýgø bÒÆ…LIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/spectrum.png0000644000175000017500000000342514507760372022616 0ustar olesoles‰PNG  IHDRàw=ø„iCCPICC profile(‘}‘=HÃ@Å_[¥R*VqÈP,hqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâäè¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"€Ç„ÄL}NSð_÷ðñõ.Ƴ¼Ïý9z•¼ÉŸ@<ËtÃ"Þ žÞ´tÎûÄV’âsâ1ƒ.HüÈuÙå7ÎE‡ý<3bdÒóÄb¡ØÁr³’¡OGU£|Öe…ógµRc­{ò†óÚÊ2×i#‰E,A„5”Q…­)&Ò´Ÿðð9~‘\2¹Ê`äX@*$Çþ¿»5 “q7)œº_lûcîͺmÛvó<WZÛ_m3Ÿ¤×ÛZôèÛ.®Ûš¼\îƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}2ÔUê88F‹”½îñîžÎÞþ=Óêï¶rÂÛÑk.bKGDÿÿÿ ½§“ pHYs99ÂVtIMEä vÚr[tEXtCommentCreated with GIMPWíIDATHÇ]–;%GÇçÔ£»ïí½3žY³‹eƒ‘,# „œñ2bB> )1 â+!@F€EÀ@+y½æáµvæÎÜWwUCÐ3fgK*µTª>¯ßÿœnqwî׆Ÿý5Kÿ"è¸sHŸæåB3°¶œ‹à¥‚ ˜/gÅ&ùÕ>ùxõù÷~ü¯O#¯­øÁ·RJcö¨ÌoHsÚˆûŠ« “¡sC§†'Ew¨"sAO{ÎßýÛ¯7~ü6ŠÀ»€|÷ç¿$Ž,Á4¡Wt;@pÒVˆGˆ;h¬¾40qÇU°ýšÏjÏX•o÷d€ýcëÃcÁÕÑ÷8ðþå5/^“Re÷ňž„x£XKŠ‡å¹ <¯¬KäG€º;îþÌÝŸy§ºvÚàŒ«‰Íxâéú†‹G{Þ9»!Œ6•ºr,:…–—lê Z­^Ì<Û¿•Uµ{À õ†Š³êfãÄYâí~Ç‹á OÊñI±â€B–’zϧs‚…ô*"Üo@oU,¬RYä›t"ÇF×UÈÁ#XZ²°äÔÞùïqÃK¿8šÙ6ß±¸2iC œ«X0qÎÑCîxœwlú Å9¬2ó)`ÙÁËŽu‹L›8/kRèáŽÁŸÝýOîþ‰g9v}%cˆ…!Tž¤[.óŽwòç݉ËÕžq<áÙ°ìx¼‹>;-;me\®"ÂCºX1M8Kï Zé´ðVØ“qºPèSu,TÇ’ãÙE¤q:d¤èüB_·ï ú Ug3æÂ(…N*áÀZc˜écA‚ãý’…­Ú5¼3b_±C„2Ýý÷÷¿-"šÖá²?‚:Y"ÎZgÎÂęΠ±ðõ~Ë&ŸÈ«‚®+¶2º’ºJè+ãjBŠÂ2î‚ßQz9®â"OÜ…6:±ÃÌJUu¹PÄ™ªÐu… G¸ìŽg—¯ ãîÿq÷§§×Jg­^'HZéS%ÆFÈFŸ+)6T1MÄ=èÕ¼‘'!‹Å0dŒprÅ<2YÂ\HÒ¨® ©RLIyqfªN*ñ!…ˆªª—"òTU/4:a™\Ð\¸µÄì­ef_4Õâb¸Ï•U*ˆ:1Ø’ùÎÉ-îþyt÷÷€+w…:m¸@sÅ\Ù¶êmë™,P<ÒL´2GÁb@ÅpºXé´’öN*þƒ¸û§îþO z¬wQnkÏÜ7–ٷ̿ˆ]É,q¨™)ªFs¡š‚ ‡–È»Jº­¨êð¨®ÄØ0ç`‰‚r=4àd‰¹%mNTÃfJð»÷o ­Þs÷Ÿè›Ó‡¡/tZéCåh ‘Æ®u¾(ic 94ºPiMÐå«@¸9±žÒgîþÇûFûŽˆ<µj}õ@ ×­ãÖ"7µcv¡×Š›8“ÕèC¥¹RZÀ\(›=²Ýý¿ÑDä U½¶N7SƪSŠrœ•«¹g ¯Nsƒ©*sæèx¥Qk¢hÀA"¶ÝbÒÝ)ÿµ¿ É ‰ûÑG{­x (‰áo¸¦Gœ}ME·×öêæUÝý§À—ÀÎÝÿ."?Î'Àï€ï;à x~çì#à%°v÷¿ÜÛû•%¶s ñ79IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showpq.png0000644000175000017500000000137114507760372022273 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 6 °Œ(†IDATHÇÕÖ_hÕuÇñ×Îþ"¬±a‡¦²ÜU[nýÓ¼ $5X7)‘z…Ô°† MÒÆp$¡(‹Å.¼ˆ.¼2’(1]ƒé…ËjÈæª­VÈv¨uöÏíxq~Ê™­C]ôÀÃ~¿ç÷¼¿ßçó}¾ß/é[V-oPµšàP€x>?–Ð{”îzžX)8;€®eñr-›x±ŠÝÕ|…_ÿÀ×Ä73SÌŽm?EÙ"/<ž*¾»Ê/÷ê)Ck"´Èõ½[ç9tù–á?9ø=+^ãT»V°ðUÖVÞ§å,ÚˆŽÓž“ú׿Ç9ÖŸÏû1>XPÌ…2ÂÉïFˆ}ÎÏ3||‹3)f䆂Qâ54^Y.ùë”o¥ç%JaŒþÆÅiÞi% )fPô.Ï?@W+ž^æÃg)ÆWŒ Ò;Æ›çø}%é h"§w’Sû–Ѧä$#Dé«ã±U®ÓGšKã´ý@[îýQosâ?½ÅÎ4ÞÙ|ÚÉïúÀgޤ¨ÿs{=ô;A’±Cl+[ú¹"˨ü‚™ a¨[¨N \À"âˆá6& :¹)ð'ìÿ} ë É-àËÌ$ùlðœ <øT<Šx0ƒ¢ƒ<ópb W'¹4ˆy¶¯ã¡vr| ï¦ÛñÙ sÎñ`>ƒ aj¯0ãz˜ŠR"•\ü,]@ˆH-ÑlºöSWÍáOö õü±‰oŽ3¹…æ'Óä0ßCcy P ;<…fηpcc€cý« Ý»€›”迵ÿ? ¹(D^p„fË£o}pH-`>hœÙ´¯ Aò’¥€…ŒMs{> ðW°í§ew„kÄBã`IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showqq.png0000644000175000017500000000140614507760372022273 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 55³£Ã\“IDATHÇ­Ö_h•uÇñ×9;´‰[Éбœd6i&aަevS†7B¥BºÌ  ŠR² é*´«d"Aˆ‚’)kP'+¬¼1â4•:†ÛÙÖþê9§‹ç9ð0wŽÛÑ/üxàù}ù¾ßïóùüxÊÌ2Þfn GšH^%õ°üølŒTqw!ÝóãN‹å—)!–ðS-ï¼ËÊ o.cóK\ëáöc\ã^#O?Ks3UMÔeÙØÀæüÞíG@=—†ØÚDuK™û2ux£!èèúnÆŠi¥+ í'˜ÜÍ‚ùSÞá#£ìŠ•ÚÁ@ ×ÛhÈÉ¡‡án’|x˜®D©€4[6P—/~ƒ‰s$9ø!OÉ€'ÙÛHeŠìn¦øz‚O¾`"šWÒˆ> ¥‘Ó÷êã‡m_‘ž.wZÀ6ªÊxµŽSÈNÝÿˆósˆ °íKúЦ`»ùþ êïÓ^ɱ.lgñLjuò|>maA—H_æÆ;Ó;ÓClgñ"^H2~ž[iÚw̬¢  šƒI°¿Ï¿‰(ã‘m”òË;:­—1”£2Œxèx¸—÷I&rd"nu_´ƒ|¡X¤x<ËE“X!>“¿’ÿ¥áÁûLÁ¹FIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showpp.png0000644000175000017500000000133114507760372022266 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 6MîÑ{fIDATHÇÕÕ]H–wÇñÏsçKNóQM§eC 6ª5ŒŽÁš8:£i ”;¶ƒØ1g3„µåöBìÆvPDP;ØìÀNb'© !iÓ¢²…é¼wrÇóÓGÓ=¿ó8(;AK1…‡9™?};;k‹øv”ÞAz.óó &ðj¥m°j}ÏcG’ÒbÎ^ÈÎé. 8Íí» üÈèfxô~ÌP ÷×0ÑDéYÊ>¢1îåº<’-t¤²sîï#êc°ž¶w ogÓö6C/“øŽ 5“¾œïG²»âæ Ÿ|-ðyîuû‰°qŽõ ÃAY¯×f'”'¨j"ܘ^;0µ„Aœ Òô©FÖÆ­yQœ´«šŠÏ–;-91}Më¹qþ:$(yH}%Û“lz‰ÎWhÿm©a9oqñ?œæê¦Æ¹¹›_öÒ{‰I¬þb9r2uŽáíj%Oo·Ÿá`WÞ`f„£ÍXƒ:<Íx‘[cô—c ^ÀFTf܈ÿ)Î@vaÇÉüx8“¨@jP‹uxkQм¸áÄâ ¿7)Ý‹=¢'O¿@ž‰G¹ñå·Š¿ÿ¢¿&ž¶0¸³T â®ÈK 2>ž)pw©ÿý欜²²|IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showalternativeflags.png0000644000175000017500000000151614507760372025207 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ /FþptEXtCommentCreated with GIMPW¶IDATHÇí•MH”Q†Ÿ±oÆæ#ÃüE3M³R“\(Á”‚¸*Ü$jAF¹KÚæ"Fˆ2ÂE‹ pÄ ‰ˆˆ@ÄY¸˜M2¥N£ŽåÏ|Ÿ3ãi1š¦ Eâ*_¸\8çÜ÷œóÞs¹°‡ÿÇ€ó€yWØçÙµkHQVÀ$î”sßÚn¬ÙÙ\¨¯ç(pØj¥ÊhÄ6:ŠXüOme% €2?ÏW@¶ISW‡çí[V4 ™šB&'§pä/ }28Èjc#ãf‡²¶g65‘qîz“)f,+ãˆÝŽ[ÓX ÐÆÇ¹ÈZ÷ @HÈÏG—™I*˜’BŸÅ±1ZàJR'M&LÛú®…ÚZNôö¢öôpÿÐ!,¡ªÅÂþ¥%;;ù¨Ó‘¯×ÿ’Kå娫ªP[[¹¬AAIKÃ`6£‹§Áò2„B`0@8 ŠÑ(°b0°//%$ªª,/,`ÊÈ`uv–%‰ÀÄèõš_èpü~X]Å™· ³ªÂÂB¬£1V>âv#ÕÕô54 ÃÃH$‚ˆl¬h ‡¯).¦·´—ËÅÜÜ23ƒøý±˜în‚Íͼ¸u‹©þ~¤¥…W”—󨤄;Éɤ¥§sµ­ ¯¦m‡BHEß\.–‚ApI¹¹Ü½yq8/(À§iˆÃÁ Çfc°« ±Ù°nU!¥­wª#w»‘ÂBÞN|ïß#Àõà¢">Ûí<z<ÈíÛ¼÷'pPÙšáËè냚ðû™F¹|ýšÓŸ>aú×c½^Îx½, LN2¬Žx÷¨ÏÉálz:χ†ŽŽßÚ~Àç\Ö‰<ÈÊ¢âOâf´ lKðOHˆç‰åN¡Ä±kíí0=P÷~±]ÅO2E+¤7ãþIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showoriginalvisibilities.png0000644000175000017500000000214514507760372026077 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß !ÿPòIDATHÇíÕkŒUÕðß>÷ 3 „œ1ÊÃ(ÚAG Nƒ TÄ4h”hlÕÒ5i'1`Ic4Äc!A¢‰­µMŒ‰ÔšÚ† ‘ò¡ø ´EÕh4 2>xŒÌëÎÜ{¶<˜!±ýhÜ_vöëÿ_k¯µþ‹ïÇ)F8n•iÁ=¸¹®*¶¿éå™{4ê5zD¯Ç‡÷yrI¿ÚÿBŸ‡gÑ,ØÿÃ7µœû¾›bB5!Í]\Š>ÄæS¢fÎÆ¥ØmxÍJV·ïö‡‰Ù7Aß3 ùËB’œ4·l(ίÎ3ë¶6Í'¡Ø€ÇјȔñGLÂß,ww¹Û yP=ís¿84Æ3ãèOÈ-8†ðë)î,ñze˜}×ÍqþëÀ4¼„×,Ãll•¹aî5Μ…®ÁÄv÷ùyäÙÏË_ì±Î€$Z‹8VSà3±½X!Ó—`Kñ¯·Bž¸>R΃-kvù¦pGÓ¯¤5ž¾ÚcwM5#0 •¼“¯=û=êñˆÌë'dQÛM&5 Ø9ºGËð>S×ýÃû°¢Ihìó»1Ýî|ôFµì½r‡éÝþuh´Oû\µþR/ä‰EØ=u¿K:Ç›ÛWïÝäøéZê¼€–Zðð1pXþ™èŽ(÷(ìÕšäÒƒeo÷×"I´H°'ÉÍïn´=ОÀ¸¥. ÑfA{äï[7ºë$™ÑS+1ãëÎ< 3­ñÏ6‹ºFš]œoÓlÎä–†èÂmJrMÓåæW+^Š ‘×vM÷¼Ì«8ëñ™®Žs>Ðux´ÎJ½‰MÔwÞ{êk%ª+ü¨u±™ý :p´T³²¶J%ÁQôæ‰5{§Ù1Xç9ÌB~‰N+]6|ÀaQ-…¨m°d“Ì„¦#þSd“$º=P¬=ZvXæü¤Üm§hîÇMêå–`®Á<ˆ5ëÖÎךD=hHkþô³‹•ó ,ê™q³æ´æ6¹#ŸŒõ_ƒÞBGzða¹Ìu¢Ÿà®–}à2ƒ¢{¶¶ë¸âU#Fô“äv¥UÛÓªt0Uøb\·MGÕW†YƒUÇj!)dâ·¨áÇCÀÉ™{ñh,³úvƒGFYÕtÐU÷wê Á@ öã´k Ñú&úiñz5ö—Ì3ó±Tfãqy³­˜çÙ,šÞßà‚Wf«¼¸ØSÖ©þû€œaß` ÕÔú]Ó}VM]‹÷p«L%–Ž@ŸLþ 9 »1¡C¦vùBaëÒ宬•l,Šw†Ì['öƒSËð$ìŘBsþŒ‹)ôˆ[dÖœ¼á|;’Y…Ç»Y(qáÕC¯'ÿÁ˜ƒç1à ¹?O~÷šþ—ñ€i¼SÂ’IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showqp.png0000644000175000017500000000133014507760372022266 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 6ÉP¥eIDATHÇ­Ô_h•uÀñÏy÷ÿŸäY¹ ”ºVƒéX‚]Lý/òÆE›ÕñF‚Íçfý!‰']­ *JhØ…mŽ„,AœŠ¢X³EC]Ãm07æØÎÞ.ÎÌu¶éÎyàÇûð>ïû|Ÿ¿?²"-uÄ‹ÓYr2wþI¥íVÐѱÐd(ü€×Ÿ¤|ñ§eW>-á«¿ CFBŽŸÌryÍÔ¬M꫱îEZ6d)úx1_ö&£Ÿ;“!­¿f)ƒ'©Y· ذ‘_Í0úÏŠh›ýpÈTJŸ9qxÁ˜¾v„—v’øi€®!®Ýf4Â3%”•pg”ÎîÈ j_H´ŸŠiþ=ËÈa|ã$ÚšJî>›¶ûX»ŸÊô€àMôn&öñ¡yð›Ävñç"íÜß›>F‚ÿ4q¾žê‡­Ç Òüñ#ñíÿÿCN°`6 ¹šç·ñóºßakÒ›zôrîN,:¦Ÿóí%úv}—ªíœjârµÓ±¥ö çˌ壆ò›jù¾™«1^y@î>B^:ã8~a¬šUò±èV¢çø¦˜þ!êÚ–Dè™%w‘ô"¹ÌFÒ€˜çÖi†‡é} ë‘À &0¸äâ—iÛB)Lâ ƒ7øã"‡ãnjYs¦œÏÆñ w)@U”&pÑnþ¦¡•+ß•oóÂwÜ;ÇäûôdÏJü,Z¢÷ø=Ÿç¦8ÚDZ“ÉÔ[Ò–¨ž5ctMpôëd³V, 8õ R R¶¹æÍ.83xš”Ärä£h 24HÌÓgRßL-øE˽'­ƒIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/lua-editor.png0000644000175000017500000000213214507760372023013 0ustar olesoles‰PNG  IHDRàw=øsBIT|dˆ pHYs‰‰9›p¶tEXtSoftwarewww.inkscape.org›î<×IDATH‰•AhgÇóÍìnÝÝãZ7‘˜Fm0„6E¬5Hç`{ŒÁ¥'!mÕCpú:«H¥¤…ŠW“"HÁË"¢Ä’–˜Zj[ª›5¶vkRÝ™éag’n6ùÃ0ï{ß›ÿÿ}3ïÍÓ¨‚S§N-Ëçó)¥T®ëSŽã¤û@3ð»RªÅ²¬ájZ%§ˆ$$°BD~®F "«•Rk-ËY’€ˆD•R›^ÌL^êÁðaù$ô=«&\QÀ¶íÎX,vóðáÃÿ¤IЀ¿x³,Þ¾!q>™^T@DšDä^YÆ»€3@z‘$'ý *mª2;9g~ö!ðM5òõëë8xp {÷¾VêçAúLÁ¶íMó3—"ˆ¿ÐÕÕõµ?=]ðC\¿>îG£™"ÈÎåèÑ£kgOày^. O§Ÿ;Ù 1‰Ç#³ëŽŽFzzZð|^àû~\D eÛö™,…j€újä©Ô²|«VÅVÃûŽ9rhR†aÜ ó{#úiÞzfÆáâÅ_Ãå{¡¡ëzÄ( ¯ƒ:ß ÐÐdÆ•\½zJ8~ü*»w·155ƒH–;w‡Û[` }Ï4M{jPj}@o€¢°n]ÝÝp]Læ ™Ì•JÛ þj›PJ© ‹þÂ/¥ôaËm¥4Nž|—sçöpöì.¢Q½<Ü îyåyÞ£’½2G©C+¢½==Ï®­12’£·w'O ´¶®*'ŸPJ¥”Rª¶äï{F©ý«B z¿Xôéì\ˉïÐÖö2º>ûS¸RÐuýO¥”Ê—=?ñx„t:A: ‘ˆ‹éÔÔDÙºµÓlf|<Ï¡C—¹?*£ …Žã¤õ®®®‚iš¯f³Ù)Ø1 Ά¡j:;›0ÍfL³™bÑcxø,ëm§ÈØØ.]ú}ûÚÙ¾}=££hiIqíÚø$އˎˆ4ŠÈ/À±cÇúûûÃnÞ œg‘n®èùÀ¶í×-ËSÁQþ‘Ž@àð1s•°Drí£\DÚ-Ë#ÌRDf€ïƒIÈÐä–@>QÊüÓ/CG$yڳśÍf‹¦i¾•ÍfƒîÊÞ†gÀùX¬an~xÀ о(½óþ[A¢qÓ4·Y–u+ä­42)Íâçï Ä üÝ\XŠ!lÛÞæyÞ"ò´Ü_qè¼áyÞC™X( “ÉlÔ4í‰ëºž'¯*P&´Ùó¼q`M$yà8N x ,7 cÚuÝœÈüÓ”ã2ióàêIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/24x24/actions/showsmoothedvisibilities.png0000644000175000017500000000144014507760372026112 0ustar olesoles‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß *h։ޭIDATHÇíÕiˆÖUðß;3”¸•K¸!-„hˆk‰4¯B`ØÂdN2¢Ñ‚!Œ RyÔ)*5ˆRAÁÈr´h±¾˜4Í—Ás(*HKEAg„šéƒgræ-­oÑ…ÿ‡{þç>çÜç<ç\þ_]¬B§]‚%¨NËf¼"ÿ÷Bïa0~Jë­8j¡ášQÃ0܇Cei÷|5&å· ƒ°E˜p‰õè^nJÃ$lªJ²ÙŒ™ø•ÂÉ.²‹±W`a‚ïªò6c’¾#BµÐŠ'Q/LZ®>µ¸ˆBs¾ÄTeôgÐ'œêQƒ[0Û0­¸€r¬Á¨ö–yžÆ%lD3žEw|Šy؇X†eB[‡óáÀʬÁêBþœ7ñ+Ó>c(êð9v ' Cx M™à¨‚p7ve¦•‚_Éì.ìG7<‡ƒø:©8ƒ¾éùæ` &b¹°´ /&xÐ(<,ìNkq÷à7¼ƒÞцݘ.܇0?ãõË5¸\ )Õ•YäVœÇÍhÁƒ¸#y½„‰Â7%7½7)ì“þ'ÑZ® +z7Õrsñ6ΡbNå~Š¢­\HðšF¿J_|†òö"¿€å8‹qÂ2{9çÓiŒÌî~ð FcxÊ´.}Ÿ½0¼<ëüŽ)‘Nú;õGU˜žªº3•Ó;9IxMÑŽ9uØ^‘êøK…¦^Ûu^›6#e;-o3(o²OøEX„±ø«„¶vŠz 9GÂÕfL¯ÔùmX‹yüÃÙ#Œÿõ=èz ıTWm¾e˜…7Òk¶°éïœk 2>%Ý?©è™ÝÜ‚ç… ÝËþA€&LF=nÇ x ÃRAÿ±õÜ‘¾ ]Á»IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/scalable/0000755000175000017500000000000014516225226017557 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/scalable/apps/0000755000175000017500000000000014516225226020522 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/scalable/apps/aoflagger.svg0000644000175000017500000001070614507760372023204 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/apps/aoqplot.svg0000644000175000017500000000726614507760372022743 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/0000755000175000017500000000000014516225226021217 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/scalable/actions/lua-editor.svg0000644000175000017500000000733714507760372024025 0ustar olesoles image/svg+xmlLua aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/showpp.svg0000644000175000017500000001407214507760372023272 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/showpq.svg0000644000175000017500000001412214507760372023267 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/showresidualvisibilities.svg0000644000175000017500000000752714507760372027112 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/showsmoothedvisibilities.svg0000644000175000017500000000726314507760372027121 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/showoriginalvisibilities.svg0000644000175000017500000001026614507760372027100 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/showqp.svg0000644000175000017500000001412014507760372023265 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/scalable/actions/showqq.svg0000644000175000017500000001414114507760372023271 0ustar olesoles image/svg+xml aoflagger-v3.4.0/data/icons/hicolor/16x16/0000755000175000017500000000000014516225226016576 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/16x16/actions/0000755000175000017500000000000014516225226020236 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/16x16/actions/showresidualvisibilities.png0000644000175000017500000000104714507760372026105 0ustar olesoles‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß 8°B«´IDAT8ËíÑ?HVqÆñÏï¾W•ÊR4-‡ r¨¥A¨%2Œhj¨ÅÉÁ (É%l KÓEÛª©ˆÀÑŠ2Z’† „†–ÈB3Ì^3ÿ½÷½- ´7ôlÏÃ9ÏóåŸÓ™C†:êe¯WZ(Ö´‘ŸkÐ~ºQߟóñfÓ|TWÈjݺ µdIcœF dòOyÿú€—ëùL¬Û–Qº:¦f¼ŽÍîíÈ2p[ZvIZ>OxC¶„©Jw7ݼã ªfÕ$j'ª]D2W#»”qÿÈ[7Ë\‹•­ØY3cx¢Z_é’ÝùŒÒ5m *çM•e½qv£~°Ð\”Ꜭt9[âÑt…¶¥n=ª·ªÃçïÛLGÅWÌ+i W´lþIH}I" !Uç<ÃöÀ̾Ú8…TGÊãwU<µ¶¹ JçbRô4†$‰ì=™Ä•åæãÅÇÿ‚4Îé·Å‰8Ñù`$é ©W“Cz!è¶{Ö‘n`M‘G¢ÊO³Šäe »¾jž®2%§ b´ã<ÖÖ—RDˆ|Ö}ÞªÜt¹U9¿°€ÿå7Ή“¢O½>3IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/showoriginalflags.png0000644000175000017500000000074214507760372024477 0ustar olesoles‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ ÛµåtEXtCommentCreated with GIMPWJIDAT8ËÕÒ!HÜðnÌC-Â1ˆÁ 2áÂ\1 –?̰8]ˆéÄ|LCŒFÃ!† ÿh0^X8ôÀÜÁÂÂ…<ƒCôÐ &?xå½÷}<Þ÷ñ–°¼c'ðéa³ïÅT ïŸZ±RÁDq((X´¸Õ»3ŽUL;|-)ýü?[8rø±dé4DÔÕ ÷ìDR.+7¶´bÓf³¢óæ·ð¹¥»vÿvu#D45#‘œN›þ’ɪ.\DC#ÎGˆûÊåqè0::ú!¢¦¹g®¼a#M"‹Odå-㣔×#ÿpIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/spectrum.png0000644000175000017500000000231614507760372022616 0ustar olesoles‰PNG  IHDRóÿa„iCCPICC profile(‘}‘=HÃ@Å_[¥R*VqÈP,hqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâäè¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"€Ç„ÄL}NSð_÷ðñõ.Ƴ¼Ïý9z•¼ÉŸ@<ËtÃ"Þ žÞ´tÎûÄV’âsâ1ƒ.HüÈuÙå7ÎE‡ý<3bdÒóÄb¡ØÁr³’¡OGU£|Öe…ógµRc­{ò†óÚÊ2×i#‰E,A„5”Q…­)&Ò´Ÿðð9~‘\2¹Ê`äX@*$Çþ¿»5 “q7)œº_lûcîͺmÛvó<WZÛ_m3Ÿ¤×ÛZôèÛ.®Ûš¼\îƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}2ÔUê88F‹”½îñîžÎÞþ=Óêï¶rÂÛÑk.bKGDÿÿÿ ½§“ pHYs99ÂVtIMEä (D¸tEXtCommentCreated with GIMPW¦IDAT8Ë=‹½nE@Ï73;ûwbc$$E¦€"` !ñiyÞ)¯ÁCPXHÔ)o4A 6öõÝ\ïîÌ|EG::Õ3àìݯ^ |j«¼Cæj0g0ƒô¶VÃøæ»ï¿>ûòïçáôô”Íf³xúì[Sû‡‚¶†7 ñÆbÄë‚¢˜åþÏ€ça³Ù™Ùƒ«G®²(øÇ'ë×û–ý®áöŸˆÛ{º‹€(ÊËé„ϧª—föR[Iy¥Ü[î9îoùààš£ÃÿÎLiŒRC©a^AZÀÏw'ˆÈC'"Ç"ò@ƒ¶°ªGÖÕÈýf`]4ý„C+(rgä~Ž0³ß`ÀEè²I›9ˆ#ïÅ\¦2‡9å—›–²u¨‡Ò&Êï·kDgffF‹Ô¡€+—Y‡=Çab]„X(­QZú‹ÌnÛ|ì¼÷QD>êcrËz¦q‰¥K¬ÜÄI5rÒìhÛ„- ¬¡Kt˶3û)Äó4MvmVïC8ð ó#æ’Ywwì>¼WŽº7Œ·=îîîNUuˆ^ ¢x /…b xŒ>ÎÄ&Ó×3u(,ãLÜ Î¹Æ9çs½HŽÁ†p£¡4 *¢šé›‰¾žñ^Y†‰úZQÕ1˜Y#"ÙU̪0äÈUiaN-ƒ(Þº˜Pƒ¬‚ 4×…³³3œ™½VÕÛI ŠðFC®¹,C® µÏˆ@ÊžYñjâüüü3'"ˆÈ£IÅ*Q»Ì ½¶¥¢cfVq‹’Ч˜Ã_n1³ADEäÕ°Í?vš^3eþš^á*R%’f_Š”iôÌÛÉíªbãå;Ìì§"²‘øø‚·<Þ‘x |øßó/|M}G¾IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/showpq.png0000644000175000017500000000076314507760372022301 0ustar olesoles‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 5•zóð€IDAT8Ë¥ÒMHÔQðß̈ M‰E¤Å@›Vµ(h[Ѹ Z¹‹(CZô…ÑÊʘAÒ" rÔBHÜÙÆ(³…JÉ B$} X£¯ÅLÿcòÀãÁ½÷{ß¹‡ •ô9zޱÞÿ¢›{9ò]Ü>ɦª ÚÙ:ÈÇBŽ|7½§HC,Z|ºUtFãÙÕÆ(â SÏé‹tígìÁQ7’åÑ9b`gÀ0Ó¯y<Îñ²²l ý£Üìˆv¿HË[~ 1{…3lYâ§=g™-òp”l]yæ#×ì`w™î$¸?LÌn]ý9BcÍ•N”®Ìiš“Œ—B…4S#Œ§^±æ)ŸÑˆ%?¬E-¾/vÏ=£¸;ÁËŠÞ¾H£D… öž ¹×x7Ƈ äcÌï!3ÄÀ$Ââù q¾Lòf-çK+jåýv¾¦ªô\ö2 Õ¼ˆ[!âê±àSÍR_në°X=Oî'…z¤ð Ëü™mLkzIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/showqq.png0000644000175000017500000000075714507760372022305 0ustar olesoles‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 4$ÀÒï|IDAT8ËÓÍKTQðßm4QÈûB¤\E´¨0ÅlUAý—vj"‚› Ä’ DQ‚V ¹¢v%ÔJ‚iU `4`$.ŠÊšÛâ΀£Ù\zvïÇyÏyŸç9T@Çnòø:ûü/ÆyõœÜ=¦úhÚXK%pœÏ'¹|†özÂV:Oc-ØÜÜÍ¡€Ìæ| í½…_˜åË;$Z¡‹]ÏXÌ­=e>ÃpÈÎDîp{™h–åQ&¯±»T+[!$õ„¢Rnˆª,4ðá#ýc|Úö¦Tš™[\) ¿Êá~N ßÂY™ óDh<ÏÄ).6sð oXÇ~±ö Õøú×WL’Í-òsŠl†pɃnF7&ë8rƒŽšbœc}š·ß87ÁЬ?äEžh•h†¥»ŒP›H²4msä_³:Ât/þÕ¿…ÕA^î¥#}Ÿ÷IÿK€ªfj/q6¦AØi©JëÅ$Vã’Þü.šê;VÄr–áXy_Mß L¤IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/showpp.png0000644000175000017500000000077214507760372022300 0ustar olesoles‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 5©v7‡IDAT8Ë¥ÒÏK”aðû£\Ýi”„eÁRvÌè¤CA£“tËÓRA^…Äè ˆ¼ BETDÑ©SDTXÔE4£@!VbÙXw·ÃûÆ.ŠåÖÀÃóÌ0ßï|gæ¡)»yžÑ®ÆHlãà‰$™ºÇü›M±\af‰ëG›O$yòšZ-<Ó×IÏ¤×Æo] «ÿ&ø\d²Õ ÆÚØ?H&·¶zW?Ë%¦Þrÿ ©;²äãñz♎Ÿ ¼“Ì4O a¼/Kµ‡wX˜çÛUæ_Q=Âb[Zyþ>”W©qçv8Ø×ð¾HÐS÷GöF-ì¢÷@}³‡Žqãpú´þp‡gc\K±ç$…S3<ûHw;ÛsÙOŒ–Ë,¹7Àì^ö‘æÇnÆOE’Z±…bŠ…4ÒØ,å9Ý˹|Èù³ÄÙs)|:°G¹û=ò;X%(¸BÐÙÌ‹ùOK4ÜqÊI¾´`VPýAíèÄVÊ_y±B)õ^DåO¿aneã+œIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/showalternativeflags.png0000644000175000017500000000074114507760372025210 0ustar olesoles‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ  c¦tEXtCommentCreated with GIMPWIIDAT8ËÕ“±KBÆYƒ`cƒCCÃBˆ â´9ä¨-A8½ÉYÞ(!.‚£„ÃCÞ¨àøˆ„78Ïû~¿”ï¿îD.b4÷ÓðÚåbê9GY6öx{¿Lpcq|þ,?,–;}„Ãìo‚t† ®üœŒÒú†ºZæ6IïÐçà6wfþ$¨(%è ׯú3Ò_Ø{ÅÖ'rD®]MP=ÂÂ(]¡ ZCõÉ»¡ss‘Œ“œ\'ÕÍBÀÒ=$Sç<ïs‰R¼ÜækOx°ô‚Çÿ¢ˆ>e Ñps•Ì4r­‘Î Ú¿³<át5g¿Uø‰efyŸü.ùy¶F™‰Ó½vâ-gÜn¡²<Æ£5N?²;Ál‚úóD.‘-ÉJ-Çßg½»Eº©éçaaµØEŒV¨+|d$Ê2‹ ¶ uQü„ufuïÃåIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/lua-editor.png0000644000175000017500000000134214507760372023017 0ustar olesoles‰PNG  IHDRóÿasBIT|dˆ pHYs[[ÕcjtEXtSoftwarewww.inkscape.org›î<_IDAT8m’ÍOQÅÓy3u€Ú”k‘@…°ÀX6$lÕ%,ð?pkØ`Ó˜›ðÑqÁÂ{ € ·îX%À‚@ÀD¡@ËGô2ó:­ š‚£'9É˻眗{ï3ADz×¶mÓ÷ý˜eY¿µÖpO)ef³Ù𧉅……Ç¡¸ö6Ãí°Ç¸SL‹ÈXJ‚ž^ÉFùøv2…nÍ2|ÞÅãQ&&zX_?:)½§ðæ[3@Dº¢ˆ•ý=lnk³ÙØxI‚|ÞedäýI± C¦¸¸¸Ø±,+ôë°`h¨“þþ©T££©$øó@Ý4M7bšæu£•ÙÿÌ•ÍÍS67OØÛ;gmíÆ|PA´À²?98ØÎØXŠÕÕífÀõu•ññ ?`{»@¥¢RKAp_i­ÀˆD ,Ë`` A2ÙFK‹ÅÎN‘™™'LOÃÒÒW®®|À«W«Û¶K U5á8ñx”öv‡hT±³sF,fÓÙÙ¹\eF ¨ßì™WSSiG±µuÊädùü½½qººZ98¸üØxÇVžçµ—`çvwÏgçæ¾¤*Íþþ岦RÑìîžãº>ŽcåÁÎ5~¥ŠˆÈ/éƒL¡V3ž—J^¾TòкÆÉI×õ©Õ껸®X(”ŸAæÌ4ÍG"rÔìYDÒS'È;#zƒG oa¹ãom"’^YY‰ÞÞä7l› B‘n˲¥TEk}¿Z­Z¶m_ù¾(¥bÙlöç]ý=FùލʃIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/16x16/actions/showsmoothedvisibilities.png0000644000175000017500000000074014507760372026116 0ustar olesoles‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß fãÝmIDAT8ËÅÒ1HÖaÇñÏßW—ˆ"(([£Él "lx¥^¢7 ±"Œ¢©AÃ%/4Â"׊2¬!*ÁEä%\‹‚Šjih Z^„›ž»çùÞÝs÷ã[±| ƒMïºpw# J ßÄÆñÊ6›3».æ•uB¯Qfòò(fqI¸¿|±³ê¨c&¡VT±÷°_x¿nÃŒ7Š à¦ÑÀE\Eú±Ih¾cóØVx‡ËB-öf² na^â$~£7;îhÁ#L 5á•ð Ÿq opwÐ…!a+^`RøX%ìÂüÂÄ ãT¾iÎ`!;êGµ9ƒê±ôÏâ)Nã6và ÎcKü‰¡’ð í9‹%›óAÙ"&q$¡žüî!L¡M8׊>l_c×ãÂ,ä2~'°wµ”×WÜ×Tì0Îd'}ÂchÙ€Ü;ñ ϱÝMøŸØ_z”\Ù·‡IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/0000755000175000017500000000000014516225226016572 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/32x32/apps/0000755000175000017500000000000014516225226017535 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/32x32/apps/aoqplot.png0000644000175000017500000000234214507760372021731 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝ :å-YoIDATXÃÕ×_ˆ]Õðß¾÷ÜÌLæÿ˜˜kl3c¢S§¦&“ 6«¢‰54ˆ±¶ÛÚ ¾´PèCÄk-H¡EI Ñ€µyiÔö!Á"¾¨¨A‰‡R$´IF¹s3Îöáž™{3¦ÉDãH7ÎaïuÖ÷­µ¾³ö>üŽ[¿Jç½s°‰XûU8r’õÅAÄÈéÌÕ=_Œæ“ØŸ¿¶‰–iÆ{§›À_¯iWÀ¢¸´“+ŠâõÎÅݧ+kW¶ˆ»¿#➙ْ¢’JÎÈfv¾x‘4nǯ–"EË—ÙýŸonpeGAXöw¯+yÛÑ^—«ÃžUˆÝZÅêÔ‡ãŸU‰´aâ |«·Ý¾}[­ˆ-‰ gFí5’Q”~0ÂsCuaåßxkØ|8gÔÀÂ\äW\*jáºî <Šðv\…í‚ ŸoæûgÚ«ùùíe"î<¥°«žÀîÐÖ`òã’ü/Çx(7ó¸T·û )e/|ÛVvYX5ùIÊ“¡*ã|I%šNÀNÜIkƒüžFªd‹“xتcËÛú~ÝËïVWkóTàÜlo¢¥Aã'gàÐ"/âvQTr£l­ÉqÏBŒ¸ã8¯¯¾µŸwŠ™:÷Žó„«úÀŠ“‚W ìE„Ž=ä†/Ëô)-f}·ˆMÇq±ê‚~ÎëâÕ5›qËp×IÁKîÇ"QèàÚäº_`GkZ¸ï< ]B–Œ†zË[*Þš%ìî­‘¸q’Ðü?6©ø9¸wZâ'7¸«W×£•|ÅEŸ#Ðß~Ö¨Ûª×MËùù73SÄ{Ð>k3«/Á`ö9‡—×ÑÚ…„œ\ÖnÚj×m›« u®¶\¼M5›ØÆcë¸`ºU%¸Ûó³€)ÀÐt¾\Åw»3?ÂYgŠÞ­ÛßûöÓw¹Ç™ãd< Ó™ò³7wíbøèŒG±³êÞÑ.VE·õ캖 6o%œU¬ˆ9ò­*iª Ï<ö'7ÿâ§u½q‰”®?2:0ÓĦûgà¦^®úYÆ6ßH(Ń9:ylîhelLsCƒ‘Oˤ©p¢¯l"eý}â Suey× ¿èÙ÷–\Ï95ûBÂõבLE>¨0:ëˆÑÐÈØ˜½<- 9~ô³Ç– oló{;<ê5žôàÊ ]ý‡—Dü{¸f›(OL¥ì?ÌØè¬ýù ñ•-_ÚÏàá¹uØÕØæÛü§±ÉŽm‹›¶PÍ‚¨ù$#0™¨”g<®ÖÝÌþÿÎ)x° ‘bå=«ìøÙo¯{?8¾m>©j&™Š¼„ñ±Y%è¥>µÃÅmONñÎЉmÉÀû‡™¬ÌïÙ>ä§3• =:ÏyÊãY ö!ÿ ”'HbÈû´¥‡$ç ’!‰\³/alr~ $†I$ Xñ=Êó\ƒ$OóÛ‚|.êYJçY:$ óëüÕþ Wçfº«´¢MIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/apps/aoflagger.png0000644000175000017500000000305514507760372022203 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝ' †ºIDATXýÖ}¬×Uð×ùÞ˽—˃—À˜ˆ EZH2&`D”ÅB¸Î¨CMØò6Éðá‹C7)[›Ë ²\,mÌBëb% ¬,£iòt—Ž ÷w¿§?~ßßå'O!Pg;û>œs>Ÿ÷yÞŸÏ9ÁÉZêR|C4*¼º`­5m†Ô¶èߣ`ûý‡|kU wµ8§Nâ|îD…ºÃ\·I¬îj›éÑJm3µ-^_\0欼¦zI5 õ¦!"„hëô_WÓJÏu‡ ±ø^[ ¦Õõ•™õ ÏÜ1 ÆÛx_OÊW–9?(qѵ›5dIÑé–1¯¸]|ô6ªÛÄÀœã/aàÍWúÌøôIlÌ}Ü„>‰©z,Êþ‹= ±½Ò=1xw×Ó.PPÐ&¾1´‹¡%Û·ŒäîÁ¦'ÑÞÀ_gŽ·cÝïO°—æÌ?&µ'ÁEx¾L#E>Sï*ÔB–X1l.*P SÉö“;I¢ ÄFÕOrO×ÎS}°2_wHj1$¹ó˜Û¹–!¸QFm³'ßü!8€Ë÷õ*:…$²x¨‰R–ö7BÔ½ËV ž„ú€)ù? &`—zUÊ7©É‚¹ë×üE[—¡j{FívC $Ćq6&z¦æ´„<•ƒ¸,_÷®Ìy{Fj[9€V©ñR·–è¬ì´6äiƒ¥ÓËÅôMF½é·YBFèsDEÖÍö$3Q(&o–øcW4÷æ_ï[fVÏE¾ ¦’””Úˆ9æÇ`z¾ƒÍë·ØùÜqbºïFÈuAµ!핾,’Ðh©ì»uX#vQ?¶ßmæaqrŸx`¬‰I¹áKøZ–Xˆ1 !S?åšS§uDeMÔ5cÿÖ`Õ»ÌÌpLÔQDÿ­±"Z# h‘z9©º·8ócwz*ò}E‡,1ìWÙ°ñC9|B½ö%+ÆìöF¡Z¨ÈÄC|¡©§zQ–±-ó– Ï E I¦ÞT¶U¹°f‰—µ^*¿ƒöë¿~²F[…~ØŽï‘Ƕ¸ýP×ÞÍ™¼ØÔèªváàÅôÝUd§­›¤óa— \H¯Ù¦¶D_D Ñ/;öRQ„Ñg#Ã1²÷`c×Oöw<Ž©‹[𩟗ðN¤*KÌG(TÛa©0îuKòJ ö=A’yV(fISO7”XMðŠÔ„ÓžçÅÞˆ‹‚:ÓÝígåÓæŒöÉBµÍÝi®áh¼6Æ^Ìý4HM;v!Iýs¤B—“Ó_*úá½²]•gIW›qµ/ªÝ~¤»m[æXi·#eןJt8f¸§uþañ«ìï ì-­¯ŸÄ ›ñˆnÚüä`¯Á¦Ò¼pN7ÊÔ4äLE_ÊNÎÔP¼V¦¯ïHÝqúKéG±ËsíùÉ׌ÏãÆ²0ýTêÆÿ~+>;kñ•“œU%K¤Vœlirž|³ò—oîY 8•óS3Æ*<˜SÚ [ÏH˜ÅÞ½òT-ÙŸÛ: Ë—UžÂ\uñîþ…­g˜¤Žæ‚,o¯äÏå¸ÿ£†àüè¤ØÚÏFþ‡­ò æÌ“ÆÏƒx®Æäýÿ Ãû8ržÿàøÿôìwä#ê~IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/0000755000175000017500000000000014516225226020232 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showresidualvisibilities.png0000644000175000017500000000210214507760372026072 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß 6eÌä€ÏIDATXÃí–]lTEÇ3Ý-wï–²m J[ˆøD4cÅ?Ò´&D$¢FcÔ&¥>Ŭ_(MŒ ¾ ÄE^´Á¤jЂ_PÒD­6)ÒHÑ.hKiwï¥{çøpïÝ~ØÒŠ1õ¡'Ùìó?3çÌÎ930+³2â¦côà 4Ø.kã.9̳Ú,—õéœÈþ‘åTºE»Òò¯¸«Š¨íÐm»,°°3`;s îÎŒžS¿„ç94fbžÃÉ£ )o߉LæCOÝ^Q\‚€€'Ð |âF³õo á¶DQZ–¢ñ|>"“«ïd‰ª´¡ý½v–†Ø–Ç*”°x(Ô7Tpħ×hÖò6p–" ü,`˜$M’¬*‹Pˆ"~ºƒå¥§!âAómQÃoÀ\ ¾ç0Ô~ùRöÒ3ß§«í \ÓÚÀ@?W ‹Hóã{ühŠk€—Ç@Åþgÿ\ø£˜2¼øx¹¿ø°F]Ù =ó<¸´ÇÇ|è-†ÒS Ì¤ì‡G00)KaŒF#pt½x ùaáÞÉ‹È*ÃRQPþ;)RžbU_!ôrÌÎU°Ðh ÊÃxx€ 8JÎ3¤³€"IÈ$w|+î£ÏrIØìùbâJy'ŽØÅçOf©~½„Ïp(m›Ï3qª‹5Cìk»Fɳ|êXÜ>d± B’þÑà²õ¼`\ 0Š×&­¡¸Êh.8åÞhø ¨h^Y=ë\¡%´Ž)ÃÅRc›Ãq˾q¹1VNérEP~w„žýgº‚L“ €û+Qy»Â"ÑÂÝ€Âbñ ÛäÂî”UÔMÑ#NŒS­T>3_ v©Ð íj>BùJíñ¢÷ ÇutÏ¡H£FœÅšÙ}Þ*üFòÖ<žVA–*¡)°( ìÎ,{€ëµ°.Ðõ6úLG”pÓ¨] eáºÖ92+â§0` [BúEñI.FuÛ<ÃþÐF{#ù¡•°Ȋ⥮t윖s²p ì€Ðxk§4¢8!þÿµ7ײ‚#ÞO½Ëw¹Vì¾Á—.Dþá5º1CßvÍ7À-!ýZ¨ÕËö+X Ä´P¨SÝÛxlÚ—ÑTRbX%pD`PV¿ù+‡r Çf Ž( ÞÉÊ/è=p¡R]E"›Ï‡i‹Öowó*Ib@¨6‘d±"IÐØ3ð ºU™rn€ºä^4ò;욀&’ ξˆgeVþò8 Kmz#^ÚIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showoriginalflags.png0000644000175000017500000000123414507760372024470 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ $µ@l—tEXtCommentCreated with GIMPWIDATXÃí–ßQã0Æf(À6œ:ˆ¨ÍP€ÓéÀt ë %Þ T ¨@®»‚Øì=DÊ_’ xȧÙ{½–¾ý' Î8ã4¨4Z4Z€ê;¸ŽNN»ËðâT RÒ½ì.¾;W»TAÒ#×P€9t]Rʌ٧9, †5 ˆ44RRJI¹užmH ê |TUAÑX¬þ³b¦˜3玻OS`ÌÂû/ÅjϪ’Ò)”{ÿ›Õ(®¸ò&‡%É`D $¬ÃE]8‡ƒ‘Q]¸Ž.Úu9y߇ÚñaAœ¶f@À‡P/âD/‘LC#•å˜è¦…£Äÿ&L˜Þp#·"f±²`!‚ÈŒ™X¬TT;'Óh11ih¶ÚŽ¥¤ƒ_ë’àùÏØzú­†»¾ƒp™^²L32zúW@y¼Òhrò¾£«32ýÄSÚÓSS£P¤¤ÔÔh4S¦{-ØÒrËmÿÎ{½Væä ±ÊÇ];£U[…B­Ï~ß:P—K–ó„ÄÀ:ÎmK;&ÿ$âuèXB²ÎQAažy>*5ÆbÇ8è8Þä½ÇÇm¹øM©zä±ã-Då vGRRî¹çšë˜Ã¿áýjÄÊÄnÛåäòDÚ¡—±s¾àhÿo¡cÔùº|Æ?­&{‰¬ÀHIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/spectrum.png0000644000175000017500000000502714507760372022614 0ustar olesoles‰PNG  IHDR szzô„iCCPICC profile(‘}‘=HÃ@Å_[¥R*VqÈP,hqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâäè¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"€Ç„ÄL}NSð_÷ðñõ.Ƴ¼Ïý9z•¼ÉŸ@<ËtÃ"Þ žÞ´tÎûÄV’âsâ1ƒ.HüÈuÙå7ÎE‡ý<3bdÒóÄb¡ØÁr³’¡OGU£|Öe…ógµRc­{ò†óÚÊ2×i#‰E,A„5”Q…­)&Ò´Ÿðð9~‘\2¹Ê`äX@*$Çþ¿»5 “q7)œº_lûcîͺmÛvó<WZÛ_m3Ÿ¤×ÛZôèÛ.®Ûš¼\îƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}2ÔUê88F‹”½îñîžÎÞþ=Óêï¶rÂÛÑk.bKGDÿÿÿ ½§“ pHYs99ÂVtIMEä ;- œ»VtEXtCommentCreated with GIMPWïIDATXÃu—Ë®]Çq†¿ª¾¬µ/<çÐ )‘r˜ `–•ðÀ<<ó#ä ò™eÈ™hàld†á‰Áv„¢Dò\öÞëÒU•ÁZ<ºY@c½{­úëïÿ¯ê–ˆàëÏOêßüc&ÿ5¨ Û ¬k¤b‰ˆenᎠ„Ûú%Yß[¿¯Êl'ûwÿçï9"®2ßzêƒÛ’ús" %ì;;ăP¬èi<æˆ9ÌkФ0LKÐÌ—µ­A­Èñª}ú‹‡ÿP«üøáLzï7àU9¾“ÏàU(×Ð)HS sK ë”z5#Í ‚Ž Ûâeåºó¨UniÏ ;zw€í?û;äND`pøƒ&Ð9±uôyÆú ”4 åzIÚzè_$ò‘eB„È'güðÃÿ§q'€,Ž£$YN=Á—^°,”*†£d5j1Ì•TŒ’ %'©³IiÑ(}ôÑ{Ÿþùã×h ·{`.Ì¡ åèD*Ž…"âdu" Ô¥BÚÚ\Hâä$É Ü|üñÇE_„Û‘ƒ $×vŽ…0…rŠ„…p㕃ë¢@6i¦¬õ`SgºÜèòâ4PuúÔH§ Ÿ‚ˆxjfsþ ØO3¢uI¤¶žK¥Å’9ÀÉ §XX$”%@–ÀÕÑÒHê‹­-£ô¹- OK“»uˆ<‘)5=—¤£H,ÝÌ…Á2£'æP®¼gˆÌeÛpå•c+Œ^¬¬siÝ!±ZøÕÙTÈj̞ȧì펻û•™ î~t÷çÂ슢ÁuÌž˜=sð™çó†ç¶¡YbôÌÉ*„Wg$ñE¤.xÍ”áh…|4òÑQÕ­ªî_¡h0‡²a¡j¹†0Fa å`•këP ÆHŒ–¹“—›A„P“a–—“ufº|#”|lˆxˆ€‡o°ˆ®¤F)FQ§K„sò‚àÌ® ‘  x(IŠ:›Ô˜,‘²ã+·,`ô0¡š'à—=º-Å·#Z(E¥4Tœ.Y+ëi,þ?yY,'Ng«Y—ÌíV¸±ˆ@z8<~üø¶ÝÞþ7ÜËäŠ!$ ”€Ü…mKfÏ\Y@[ö_–ÌsGŸÍÍevE,ÃÍ $}³ˆÈQDþm)Íi>µÌ`°Õ‚“.­#éL3årîA`Ž„#Lž×Ëd½)…஄ æÊänn¾ÀÝo^MÜÿÛŸÿý‹cû—'Ϲy!üÏgϺcÇV®òÈu>òÅËgD½,—CÌŸ>¹ä‹›‚ö^¯ºk¶c·¹âò8á!œ®¯™Nt—_FÆCôÇ饊þëWý?âCDî×eßUÕºÎß‘3¹X·Žwß}àmÙŠÈ]¹»®Ýû¾Wàˆœ};Î/&+° àP€?swþ€ëõ¿{À?Íó ð0" èÖ.û«ˆØ> à üEDüvmû·Ïÿ,¿Ó|ÜËIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showpq.png0000644000175000017500000000177014507760372022274 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 7³MÍ=…IDATXÃíÖohÕeðϽws¼º¹Ô„$-† óšX‘”„‘EAï2Í4 Ò˜ ͺ¨d¹ úC˜‰õ¦²w½ŒH¢ò_å‚h¢’nÌm¹»í^·_/îov½ì®k»V/:pøñ<çwžó=ç9ç9'¦´Œ'g1¹‰“׫+€™´D9pK¦sîNü£šèº‹‰wrïMî¤b1u)Ö$éXÎ…[8™¤h ‰Þ>ZA *qË™•fMœ'—‘\GÏ!2 3ñ&®Ï°(Lßon ©qß¾dø;†S¼p]Ñ0“޳>Bg˜¾#è&ÑHU¾o ¶†Êüq–"ŠlOÓÛÆâù“øÎÝËàû‡Øú>E‹¹x;Ëçrcþâçñ ýýô$èØÃOÿùŠ  š—Ö2wâ7ßÇàÎ'hßÃÑü1EÐÆÍ•Ü½HHg0ɳ|d ˆq÷ÏßËìc¤04Ê.¼ÒIjºqÓÂ'¨™GbGpg§²æd9WCrœã<·‡ W¬·S–æ`3£ |?.ek©aÖ¿ÍÝvÀIFïá†2^ͦ% ®ãÔ¡K)A´³]¼×“SÅhÐ^ÔL#Hy`Õ×ðó®=ÂÅ^’}¼³½ ÆCn4‹± $¾êG¦ œd´™òrVÞOu3U1šëyx!Ùßø!5õÉæˆÔFƒ’ J2´l¤r¿nc^,h‹ã+â'NóZœ]]¤w¦¨ I/cˈFXy+åä·QÞLM†Uli¡dÝÇr;e‘6)aAˆ¾e<µY•“88œ#Ÿx†C¼Õ„y:‹FX‘¥) Ú1Æ.:ŸoUh ö-©¥¹¦‚B«áã´4°ó®Ÿ(6Ÿò÷yN'yt¢ØŒÀ ¨öåּŇðyNlþ¦ý]ŽÌ”ÂCxŒ…U,iÞÓ8BühîlßM—Ùï¨åÅVê2ø:OlvÏ€v/ @s£ÜWNd')>à™.‹¡¢Ñß~ÛEfÌ#ttòK1“˜hü.gQ–•¯sÜU°ükX°c¥õ”ŸËqy$ß3—fcA=z91dËõ¨¸Â•l 25Ì(±€à*&F ð—L©ñI"ž µ¡Åè_Æ„ùÚÁLIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showpp.png0000644000175000017500000000172014507760372022266 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 7$ë%,]IDATXÃíÖ_h•uðÏ»sÖ9ÛÒvŽ'ý›š4ÍI‰aKJÒÒ p7YD˜ IWeXƒ½Û²´,íÂ]ô¼ Œ.B £$YAR«¹ZšÿZ nNÛéâ}‡gvÎt¹­.úÁÃûžßï9¿çû{žçûý½Œê×ðVb(ÄèæJ¼Ï‰Ã|ðe1¯’ÑjeI@²‰*Æ@XMòæ&˜W‰pŒ”·rÇøhûú‰•¬ŸX?úD7SïÀa“#Ô̹xÓÞK á¿3þðŸÂå1Ÿ'°»*šîŒËb\Ìá`$¥¸ “ÿþy¶¿”YÙ›ÃÕx|/@[yl¥±•œ—þØÎÆ\îÁ©xî’Æ_¾$Ü áÒ_ãIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showalternativeflags.png0000644000175000017500000000126614507760372025207 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ Ž)!›tEXtCommentCreated with GIMPWIDATXÃí–ÁUã0†¿° Èeoñ£(D[AòhÀ¡“ ˜­ tl¢;ǽ`/w°;˜=XvòL6»Kþ÷ô,Ë’æ×Ì?#ÃGñÅø¶cÌ|à;ðû+HEQ„h|†±“c…Ö f«y‡ ÐÛê)0Á»»ƒ¢Ø|¼½åøÑqÿ¥1LŸž(Ù[“'¾Ä1"òºö´"H"΋o†@Ïf õvŒ#Qµe[^¼Aå·>8m»ÉjUk¢Œ]ĽÝÐÚõ¿<c˜Z ý>ÞË ·§•k/.Ð^™-—è$Áj]j%ËJï)——yNrv††ZÐ3À$I¹^Øž‹ïEQÔFßýv]Pk I`>‡ÁîïÛ-Î2¸ºÚœl¹¬ãý ××åÉ•*û«Uikk‘ñ¦Ã!HšîNG$Ï˧µH¥fÀß^gí&¥óqê7@,‚³IÍе*5°°v·áósR ßÚ¸ª Œ©‰Y ÝAÔnØ‹°I ~Ÿ˜T›Ä1DœßG€X¤)²X î‚ÃÍï^Ökx~fT…ôæÆÅ°Q^³ŒQ–¡€ ̲R+À7eÞÆ^èûåIª˜6J±×ò‚ £¨öˆî’ʨµðÁ»@¹Pï¦a³^8Žÿµ&?»þ|*NÚ–ÖƒWÂ}¶çÍ®Ž¿ÐG£\0™nméIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showoriginalvisibilities.png0000644000175000017500000000261214507760372026074 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß +ʈYIDATXÃíÖkŒUWðß9—™ad¤C„2E‡ }¶*’ªtšQlÐ*iKK­¥Q±ø€LÚZB¥òMC[Ç6&ÖG›" 1$ÄŽ•±¡€H+„-”GÇ!ef.÷Þsüp÷¹sCÑV>˜Øœœ½×Þ{­ÿÚ{ý×Ú¼Óþß[tVib–ã£Ð”·mñÏÎûDÓ 1MƒvæÎ¸kÅ)Åó ñ$U†“Ž3o+õgh i0|Þ}ÚEoËj"–H!W3ñ,æ#CTW´¾óÏfÄ)yòõœ©§ù4õEÍŸãÀÆÔŽ·hüZlÐa‰q\5ñt„Ñ>Õ}z«=YDœ±q®ýÝ‹xøVŠqa.uk­þ¥—è¼ý _8„§1Âãq0¾wÏK\l©b1çëFö|D»‚ ²ÝÓ†”uVk^ö>+b6‹<}ÓUŸÅûuh £»$ò±D;ºƒ°„é0w¾a,”"? óÓ¤Ni!ÊÊ‚uuÆWôǬb“\ãþ*ã—cií–x8ìñxÆ9ýAÛÝ#£û=””0ýÈi.%Jù[»¹Ð5ÉU•¨ÎÊ')‹Ý\¥{sUÿSàWc-VKl‡+—FnÊ"ÒÈ3Oìt¦jó?çìru“ËØ<Çz+]…ëÈE ýàÏ`bدÄÑŠ²QaÁwFp3ódTþË"÷ÔÜcvÙx{Ó28-½h·½”ó¬|¯•"/TöºGw‘¶=4[ÇMN”b½qmœÌ¸ÍýYäzeO6mè±»vÍŠ^Ç!y÷Èim(”¯ Nm©+éSf‰(³$l;e‚™­ß°6‹=‹¸~€¶¯zHð8ãt”·àßѺ!¯8¶úBÙãí—š²írß“XÖÑ>u‡©qfYˆ•—$º‡´|ËÆ,*_EDqTÁ´M= ç´ž1‹ÍÞå·…¹/µ™]Ê™Yɳ›ðž,q2ÎlªÄ‰ÌuåH\Ò˜×#¯µd}Mfýu†.³]‡)Ø…G%~\•â­¿Þ¤Ïlñê@c™RÇ[ ^xL.‹ÔsW¹.]lyžvˆ3kŠØW¡a>‹´†#Û¶÷" ÷µy_SÞP+€ýï Þ÷ ãE> …œ]¯Üc!WË-—z0 õýÀòa$öÇË%Y$:4ÙfE¨:äB°,À8LÅ+úµhq³ÒHg”‰3D©_C1gBõM}äF«ò¡_W´Xbúðj ýß·òd³Ÿ×¿Ab–Ä%šñ³gÆzÈ¡Œß‡ZWjꩦ¡+jÿc¾ÑØ\ª+Ð{ï¡rš‰Oâ¹J-h” Û5¿©áÿb<@Lèú¦e£JC±(Î$ü}è}P®gp\¿¿ˆÈ"úƸOɽaÍ‹ë*,øãPRâN‰ž7)¥K°Ñ@ƒ‰«ïÔ;&ï‰(ó•û^³²Š¯„[¥¶Ô8Ú- ¶ý®Ãýv†©#“Îý&üÏ\€“5•ôOgYw1^¬’L“”s@%¼]¯cV•d«ÄûkÖ|©Æø¢jãÿÝ Yˆ§ª$¿ÀQÜŒ÷VÉïŒx{œ'Ãìè~“Ù:%#rÌyPñA¬ ôjLù•$¤åwÚÿjûcà©èSØÂ­IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showqp.png0000644000175000017500000000173014507760372022270 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 70žHúeIDATXÃÅÖ_hÕuÇñ×vΙ¹nóDa6­.TDÉT,I-‰.Šè"˜¶V”[ŠE ã¸pdyÓBBA25‰ht³þ D¤B‘æ…IôoMWlévÜÿÓÅù< =;k;ë‡߇ïï<ïßóý<Ï÷SÛµ‘X~¦ù¹K»‘üýDªÿ'€¢&Öæi&V8ͱ(¡GYfy)3_žf€¢]¬.Mþü=3 Õ%dZšg“¿žÅÉu÷Ï¢xï4„^au ¡´Øâ03¤iaŽb„ž`Iäßñ<<4›Â}9˜ÙȽc¾>eUˆ.äÕu9j»×f±÷O†$®á] ^ÿ1}8MaB¬*IŠºÑÚˉaF‚X·G)Ø~8Sqö¥Ÿ£>J/Ú{ø©›¾ "_S°”å…IÁ»Äç럢 ¾ÈüR>¾ÄŸ9³™·¡Ÿ¡÷ÇWM¼ÕÁg=ÜQNáKãVà1 1˜9ùž;˜ÑÍÀ6vA"¨L'ˆ Öa"ë‰4Ñ£•+PÆ‚§8RË¢kïê_ÃÈFâUì<|%ùUj˜Æ÷ya£ãîq‹»/·2ð<Ÿ×°d‚Úè$¶~R·a/Ï–Ñ·5si¯çD ˦ªwÆháû‹|7J¢ŽŠj–ÎåÓNÖ²"çp‰ç>J6¶J wVÑVÏéM¬Í)ÀN]âÛsi»5©aÁ|Zë9½…û& ®¡‘,´pìCîÚAiz|6ýè'ÚÆ¯qöñEVhHP”ÅÞ¼Âî Ût» «(?DÁ OÎá£!Î_[‚ö <žRÅuT¯àÍGÆT~Ãa.vñÃ1vŸJ†ðøZΞáxç˜WèBGÖ œÛʼ²´Øßh£ç,ÎóôœDA ­ô;y4ðT. n¨p6É7ñ@%e©äƒh'~‚î8Û÷ÓšyfÖÀ¸VFó:*Fð ƒí\âmìÙÏÀdæÀ¸µ,*£*Nâ ºû9ÚÏö–ä LÚÆ(b÷JÒÖÇ3-ü2•ÿ£2láæË ³ò¤À¦Üò®² /£ø8}AiÖ4D °zõóDE…/kÖ, ,ø}`±XZTMÓ6;΄I“¾­À s À㙘Q66æ ,³¡os`“‘‘á‘BÕ0Œ_«ªªÜ&›2æH·q»½ÓøºnpâÄ-3«4°(//ŸP%I̹Wus  ·w€ÊÊS‚˜˜0Ø·¯“Ë—ÿ0«®ÇôôívûÙh øÊÇŠI…ñ`‘).ÎbçΗض­mÖ Z[¯sñâ]Š‹³ˆ‹‹¢³³—7†ªY q!Ô<Ð4­"8:)O7kÇÅE1~ü¬àºsg€Ã‡žEË»x`Æ UUÕ¬I¡®ñL£ÂÂ%ìØ‘ÜWU½ÊÊ•©TTäÐÑñ>—.í¤ºº(ŒµnƸ§êºn @ï‹$€¥K“ÉËK î 2HMM$33™¦¦µìÙs’>8FE…—_N5ÿË´~[S x FD8úóÏAl¶Ïéïw³lÙ|âã£II™’BH°EÇÆÆ¶«"R2)8Ã)P„.Läôé÷8r¤ŒÜÜESÓ´R¿ÓÄLIÔ4­2ð£úDå¹ãOËM`ßtsTUÕL]×_‘6Y ˆHW¤>ÿ¹6ý¦@IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/32x32/actions/showsmoothedvisibilities.png0000644000175000017500000000177414507760372026122 0ustar olesoles‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß PyLz‰IDATXÃí×kˆUUðß ía†)’5ÙÃWh˜ BädL)†FaE‘Jö²ìCDB.(Äèe4dÒ‡JRÉ,ƒl¢¡—凰2Ó2 Ò„R³Ì¬éì«g.÷3ê‡ 78kíµ÷íµÖÿ¬}8>þï£TUñF§f=-ÇÚº*à/£ 8%Ÿ¼%,?&¨q·T1ÑŠqh˹%93£`Õ*\~àWáqü‰Å¥ÂÄLOéŒäÜ Øˆ!9ÿª0åø'¥Ô«”Êx.O¾]¨¯±xet ³» þ nO项N8?Ááo ëd‹Áø9ßïfu|d|£Ð =ð|ÁlŒ°_¸ó1*õ›1_xQ–NÔ¡YØ |ÔÞ)¼_ѱÃBæ Ëp]MÞ..À—}½ðC'§_…É)Íšj± )µáiìÇ=èUßHa2V¥n/ú «€7cVî÷nÄZìÃ’" cfJ_cä!´Ï€±‘ÌËÍ¿Î+Ø÷›ù iw2œ&ü‚>©ë]NÁ x)•;„3k„r=.Ii¥0UXkÓ‰ƒX‰þ_X¹ç"poêæO”„³ñ}§ {;Éç·8'Ó×”u³“j¬hÁ„dצCCË,x²`xPX/\-LÅlŒÁ¯xfÔop+Yp?úäiÆ¡µÆi¶á"ôÆö‚~6 m5¢¶ÓRzXx¨ &dá”Çgø<Ã{jæy&èºBêú {ª€/Â]¹v‹0\ØÌÙÑîÀ<%%Ã+¸=Yx½°Ñ ¸)7úI ÌÄâ´Ø³„?Òþd¬æPãú }3µåB¼³œ‚3o=r¢AX[å4å†Õ†­Âá1Ì)tÐ72Z—VîÎÚé—ßaå¾üa|fUðÃMëµ,´ ÷eÊéœT¾&Ó³+Ñ¡ë„[qq*—ç);k*×àÓ”Æ O ·%èš,ÔÍXŠQÂDáŸ,¼A¹®I´S¿œ‚iyåªïFwÛ‰)Ýœ5RËv4>IéGa`çw®9л*:éÇUì†`K‡–¶Ö¾vÝÝùM(uzA»Í-à×Á.‡A¦à•‚fvfK?£ Ÿ.:Ü=Ž‘¯tÕÆ_/¼×õÿ‚#sâB<’ôê™LY!,8þûõŸÿ+¶X€ÏÉIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/0000755000175000017500000000000014516225226016610 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/48x48/apps/0000755000175000017500000000000014516225226017553 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/48x48/apps/aoqplot.png0000644000175000017500000000426214507760372021752 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝ .ÿ÷[$?IDAThÞíÙkŒ\eðß{vö2³»íö~ÝÞv[h¡PZJ¡(´¥ÈEEZ"7xA(±ˆx bcT„HP‚ˆ" jŒ1F1&Š>€ˆh@(¥Rhw·»Ý™×çÌî,ÝE¶­ÖM|““IΜ÷¼ÿÿsžÃÿ×àš<Þ |Kþ€$ÈÀ¾ñsÔnsp5ư§ 1¡‚nïÂ#c´é“ßÝ,&ìÆªÃIàoxóǰçJÄ]*綈xáp€?1»–aß³rb\)>½TezNÄý‡ƒÀSÇÄÕ©/¼[Ì®Ñׯϛ,ƓŸVüö•LWü7ÁŸÊÏVª\]oÇ·ð»W¬š!¿v!!/ü²•«'ÓŸdà‚¿7ËÒ‹01•»žAøi#j£7Ÿ#lX,Ö'`Ó!1 ¸5ô: |ü¬ÅÌœÉ_ l,PnåÝ¢Ë]¤è…ÌêûÝëIGÚé•“òz®i¦œ™Qû<¡}âAÂï@[UhI}æÎiâö&NË¥èj\5zÕ5®sû~´÷ …oË·w wï[ëøX}&«F.´ÔD³‰:íøü`,Ìá)’ n+óƒRM¬‰|¾pˆÒuüì©tLâ‘éÌÎ Çý|§Â’NaJ‹œt€àCV!wdu¥4|'¥éüy•òôÞѶù,ž)`åë¼þøùÓhÂÄfšÍìú!-–"ïÙÍqá VŒ©×Š÷k±¥6]ŠÖ~¤92“Úܾ47­ð×-2Ö£U–«Ì¢¾-…µ¬;ÛiJ†HôV8{;ǃ£0sLà‹ZðõŒx„ãòl™A.!ix†¿ÊòÖ”Èí‹XÔ–¶3§®ìuçtFC½¥óÓWW“×ÓùfJC$¶÷s] ¾M'fKÞx¦Å÷³fÐþ0ŸY­Ä@"²¼Àck¸k9gÍ!æS œ²z@ûÇ]h¤c¡¨@(¤Q'æ97,Éê¢ìØÝqà-hµ^åuªÛZðE·á´,¶ÎåÌvú›†J åú4F\²ˆØ˜•Ì™Gs~Tkòttš2ç‡ö~òH.[PSAEÁÑ8;Ë#•èŧ-ú,>8¨Ç §NãÖ¨'4¥‚I•Ùh’dȤ¹ê(É(~°©gNgÖ†®™ÓMDZqFÍŽ –Zé3>÷ÀµZq7¶ f– KÛøÆêš³šªåtÈ0ðšRµ"®:Fxøw–¥]_Õy±áÊ÷gѽodk˜€ûÖ³ì¶ïEÈ *¸VÑ4\¡˜:fFàÜ„©µUï´ëÄ•ó›·\IßXço‘£gñ§­L?Gì=NP_MM™ÔsvyÂs¾gq!Q¸þ'”óôÄ׌ãнtíãÅF`„©³Óù{×΂åâŽî›û´´rz½ðÀõþäz—*ë ø•?vZSÎûV½IrÝÅŽeÂŽîfŸ ÿì¥3 tíã¥nFȶ Lk'çäršÞy™¸»$”ú¬"ÞÕÏ©›Åî7Å6/éÀ`˲\t9gž›êäùWFÞ&¼ÜCŒ™öô§( \=“ç‰!Ñôæ·‰³ŽžõàÆóW Y¨¼1r,–~àS†Mbëžß½ŸìG`çÞ4­äbdÏ>vtSùáÂ,!ß̦ Ͻœ2?ØQÈÒ5šžø‹Ž<‘Ëo uÝ%¡»ë ŒÏ^Þ[£®Œ@¹4òi剜}5]x¥ûÐ =—ŸÅ’uœt.=tí~ãï ¯î­õ~^ê…@FbÖ‰lß}èæ"3×Ô1šÿ;]½Yce&ÔC¥4N¾öV5 fa´;MÕãb%ôU£PU¹žqD 0PÍÕ0ÚßM,ürÏÐpÂÞr½ÞRÝP8LH9Šq_VV¦Š“&SŽãÆ„ÄÂ_å¦1y!¥Êø!Pî%ü]N4Ocr'ãÄ ’@©‹ä—™òS™¸ˆÒ8òâÞ]„DN¹ÂþÀ“;¨TÆ>úÜl¯`èC߸\ÿY^‘JŇê›IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/apps/aoflagger.png0000644000175000017500000000554214507760372022224 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs°°û‰QtIMEÝ3#Ádº ïIDAThÞÅ™{tTÅÇ?sw³ò $ò—-¢Šˆ€CA * ”G‘¤F ’@’ìnöNÿ¸s7³7‰DIì=gÏÞû›ïï7ßßk® ¶KêsŸ\ Ü¢¿«€=‰!^»m-’*iˆsV ŠÂ`˜O Q0í<ŸÙå4ê%Nþ.`"Ðå<Ñ´ :‚.)Jª$#†@‚a†) D(ãùE+v/¾gÒ2mu¡¡ˆ”S0ðTÓSˆ@# ¡:÷"!”PÅV²¼•8¨DRàâ5ÀK€w€kMà@ ÞBJ³Rmñ$†!!â|š„!rþ DøÈ²䯢lœjëƒÌ²€çÙÀq«–‰ók€W|N"·÷ÙÎÛI!PŽÚ*âƒÝQ/…õ} °Yµ(KÑÛgÓ±6ð÷_Psì¶ËNKË€±z4ؤYžI9À™‹Ÿ~ÃW±2­Œþ¶oÙˆm]ÈÝб½3jGgØÞ©Z9Ëf¤σaÎW0®3íïéÊÄÑÝð\¸¥OÖxð†Ý”˜ ŒÔwªÚ]Y ŒçQ*JRŒ …û_ÔbÿžWé…b•Þ%u¨-„q¾5`ž¯Ï !»#wûmò€ç°øàÖ^|~S?Ú-ßZç.¼ ´5pO!±]z <œßL@¢ú܈P‚ š¸2m‹GõíÀV@= ñÇ-Ý`\´z`r{:Å3ú§c,Aw%X8¬?‰CÔß_SÇ$ã$$yH°$/ÉøCÀuHʺýüQÒ”`ˆ¨þ¿Èl`&ÅÀ@`¯ "N¤¢„ÒàÌõáeüp Ͱ¦P‚k•ï|Çý&šÖAÛëH–Æ| ¸èe, ©l6v,Ûâ™îCJðPl,T ôiް”#K'“ù…;oZk‚BÑ·–ü£lA–Ç'G l…Àf>°4#zB˜ˆäk$dÖt§ìŠb`l(Lçï@?¼b8’"!xد|¼L]xÌñ3YÐ!ö-‚N£¹UYLÇã»| ‘aWÕõ•à˜é™)å„#¥åqÎUV,ÏTÂì@(”¥è®vD(&1“u-àrËf …`QZÄÀed;߇^ŸÝͶ×̤¦k">V ºVo¬[©'8iî@bØ ¨I%^ ¶Q‹Ð ¡"H c÷„2ëb3ynpo„Ïf…±P¼‰ÐµPêÃP¤‹ßÖã™ÅOR; `ü†u„Ö¿_7ø§ÒjŽÔa³+ó0D}N¥aÙ¨íiËRŠ 3(T ”²-Š00™™Lø²+ œ­wF (@ð9ØVâ(Õy1=›*a ¡ Å›Þ!ï{êoT/u#}R%¥DÕ}/ßD-gÔRˆ¼Öމ|v\éáÄz× y༻$`¤¦“+’#þÊ&ˆ„i\¨b‘˜ç»Û¸¯ÊG¿Ïz`Óþ~ ´ÔµÈ{ÀHŠÝ@0¹Z¡#@ª¾÷ÿ-‡#G›Öu’ q¸ÙaPÚ²Q\ý1ÝVo¦G“UL’bê)–Ef³:8B³ÁO”ŽJð‰.%ÌúÝ¢¦Lú¦÷% A{§é’c’g‘D\Eä+8_Ïó'1X 𹆉ø(¨lÆ+(’+ÈÒ]¡§’(uÁúF1¶¸ÒØÙÿ#Œ/Û ¡.Ú:BqTÀǺžqë’Yù­XXÑ„8QO.pí<ÜŽ¤/’z<Ÿ¸Ö€ëÝQ„b)“™܃‘áÒ]Ù¾«pœc¬µl+Ì )]tò“`©Y”bó(P¢‹´1yí˜W‘È.ˆ iè´_ª{³ž¹øÉÏõr¦¿¤‡z~÷ËŽeYÀIJJįÔ㞌9.ì+<‹wõ:둜X–:Dfó6“ >v6ˆ² Aª§„] Ü£küßk ÇS@+`/Ф‹jZé«âÊ¡ ŠÑ†ÒUB1*ÖÆ%2xØkuÐãÀm²‘¬Š«—¼9@2W7:—¢*9ïµ!NRΘÐjLyâ[vNm«'Û„´‘\ª4÷f\üO;Fq¶§¥|Òl)¥9fn÷_ÜòµÎ„U­Ä“žçÙÖ•¤¹#Ø–á¯( E·œBæøõ^.ÜÍIå0áÐ¥©pº/§!RÜ»Œð“,$GÝj4C‡ÂDüV$ãê^SôYÍ<éÕö é9æi¶L,ç®GN²óI}ì2ëÜÙ-&e©A#ÛG8q¼)×…܇"Ùh?_G²Æ]ÛÒÀC¬ƒºoý¡Ç~JC®AP(ÊY€ä€G~_ýÈ¢±Í ”Ñ£ØÚúç·a,Š« ëçšÆ³ô1]_pj` ’cµòþôJTè¦h·aU?°I¯ÌQ—Â«Û Û‚aJ0›IÀUÿZEßU„Í#†‹GÙ1l1ºÄ˜f"Ùwư’æÀvOWu 8IÉi“Ão ­×#ìj‹/ÏXï€Û€ ƒÛ-¤×Ñœûa–üAà¦Ú°‰F=¼—\¬öô+€›‘(OÉ3À‘8 ôCr ¶ÞýLÐgf1ø±>eþV’˵fz”-~dC]´kìp?/<àÐýp²A³|9 ܃ä½ïó«ÑpOŒ`YxïôO¹ð>Ð7þ½bj,%+>LšÖb¼pB‡Êü;²¸ÅHQÿñú)q0 ¸ÈÐ…`ð°FçFlG`­‰–SJ‹ñ °3¾Ø «fAV‰=N†O¼…µ¾ïô×c©D\y D­h-%:´€»{Á@ù8q\ðPë4óÄÚàÇ( <ÁCñÓ\õ[ǪŸEÌ?òú­ãÿ²› UÒH XÎŒª—þF!Ðø²‘·"¹¾ýõ§P oŒåÆuæ†ðŸ [ŸÁU •ƒØiÔöÿŒ¡ºþüÚ‰aϸ7IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/0000755000175000017500000000000014516225226020250 5ustar olesolesaoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showresidualvisibilities.png0000644000175000017500000000354414507760372026123 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß 3 £ñIDAThÞ혌TÕÇ?÷¾y3³?ز°² bÁJ¡[hC µ(ÓJk,`j¬1m±kk̦!­™m1ÐZ1Z”&­­­¶•¨*¶AhýPZ~D±­°R–Û-ûkæ½yïôwgçÎ]vQ’šÌ7y™ûÞœwî9ß{î9ç>¨ ‚ *¨à@ÏK7Ï¡:á1-‘å éqŸé ƸOGÜã×Iµw÷Ñs.=_Ÿ‰ê}í»ô>µ‡Ìw`ù\®Šgy î3?áC܇„g.s÷8âfYÚšæí¡ôÜ>Ç{<—¯yqª<—×21î{öÏì=z4ÂË0S4»æ—s]ò¬LÕÂO7ŨJW2Ë ÖÓQL¸ Ížë®eÒq`ÑõÔ x ¨)²Úú^¡õÏ„iCNòhj€ß]b­¢iŒ»ˆî-ÀJù"ÌDø­›Ž°¾œ®{.g¶‚qCõÇ–.bʈí‰Ð]S©:¤YIÙ®€ê4«7äg¶ÜhßÛÀu@yô…rúÍj±mó»QµG&ÒF;‡j€1@­Y3v€µ¤Ø#…ÔÍD¬4jZÕOŸ`üŒ0#7aO5Þ3 ù 7q‹5Aíµ.5m›I\|&’sC¸ò«È›‚±+cI¡ù›q@¬÷|~×XÒ~Œ×âÆÁº>Î\ó* _žKÇ•ûá³ûØœ± ëÀ;˜úÞæu×ñXŽ´IÿæñÃ[ØPŽÓ‹îæ6?ÆŠ8Û²Æ3ÀbRô Ï\Î÷,$XñÎß§ý\ëÖ’& iò½só‹ðòót­C}wWX5$ÝÑÌÙÞj&Úïgòé½ùÛ|·‡E“Ôðô¸»X#Eh Q>¹‚&/¤5áçÓ~¨hQ"ìã¸(ÜŒËx §†`–%÷F›h9²ñ]2@UáN"]’v²|W Ÿ¶å”ðã.»ƒ nÈïQ,³²„š‡_Ü~îÓö_ëÖÆÆoQ…­Ó¾\kdGŠn[ß·1GKAèŠù‰´³³À w2'tØ‹f±Ýœ…ŠW^zžŸ¢E9VÔ/Õn°žõ*‰PQ1,Ô6‹ €-¢ *÷ _‘ˆÅ~@Üõ™’ði }nUÙ’||0Èoäî׋²vÓºfûPmu¬}¡pÀ8Ól9˜T11‘o)aj‘þUáÚhßj÷¢Ø‹âV›u3Þ–ÕÌÛ³£tS [e„ãE&¡hC©}›ÓUfB“Ú™µ‚&-¬É•BQ€°éìvæK²Æ`nîmìâ¾Û %DðZ sµXFF†È‰â¦¨W /˜û'p t¢n5p8)šU¶²ëCý.4Z<'þo8™‡ôŽy|)§Õsiñc<“ô¸ÿ/Ð9(”BË€k€Ý¤ø2$¬ó±B¡\óÌ5e}¢¼-æÌ•+1÷ö¸< ÄÍ6ç‹SÀ»¤Jú¬ *¨ ‚ *¨ ‚óÅÿ%¤oªœåVNIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showoriginalflags.png0000644000175000017500000000244014507760372024506 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ }—=tEXtCommentCreated with GIMPWˆIDAThÞíØÏoTUðM‹N[|UZuQJHhq¥ÌƻàMÈPÿ€&´©$î\• Ѻ0ÚÈÂLuAM ³1R›¸061E‡Iµ"í!^¼¥Ø©´ÑÆùNNòÞÜóîy÷žs¾ç¼K 5ÔPÃÿcÍšC$ ÍšÆÖÓËwà‡÷½Î9úõL®d‚úÿÀwÙ¥K—)S+ž î¿à†.]ÿøÙºõž@ë~ÕæÀH¡„Ÿpcß)Н_ÎV5hkÒt!+û퓞¼€5ÞÔÇñQ,«bëÕí¶‡‚BxË[+¦9´ ËK‹Æ²(!!Ìš ¤É0` *[Õ„Pª^½V­6Ù´x¬ìê®/U¤6Û|¨];˜2u?c"ß—“k-+§¥ Ûl[qô  ›c¿-óì‹x#¾žÁ+Kèì<ê¨N€ 6TÂ;°{µâ®'vW¿b(1v~ØpÅŸëç „Q£¡EKX*wðý„‰P‘xþ,ÆSRŽöÞÌËWÆ“2b¤ª*'ñþœÜŽ ´w| Iè¤ÓÒã!d°e›m:t¨¿ãÈ'â—.oóv4ïµ7ioúSRÝ—\zä’K»uWÃHÍñ}¶Æö3È,—[ÐЦ­òÇa‡ÓW\yïŽÛzD"YY]¼ð£óxs˜ÆÂ¸q½zÁë^Oµkïm×^mõ-3ÒLÌHûðrVöÙ¤RŸääBÂqÇCœ9ôãç ×^s-BA!$Ù#/žòÔõxç˘1RÑKγœÌš cÆÂ¸ñЦ-à|vÆ™Šý‚B¨ÏÈŒÀ³î,j·Ýöس¯¤´oÞ¼nÝRR‰Øt•Cì15mµõ»ºDyiÑò%æYii‡ò•¯4h‰>íÔi=ZUˆË†8¹–Ä´i‘H“¦ªŒ~íkEE DŸ} v™3çsŸ‹D:â_»€uÙÌÝrËþ¨êá’Ò¿ßÌ íÚõésÖYyù»Â OŸr5=å”3 ¨¨OŸÝ«WþÓ¦vÚ¼ù¿B#hKI=¿`!uÊ)ÇsÓ±ÎKïx'ýš×@£ÆRIiWêÔ=}ÐÁ®ç<ç²ËJJòòÒÒžñŒ´´w½ N8Q¡Ó‚_üâˆ#>öñåÛn_X<¾?%5„pι‰Âý¨0QMËíÄd,céw ãÈÇ÷oãZµº”BV6Äìž^(JK?4hдé»\´ ÎIJ'—è:¼§ìÕû@!X^Àé3C†Ê{9ÙQ~èÃáœÜƒ„ï JC†/¬çºë=kC¹ŒÌýBèAq×÷ÀRrÓÍPT çø®ø“rÞ¼‰J ¿ö˜3§Q£6:묓Nš3w‡,yx¥óµÔ«ÿ&•“{«éŒLHJ§Î0d(Ù›}'ogÜ‘®È¿Þv{WQq-6{ýS¦Ò‹Y± pફ¾ð¼ÉÒ§^ÿöÉœûœ…F8°®Ï…&M5Z®ú;×[Ö–(„oÆ'5ÔPC 5ÔPC «?µ"~ÞxIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/spectrum.png0000644000175000017500000001031214507760372022623 0ustar olesoles‰PNG  IHDR00Wù‡„iCCPICC profile(‘}‘=HÃ@Å_[¥R*VqÈP,hqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâäè¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"€Ç„ÄL}NSð_÷ðñõ.Ƴ¼Ïý9z•¼ÉŸ@<ËtÃ"Þ žÞ´tÎûÄV’âsâ1ƒ.HüÈuÙå7ÎE‡ý<3bdÒóÄb¡ØÁr³’¡OGU£|Öe…ógµRc­{ò†óÚÊ2×i#‰E,A„5”Q…­)&Ò´Ÿðð9~‘\2¹Ê`äX@*$Çþ¿»5 “q7)œº_lûcîͺmÛvó<WZÛ_m3Ÿ¤×ÛZôèÛ.®Ûš¼\îƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}2ÔUê88F‹”½îñîžÎÞþ=Óêï¶rÂÛÑk.bKGDÿÿÿ ½§“ pHYs99ÂVtIMEä ;\/utEXtCommentCreated with GIMPW¢IDAThÞ¥šM¯%ÉQ†ŸˆÌ¬ªso÷t{¦Cã™±ÔHH6 ã$Øà?€XŽÄ‰=¿`¶ì˜%+ä-È€¶ì ²a1 4¶gpª¯çÿqû_Þ<|ùÌb3/8–ÝgŽŽó«÷ÁE”àhI¡˜Á<Ŷ ­…qpmŒÙø|sQà­Åéð¼]Ùã­Ç|%C7Öz¶¼ûέ?þö?~î+?þIû߯þÉÇó©Èkw`y-ü6 ð’è¯ìð¬hEõ£‚˜£û†tÃ’"€® WAº!k ¯ºCR<)²ßÂèRâzmaœ ºÕ0rž 5ôBùü[ú›o|Aþüèù6ðéôWoSoß cÜqlRÖW ½i‹hn·íN¾pÄÁ `P. K‚6'_4¤Çóž+B>k¤‹ [2èÖpUPÂ`Àv²5˜œï<2åÄìgƒÐåë3¼¶à âà mö¯ }†t×¶»Ž6¡œ*®`9¾O' + ÊY"Õ‚e°"̧™éq¡ÏЏ#Íñ$¸@Þ8l¯$ÒêøÃΩe[áÄäY¦iÒZë¯3°úƒ?ýKx]±2r°Áþç;¶3ä"ArÒk+­)õ§ž/†nJ;ÒkN­#?3ô}§XÚ,Á½ÄâòÑÜ¿"äD&Nlá‘MœX{®^k}cð#`ÞÊv7Ý HÈÈÁväøÆt\Ù–ŒªóÙ׳¶ÌýòÔÉ¥Q·Lí ^:¸*Òm`űAWè³ Ú"ÂØED½ÞlÙ '¶pd ­>kÀùù¹ðàÁÞÿ}d7ýVŸÀGjLÒg'Ïݼ!âd5î³õÌÉùŽeªìæÊe)<>-P‚‚û‹gÊŽ%ÁJ|ÁÅéË`Õ.ˆ{8ÏAŠpÒXúŽÇ}} ’ñ«ó½÷Þ‹ÏÂÀ4Øäx/²1—ÆTË\9ηËÊ2WŽæÊeÏñ¼!“£“¡sÇ'ϧóJ*dÐf&ðŸ9–Ç÷qíÄõ#NlÇ×¾ö5Ió:!ua_Ÿ2àßøÆW€Sàuà"|ÁÇ¿dV\@³]ˆšBE;E;ÍÅ™µ1 íRå¢G>l–˜sc*3eË~š×9à)Ê¡€ ¡Ê$pq¼Àe+HXÛöŒÌÀ 0ŸÛ.VHP憻PÅI©“Õ‚yR‚žY´ñj>çn¹ä(­ëŠåβç¼îL{¶–B—„mŠ'ÕNr•À} ö‰œ;h…ãÅñɹlja«åIÜý¢Ê•âNIä 9wÜ•M ߀ÐjsáX7^MgÜ)—LÚ8Ö=IŒ[e£ºr\VΧ‰îʶd./ò9Ê”H\ÌäWK×'g_3ÔL­ùY!{ZÌÜ¡v’:ª )Žp}ª8E[$®t²;­ÜÖ=E:îBIŸ¥2<ŒÞ€Ñ èp0&S1¢UkbÝ [͈_üâ¹}û¶¼T\!©¡Ctô#æŠ2*@ÁÈÒ#¤1IäD7AÅ™FÎ$„ ï9j%»‘ЈC6<Ìδ„ÔD[e‘{|ðÁç/½X†%ærà Xh8sÑYÍ5XI6í8B£ˆ‘5òçª}TÁr8åP†‡çAÆg’£Å°bô}¶„õ¼ŽŠùøð¥Ì©G‹*\y3‹Ó]F8GRY´qÖ'ÎtɬQöíñµ0@CÌÐp“ø»\CF’ÿgr$9^߯êfvü«ˆðòRB`É õa@cÑ • ×"IEÈÄ$Wte ÑÓ9 ª¬£/WÇrBÁ4K$Å¢-…ˆælXé´*HU¤*7óVîÝ»'ªzœRšUu§ª»H0g—Çe ÏHäDÑÀ»àLÒ)Ǻ‘‡1»‘ÐSêÜN+wÊ%K®L¹‘ç†N4u(oŸ´tȆ$#gC²¡¹3•F)-Júq>Óœ‰»ÿª»¿14aímýLIQ¬emˆz¨© Ý•æ:Ä«…×Ó%ûŽ„3‹SÔXRãv FúIÞq‘+ÓÔiÍqú”±&0õ ë.hŠ‚qKN)ÆÑTIs墕0 =Ç€RНëZ€÷ú/ôhzH ÕÍjƒ}âÇÍÕKjÌÒØ‰s¬[v;vZ£ècÒÆ¬%UJê˜CR"/+šœR­))9õ¨»’q4m¤iCÛZ£s{FNOOÝÝÿÙÝ¿ãîßv÷ÿtu!y`÷|£xS¢ÌMbi,³4„#É,3uWÜjWTªjh6<ù•×5Å¢“­¤±¤†V!m‚nò|!{. ILœ¥Ç¤âL©“%6­&í1Iì$h³¡(‚Žˆ9r5ɤ)ut‚¦A•É)9tB5*X”!”Q¢kÝb“@D¸ÿþ§pÀ˜‰ |wÈ\Ã)a€#"LÒ£\ðLÇÂóÄ3E⻈3ål$r@EGÎh2Dœ$qM†ÃæÔÀ ²ÚND^ÿáø}ôÑK‰EBM‰,úàÙêJõx¦yb³û?ÈÐ+'á4×(-†"¤dHvRÆÒ±ð¤A·2ÐÄ®"º^Žªy2³—udc"‘'“øð×Õ {wšÃ晽š‡±×Ýb #ŸT"‡¦ÜYs§¤Î”Ú€OŒ×(p«6§oŽ™ÿör)HrºKLšl¤¨‡‡]0„Õ3Õ¡ôzi…K7VKOìGËÈ9µ( Å™s´ž9‚OB±E¤#ìRE7Ô§–)"o©êùEyKDî«êkŒþWGß«éàUåL,oµÌ6Ê wØ{ashóÝe@âZ+Ða@·þ:Ø'"zS\?N+©BÚFO³ÐgÝý÷;£+Û¹û}ß¶»‡Â³€Åã^ØH8BGÙ,³ºÒ ±Û<#ƒvÍ…9½ýб1=º?’FO©…òW'mNªþŒ]D¾üXD¾ à§:—G‡Að¢™\%j³à÷K+\Z¡zb³ÂYŸ8÷ÌÚ3kˬV0tD*‡Žˆ“óÞ#zª~µC¿ÄÙ÷‹ç“©êþM3;w÷ÍìÌÝÿËÝ?ăEš+†6ö=sÑ'Ì„ê‰æÊ¹O¬žX-ó¸ï8±…Ë^h¦lCµ×^0—ëD[3sèžð±ðÚfʦœ÷Ýœ´ú”/®FÇsÍÉû §ºÒ-Œj®ƒûBæÊYϜ؎:¶Ü÷מðÐP¹Î'ÏIä•ÇçÞÃÝ…Íi3Òj¤ÍÈ9çÞû]àÖ‹·õ`€0é—4‡Í•> ‰‹^8ëKìbˆÓ<"U-]•B4LÕt‚G‡1Œ‘›z²u4wd_—ÞûogÀ}}™ˆŽÆEŒ’‡Ì‹S¤_1GõDõŒ!(Îj™½Oƒ« z,¼›â®¤ÅC™µ_Õ=IÇn¶ „+A·NZ©úøoàøÉ‹#0H¼Y´‰s©¬tÌ´hZ°ÈJÑx·<¼º¹èY6yã¬ÂUÿpY3}ÌsPfGе!ÒÐÚp÷?xy¸ ý0qn¤±'S¤££ãBàÂf²4F3eµB»µi(QÙ§uôÖ×b±X»" 3‹È˜[C¤"µ>[NÓ¤"ò¦ˆ|ND~ADÞ<ðqty¨OT I /#Nú™Ít”j‰K+QûZNícÿÖ9Ö•2¨¹ŒêôP¦t‹ÓìÀAÝY·x³¹nÏðöÛop üáPý[¶nwnžnÔ~•Èm ~f3g}»Ê…MÔ«­åGT6¡¸‘Èiäˆc(æŠÚs¨–bdÝðýþ2À;ï¼#À$"Ì9çïé4=rö-³ï%ÆÆ$„§6ËTOœ÷™Iâ5dµÄi[¨0¿f¬Cänâ¼¥v?D ÎjÁ`¬+ôêS>tdÀwnÞøì_ÿ…´Ó•‹ãÆ™u¶‹ítã|î¤ÒÙÎ6Î[gž¦F*ÎåÖXO7©s¹¯´&œIçt3êéÆyomŒ§Ÿñ{Ü¿S(_è´“ýÃoñ¢=ÑçO*ô³ß_ä„›÷>|øÿãy§¼ì‡W.U½åî_Þ¾üðøîàdDäpèc«à—¿u÷ƒü؋ȷÆxçÀ…»oŒqxkÉ{À|ÓÌ~ô¢pÿ,Çxƒ‹I(ÜøŸ±àÃñàCàvü·6Œ9xQF¥+î~ïG< ÓûÀGã%^²ÿ€óÌñ-è›ÞÕƒD‰IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showpq.png0000644000175000017500000000312314507760372022304 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 84ÕÑòàIDAThÞíØ}ŒTgðߙݥ-å+ ´ˆBaE+KÛ%(JiÓµÚ&6Ô(Q#UÚ`i‘¡ˆ±©i£Ú ¤1 5õ#”JDM*%e-Ú¦¬-l—‚[)tvçνþqïʸî.³³t»&œäæÎÌ}ç¾çyŸsÎ{ž7kìËTÍdE=¯4òæù|wv 0ƒ—9Ü/qM†5ýØ€2¸v5óËüO ¶þ\Ž_G¬ÌUê@†1¸¾ÒÿÇÉ-z•eùqÞGîUÂ"3#¦õ@>G>„vvVQט°ýÃe:ÿ2¶Ò~Œ8âþooäLä§'ùglâ_ØW)€/rÇX S¨émÜkø%…d6e’D>RAZ³™èÄuä÷÷'‰3²ÈáÏ2dFcN`;á³É.½3âkëy¡ë¸2È×Q¼™á1màÓýP`ñ0‚+»yÖÄ;ˆ^ŒY²Žß÷ŠeEì*./pK–èSÜ7§Rç—P“ãëó¨)¼ˆ]ø;8RdѨ´çËd ?…øVæg˜€éû¾‡kΓòí4 «6«û cÖøîFΔY ÊYýñ!“Òï×e‰f°úæJÊŽå"Wƒø…õ±©À»Ös¹Î—‘Äk&5±0ûK~*f÷a†MæÎör'û7<ñU²»Î&è¶%&DTRŽ{µ•Œ ÿÛy˜Ãñ¯ô±w_^MæûD<1g7Têü9ÈO$x…ÛrLé¾»·½èäÏ©¦ÒÖcwŽ–»7°¥’êÁ71¹‡ç ¸´ +Ê\©/`é1®ØÀÏχó½Ø7/gu¦˜¸—ë…8·fr \šv¿WUÉçL¥žöPF‹÷0:ê>tJm:ÆGz Ù`Õ¤ïìt¬ósðXù>Eé¶–Ü ’ÊÔžTbÅ^ô@þ2‚óñ*j˘ol–Æ:†ÿ•}'SÕ©ó™ Zö „¡j Á%ŽQ’.¸ˆS=ä@°œÚ"SËœoêŠÌ¼ méJÒ•ìÓÎâTÚ½žJ‚&í¡ ­GØÌ-Õ¼§s½‡‹DŸ!ÿD—"‘-™'Û#Q àΊ+¨B…匊ÿ·ÍOF”Áü^V.$;‰ø;i2®(nJvÑ©SXõxßïj÷bÕ2â {È«äÈo<ÿ¯ÍŸÄC˜ÿ¿vÀ\p@7²n%]®‹èF¡&ùéØÐTtŠ0m¢· @FÒFMµgU÷ªéôÐäQëXgÏ»ªªÓ©ˆ8Ñ©Yßj RÇ'9çAoÝFeÿ?xý\½þ (÷Nõ_²Ð%„þsÓÕŽKŽ=:¥`§D *„þ õÞ8DoÄIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showqq.png0000644000175000017500000000303414507760372022306 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 7;f-ŒÙ©IDAThÞÕØml•åðßsžÓgáE"tÐ-Û€r8ìb\L¶}Zu‹| ›"ãŠÊ’‰˜°fF?ðaêµífb2—øaËfæœ!ÙˆŠTÙFŒaÅÖjKž×}xŽI9iK{N{Ê®äÉóv?÷sÿïûþ_×õ¿¨€må+[yq;‹§»ïX%´òAŽ…Y>ÚÆ¾‡X2]}*d[h8\C>M.àמiç¿åôV @'g“$ogù½TækÃ<¶žú]‡9wM€]ý<²‘à[„ˈ¦~æõÔ7ðþú¯Y‡é]G¢Ÿe ›°p±^êÏóh’U«y¯s’@* ÖÐuž}‘`~áY-’ ºv$YÕ@×ú®)ô&h8ÇòuEÿ¯ÅºêúiN²a Ç;9;«^¨8.äéÚN°|‚v'ñWR'¨ y+ÏS/sdVWŽði’ÕýÔ­›` µXK¸2Z‘¥}<œdãjþÝÉé²V`+ÏæØTFªÂ⇱l’ßtã/¤Oy3Íîx©ȳ àö2£hî²éÂw8§gV8ÑRË®]Ô\ Á`4ó¹w bÈÐÜÎû³Fâǹî"g¾Ã'h—Âòû£Ôãx–æVŒnŸ Cü°†ëã¼Ïá]¼Ij„óYö,¡­%zeV´;î;‰WñþCüŽ‘sdr<æ…W¸<^ð1ß Y¼±hûžÂ¤O x5ÆS­ô^­¿Šˆód‚`^á~ V™wCþ–‹úáú«œm¡1CâN‚"‚~€æ—8X„TΪØUGö#â"•â\–'Úx5 -3¬ÈdQœO_ŽâÉ”l+²ü'Œ~:œfÏ û^¼eå4qŽc[Øö=ª§ò]–AäYž XÚÎså~ÊÉ\'CkYðô<š¸ØÈ±wÈNôÝÜãÞ÷´òÛŽ Ü⌋ú&æ9¹”ê^2)rü,Mk‘¿  ?}åóØ¨˜•uýù}f²œ()•ØÊó Ø¾ƒšŽÈ ¦/si€Öýü¦/@¹%›\H#…ã2†Úz%éUáñE„ëqá\jzI®dó2æôñ¯áÈ^4¹aä¼ÌÁ¼‚D˜Ï ÀJp” nêam#ñ8–âë„7Rý «W°i9UŸq|(šÉIr]¶5à.â]¿HVž1ª¿’³Ñ&nÆ©û™³¦è]&ª@x‹Ô%F²ü<Ãó¯D Çtå [‡¹˜`~7‰FâA‘o^‚FÂÔôpG–k¸aѬæK ^Ó&꛸9 ûû\×0A» Þ‹Vddˆ\†_`o{‰Õ¸+lcEŽ[Ê–|ûvS›Ä?Z2H>OkžgÚø¤d[x-àþrf!Oþ_S߯þh áÛ­ü£¤ì6ÆÁ|yDº5àîE“l< >w(ò‡Òìh‹8_yÀvÞþ2wm¾Jf›Á¡hûd²|œæ'í¼> ú¢,)ÃÝwM0ytጠG.uÏböµL>6Ì€€'—‘¾mœÌ´¿'Õ|!àÙÖ(ŠN§Â+¹®skžM߈BýÖU2]‘L|#äÇ/F¥Î™¨%Ûcµäê‹úwr£ùÏ<¾DçLª¼’H¼™¹×sænHŽ"èŸ#‚žÊðÄttÆV š¦jp ˆz9ÇO§“ 3²-ÄÏÒ]ÇÂAR½QDÝgï/¹0 eš©Y÷åYx‚\ÈkivÿªP«Ÿ Jð>!Yv¶E;èÿÇà¶ùæµ4¦`œRKuA+Ä‹ÎÁÂÜ8ýsu•u2F…¹\q‘ºš‹S¬÷L=q•*ÈÅ …˜W Xá¨*©ªÀŠþWlº·PPX±¶Pl Ž¡k³E=3êœ2 Õ¸Ñö?2ƹPpÑIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showpp.png0000644000175000017500000000276214507760372022313 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 8#òÙ@IDAThÞíÙkˆgðßÌœ³iºMiŠ!½_²ÍÅ$µMQ›«›¦±iPЉÁ[m£ù ¨P¡¬eãž=M>ÄÅ5‰—¢P«X¢”Q‹² Š¥6h…¬ iHiib5·Í¦çÌŒf–žÝ='{²ÍeòÀËaÞyß™çÿ¼Ïû>ÿÿÆ•u­?Ûáøq¾ô!Ò§)ß>ADOD[' €ò"’e¬C²œÒ} @¸™91s±…íìˆ&€òÝT]¯ f°gýlbv…éùu+–‰¶ÐÝ:Δî"^I{qhÿb\v%ý_ç¢Í̬pí°þîm!xœÍ׎SåÄ«X^¬ÿNL ‰Ëã@Pæ¶*×5ºU-$(ÍgJóI>Ò8úƒv+fÄDß:J-”ž£s·V¸¾‰±«‹$+éúð»]Ïþ¨Ùs†@Ì%}€ö–æÆ¿w ÜF)#€‰:IÞ˞Ͽ{Îss…›ÎbΊ3ñÙ1xãaÂi,B¸…-SÆýd ÷Ô‰þÿ°ÿ¬3o –FDÝôLŽÑ_º#â­çXr5íØÑÓÛ{öîý.7Ìby4Ôñß%¼€½Í_#öV˜eéäã® x¹ÈÉÓôþá,Ì[Oô ëB&¡5bïb–ÿ˜ÞcÍ;ÿäLâﳦÀU8Š] Ï'¼¹ôYÒÅø'ÿž;Ø2šÑ"µ1íOÓ{¢‰ÚQèdQÄåyßû0-%*Ÿ]ôÓ×W™Šß&|'f÷>ÒO³q^zgI:aÒ5œø¿?Bw•ц©ag“{ ï3¤7°0Z`VO"^ß¼z*ÝFú)’"Ûv÷e{¡c.¿@:rÎãGéÜF|#•/óÊÁ tX$ý¥9£Øu±°&úƒv Úb‚ž&Ïý¤!‡ûH×Òq;¿ªïøð”~Hµäãü÷åìYa÷(ö|’ôFõïß_$Y1ºz*Í ™G°–Žùt¾Ðœã#ž“ds;îÆ"’Ó”— ³Üÿ`”ñóFf^ÝÆŽù|"®?®å8O|`lN7óg¬cû¤F+°Ž´mhî7*0A}7óÄásë|­=r:¬O ]¼?È È™¬KŠ„ßlF=5]çãÒZÒ™,i²J/ÉÕÓ©ÇÆ€€¨Ä]MD¸zòõÑÔÓÐõ@FØ–Ö‰þq¼ŠJõtõ¨êé|ˆ6± àÊšîx1ek^ö»«ìÂÉaêéþÒ a»(º>J<—ey_?v¦l‹yå5’Þ¬€T¶ò§ýôÄ<s8Ÿß†[b = @TÎÎõbîø·c^:@u³æ`_íTg“®¡ï<•ò³ °ªH|¥•@×jªw2äŽ$~ˆê,J?Y¤JIF:Ú3yà7ü4åùÓY+l­§žF!{ÁXä•8ÚD{wàÙÌɦ«âÇ2ÂöæcØS‡ñL moÍ[KÞ y ³Mtð¦Œcýgz~*$y«âíü÷T¾)‹c!ã2Õ+ð³Þ˜Œ d?¾Hi#¾Dúz~É£r98ÊŠú—oçõ¿ÕdG˜ƒ¼lØàþÁ”.¾Îœ¹cw|#(ÓÓͱÉx ¯åº°U¦ŠŠ5R+·]²V×âüü>•GkRè??ÛëÑSù å/=Y'}£U8ø›æ©“æŽWóë3í‹bÕ¼k.4±ì€K.¸àâZa©Ÿ4Œ«ß)2ýS²ïC‡¦ãæšbS©i Ïy0Yö/[뙿•ÙËÔ_s¨_F9YÇðï3UÐseƒQ¿WÔD|¬–æ«po\(µVÌÓ§˜·B>&§¼‚a\e8ݸN×ÚÿÏB’‘p"®IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showalternativeflags.png0000644000175000017500000000245114507760372025222 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÝ }PÓtEXtCommentCreated with GIMPW‘IDAThÞí˜OHœGƆ5¸Ù5M5Ÿ¡»õ`ƒk„@X ){±9xP4„ॠbA–z‹…Ö’C 55‡°”г­H ‰)u уëŸ5î&ø?.N3Ÿûéš]›¨txÙogæ›oÞ™wž÷™RH!…RH!…‚Oà)ÐØöš ˆÓ§@ýnä¾8uýv;TWñc»w–M[hëjו…€¶Ýä@:§~¿/-…œ8r (OO§ÜØØï'LIKàÓ4rÂaú"JðV:ɆNDYÂëEXZB„ÃòÙhÀ$àJÒdº€ÉŽDG"7±ÁŠ'\E ÐÜL^a!<( ÷ï—ö1àRÓa±¼_e»\|qô(>œøåë×Éin¦IQ­å@0ô¾ŽdeÉCÑU X=yÓvfëÒ%°Zqª ¾ ·› `ߎ/Bw7_«\Äürþ<äåÁíÛÌŒ¿mËãÇ¥­‡Û¨@µb«0Ð¥œ5:9×&ú–Å—/Ëkjb ˜ÒCȳO&¾Ô40™¶Ç^/™uu|på „BÐÕ¡UN'˜ÍP\ Âýûü°²ÂW€Íl&Sï##€ÏôñÍÌÀÐÐê15@yZ}=Â襾L½½pëhšüo·CM|dŽåep:¡²R–²ðûù x`ªªZ³Ü> x16Fë™3اǃ¥6*Ñ™ÁÈ6y²(8L>~ŒïìYœ'Oboj’!rãF´}k«|noà ð+ð(J Ÿ| ´ ’nÙJ‰X xáñÄ_êçÏf3Ó€˜×Ëççc_š:ÙåkšmBeìo€iý]UÞo°§¾^ÖÕÖFXû¿Á¦eõ¬Êv‘wÍzO””𶤄W ô?3zý“'«ý ê[†#Iãã fØ,…Bê Z=oèxåvó:-`K ÀƒÍIÿ»V@Í„W 7›.‰õú›7cfшßeë¿åpÄÈéOT;—Q{™’‘PŸ¾IŠŠ¢Ù4ŽW•$@×5 ðf#Í´)ÆÇa`ÚÚàÚµ({´´þ1Ò>ð­ß¿*ƒÿˆs¢šU¶33’•"2p’‘ì K=k §$ŸÈ u¹ £ÉºÊÉPlÃHÀ _1b~²n%•‘’„E`8Y÷B{ÿ_úúöÞ̓ƒR"+ŽŸWgÏ Íj•ÒØjEìôµb )¤ÂÎã?±{?¹ KLiIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showoriginalvisibilities.png0000644000175000017500000000470414507760372026116 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß 6¨–ê QIDAThÞíÙy]u•ðϽ¯×t'$ Dé$&‚`ˆ¡†P‰i‚‚,E…@T¡XD"û% SD1 J˜QÑS´fF"[(7¤11$+ÉÞݯßûùǽÝï¾›& §f¬œªWïýîý-çœßY¾ç<öÐÚCÿ¯)ÚáÛDŒ½qNÆ8D"‹[ºÜ?í^ó+%G6—ÑÔcpsÙÆ¦²;{<Ù&½ÿ¸W¢-ÿxßõ¼÷F¯ ¥‡æšzh)§ßMesÛ7›ñ¯áo/D¼æáߊÌÛÄäßѱŠ( ¬’(¸¤§Éy»ÛÄ ß@¢¿Âû oºÅª'>ªµ­›¦2ÍÝ4—i쥱̠®tÜÜMS¯§Kš^¶~72öA-¸²¡0)Âí0ÿ3í®ÿèB+U] Ûšyn¯ïE¹‘ý–1/gš ÆÆUgÊØôQ²³SZKŠ&4§žÍTròõ7øuÄ'ó¶÷Ì»}ûäÙ1üi¿;„J)gŸÁéE..Þúù9ùœCÝzÖx_Üí·ã‡¹'UÜ ±.ÎM:_*,ýf¹Ú¶G÷áy[ß‹Jä÷OÝmšªyªé¬Ü—žÆÜêàŸŠ¼Ü´L¸x´¯‰Ü1]äÆOáÕS&±îCSnü nª9qb<¾]XôΗè÷iŽ¡æD!òõìç…¸_`ípºëöØ¿ÈÉŒãâPpðÈ>ïŸÔ©u퟊Ʌ§gH”S-¸͹ Ë0U¢†m68D¦ÔkSoìì€^| ÷‰Ø<¨>2ÜVrxáðãØžÑ›T}`ÇMWË åMy:ŽÈMØ‚£%6÷\ÉÁ!2.§ý£ª ¹ƒzp6ž\±?Q5ç¹uWî¯- 5E Äç ¾ŒCrãgñ•bX…—jÊu…¤œ ™™V#ÍBWA[´ùÜú!Võå‡Rà?'ºÔýöÍbvkÄØÜM®DOn<)·ßGpuî„ fIêÃr,ñCLÀ×ñ°Ä-ù ‡}Òá"Çô1"âàžUx¡§yÁuùHbïñGß7OŒ}¢Pó‹¸ê^‘Ws;Œ×9wvXbþÀ™8± —döY¤ÿj* ‘÷ü²îÐ:½Âúœ `¿×ëus†lñáºÃƒÅU©©FéÞ<ÛÈŒù·å¦n9~ß 5ÏkÈ]Y5‹¯ý4ît—†J͆Ë;‰ÛÁꜯ¤Ä‚ŠKŸmYGÿ[KU¿ÉB⥠¯ìç1tbþ”Ñ/³~ˆYí3 ínR.—Ò̼9-ÕßAŸqZ56¥Cÿè¶ìˆÿÞ’u9›6dK†_Kt¬6º÷gêî)ÏY‡šMGé§£°å$ßÜêø(˜sq>NEÏv,ÿ–0bš3Dî·»jä¡Jäö%Í«^«0ª¦î×´…¶mé­d‚vò„áÿÓndâL‰ß)Š«rÇ«Š ¼ã|çé5¯Þ*¬¬”\´è¿j¡uW©±¢K°â}KX‰ûmß’ð¨7µÓÚ]ËÕôGKÜ ¯dAié> ^¹¹ÎZ.Ò0(vc(»°U× >ñóŸxæMð½ ƒ¡}›×4øôØ%þ»{;D^žj¦¹§fn™™>+v‘«=c>ç„Þ`jA¡çºÆÆ~®²\ö Þº¤!°º¡×‘¿ú±%þY¨ûž”¸í XŽC³=¿3ÃÒµ{ë.7ÖòÃ’ŽÔ=›»kfU‰yçjÇ/ùnš‡>K{µjV¥T‹>QpSyv*\*ÀµÞ‚?Š é×zªŽ¥]¦>ýn“jY¡v˜œE®ofõ]‰m9»)'@iC»ã¢î/Pn´®ÚêqAkKÙÄb{"Zº¼Ü·O©×YÕ¦¼–7ôJêó@dCjØ"¤û,X½·©KGš-¸s¥gŒy¸GbTÎÁ6æÌ°„)QÈ*»t§;]î$WøHsµùÊjñü4”?ESÌ ¹ƒ{ãªëÖÏ­íÞ@b[t•Ë¥¥-pÁê½-èjö{a{4ùt’8Ab‰\h ‘¶ˆOôÃá@TM3ùô”6G©‡(çˆÌA{¨™Î³¯îã© öW²Ç]1”g{& æ†ÈÄ5£ÜÞÕì‰xŸÅ³.ÅK…Ä7?0Ïиê¡| ÊÊÀ>ZU½]C *Ôåk`ÂÉÆÄ|¦Î#W ¾€ïáÙçã Ð6C´eŽk¶¤výc¶+.nÄ—³l Oâ{×cF.Ùf­{ŸéܱKßÀ悟UR$¢íX•Ùå‚¡9õ=²²Ã ¶Ö¡ÕÌŒaËœìòR wRáÌs$.Ë1ŸG Wfuj>ý}×T÷T,flÜþµå™ DëÖM>Ñ1qpv>¹7Tœg«E…ÝnY’/)OÇ…I7ãŽÔ«7gQ?mmõM1¶çKqÂ7f¯ôd"ççŒi¨ZX—Ëæ.ípMÜ­ÆW]+ô¡Ñ±Yý›§…øâ€š/v2Ë Eÿ(~ðHníñSÁc‚é×®1cæðZDÛk¥5}™AˆQuh!Xòâ?x*ðñbo@Ò½ÒŠÿ'8*ïhxŸÄÖ7Ñ·)á.üs.ÆuÞàK›¾êo´ìŒÃÜÕÓèÌ!ÐÝDwúݽ±Í„çG™+èÌ-¹KRsðÃ0>o8öM1Ÿ PÁ´¬žÎ¬Wó¦6×Kr•V+õ8G°¹âÖÙì]Ïtdù5¸¬X‘½ŒwáÞŒù™’4̽…îÙVÖM2ŒÛ$Þ1Ð’;ëé-UM‘îªn™ð´Oð|³Êgõ™ÎÀ­ÅÄD,–Ôg»· ȸ¬-“ÿKLØ¥õ3®ê¬3ÞG?ÇdI]ÄÛIwú¯âÌ,04Öµ(ÇîdÝüÃëú² • ùjk·Ó"ÐiXÖ0è/™ujr”G·‹ê‰ŽË4½WîM%V tÌßN€Tˆ…:íG]skÐéÏY%1T§c1 ³ëêô”N“Ôàó›ûƒc÷˜RæãÄ›­™i”²®`ó«—øé[ÿ‡f÷ 1,sê÷ïâŠå8Uâ·oýšÝ+Àz;w2óõ 8NÚæÿ÷n 屮§ãLì—A‰Ç2x¼kv _öÐÚC?ô;‘µÈe©=IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showqp.png0000644000175000017500000000274214507760372022312 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEà 8 Çl ºoIDAThÞÕØŒTWÀñÏÌ›ÀÐÂj•²èRtSÚK5E•Ò_£5š6˜´°ÝÝÆhŠ?Ò¡ »´I“ FAPñWMåŸm)¤l bÙ¶‰Ö†µu•ÕýÃuKØ7ïùǼM‡Ítafa™=ÉËûyß=ßsÎ=÷ÜK]ÉÆÏWÛ"]?ÊwÞ@ü8]Í Ý… 6O@€üBÂ[ø ¢åä—M0€àAæ¸×F[ɧ'@þCoci¶ts€f¬˜ AsB“ûK°8C°…ÍSê ój¢OqcöÌçK›NÿWë µ‰˜5ây7æ YäçÝÎ'r•ßÓ2¤7Ô)@º“ÙšÞÉ;¸uñ½tÍ«3€®«ˆ?ÇÒÜèß5£©ˆGêÍh*0û>ýdŽèÓä—Ô @~.Ñg·þ°\Ž«#2%qu±Òi ¹¢Š6·Ä×°ñ΋ ŸK¼‚›*Xp¢B»K±( x”­“ΘÇ`ÙçsSY¿oaÌ‡¼œ¦·À% eQ3+EÏþ×O÷ÊsÕ8ɦÙ_㮀98…C1‡#ôîE¶Ä+iˆøè$$•vö ¹‚µ}ãBÑÌ™‰î˜ï„î%\ŕͤ&¾ÉúV¢&úæwl¢×`Z–pÝ8{`Øú³N„xƒâ:â_’’åä]Ä?Ã&òëËÆÍ¥h#øéÞ“ád‘¸™üëUy`U©T¬AŠß&8þŠ«¸r.~þ¶ò£ü~òð¾÷®æ?G‰3¤–Ö¹¾¬XÍb<¸ƒ¿£õ?@Ø‚/Qüù°6#´ðÓÒ‘¿•èäU0™]§Éceѹ“££· ‹XP»â½ò ž!?µªzŒÁˆÎ˜ôeÜp¤_ÝÍüQ:;v~•?ãßUg¡€Ž- ¸—ô>ðj;Oµ±pÜçõjl£P$¿Ÿâ ´’û ©¹,‹x©§[¹¾n’Üû㈓‰)Õ”«Ë@ðb;ûïá#u °BȆçO•=O@²÷‘ºŠ%1=mt·qC]$ wE¼y Â»F¬$³ói‰x¡ƒîVÕ @â…õFx¡\f& _ǵ´¤8ÔAOk)Ì΋dîæ½A {ŠœxŽYËG)K.ÇÈ,ó\÷GöuðR‘µÛÙ7&€ 45Ôê¾"ž§¸”àl»P3Ê@v³°—½÷°;vÕ âŸ´b¨UsÌÌãÚb‰zKü=¯ð½Ã4ÒÛTJ}3JW*¢¢ƒÉ/NK2`f;·ÕªyÙ4ÿº™ìÙ´/à÷ØGXàÄl}š½oÏÇ^cêNŽ¿\¶Ð ’]®J¿;Š03–ø‹øb††Ñ’}Œ?ãI†ìã»OòD•èž¿”ŽQm0˜,áúÏ @*Ãý‹ &¿ÃÅo:Y‚Ýrš‡v—:O%}g“ëtÙ9J¸‡Ï…DÙ¸â¨UûV–GÌk©}þ§z•l†_§øæŽpÌp\-Ž¡áÚÄÓœ¹<ßGt¨dÊ"¾ö}þt!K‰LÖ¿>¤åchDoÄ}Ûùíxs5¤¹C3ɽR ƒ§èY÷_v#Þl[q•Õ2Ãç ÅtL)휘|¶ã¤LбþdêsMÅ»ÅSØÛÃzWb¤·Îg¥0)é S!„R#B'q…ðQ!|ЉåÇyâÿ,£#NSèúIEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/lua-editor.png0000644000175000017500000000450614507760372023036 0ustar olesoles‰PNG  IHDR00Wù‡sBIT|dˆ pHYsÖƒ… tEXtSoftwarewww.inkscape.org›î<ÃIDAThµš}pTÕÆ÷îfC!„¢‰D‚Ð4ÁAí€:1PÀiÑ"VNg5Z§ÑD@bö½Ë¢Ì¤€ˆâG;´4k€‡`)Ôa Ø~uŒ"BZ4YÁ4ÙìÇé»ìÞ»Éî²<3ùãžó¼ïyÞ½çœûž÷D#‘±š¦Í:t讪ªª.Ã0V*¥rõ"Ò&"“t]ß^SSslõêÕ?߉È/wl-YÃçž{.wذa?TTTx ÃxB)õïâââ-ZÌÖårÝ 4‰ÈѰ•ŒŽ¤‘§€«† R»bÅŠï“ñåï7ÀÕë–/_~árýÅÄáv» l©öïv»¯‘¡‰ÚÅõÜnwßïwêºþ»šššO—wå`‡”žžþíðá﨨ðÎÞ˜žëA]Œ7z@µ- ½I«µÀ€o ¼{4‰ÈÉÝÈ$à×Ààfbÿ0~à  ø#ȉÉ5#f†aÌòNçb›3A­~šäøÜ ’´Ov•|`#° Ù£ð6Ø+ º=QC=ºAD&†qGl¹øÔ‰¸ü‚üïÔ)Sv>;”ªD¦"Rép8ÞÐu]¿ Øcv¸ŸË8ðDãwš/‡·8ºA×õC>Ÿoöå00=>yƒCÓ`ÿþ)+».&çÔ©ï™:õe:;{¢»Ü¡.ôѵk.—kJMMÍG‘üéÐñq¦ÛñbäÈ vî\dÄñãÌŸÿ'>ûì[+S0Ì*·ƒÁ%À²ÈfÏõXˆøái¬\y7ßü*Ý ÐÑÑͬYÛ˜?¿ˆ ŠÈÏNGG7MM'xóÍðzc§Ó€B b~†ñ¬øÜÌWùV^FŒBaa6[òKC©Ð$†a”Û‹e¯µ%YgŠ 3fäsà c(+ÛÊÁƒ_0vì0ΜYJii;v|ja¥N›Z”ú‘]DjÍä-Ðá#´úSŽÃ‡Û9r-Ï¥ý>+Ë„: ø€V‹ößÛëêê2 z"K‚^3R¨û"z{Œ?‚eËnaòä1b„4-æîöO«o€ˆ|jïê꺫¹¹ù+àpT) Àáˆ,ä•–°oß=ÚÎΟ±iÓQŽ;Ë×_WÆð 5YˆŸªëº²§¥¥ýÝçó-4`Û’ȇl¶È³OQѨˆçòò9q¢“²²­¡µæpØÐõXC©?G·hš6/ ¾j_µjÕ7À&³Ñ³ÇAöcQó).m•¯ðÉ'ßàñô0n\6……9´¶v’–¦ãtÞÁëí ž(ìv—k&º®™‚öYÀ”Rï^,Ï‹ˆ£¶¶6Û„”¨¾¿ÊÊ&5ÒÓW«ñã׫ÎÎnÕÙÙ­vïþ\µ´t¨íÛ?V'OzÔ’%U júô×”×ëWǧ›ÕÉ“ÕÐðuúô÷ªµµSÍšµMõ·Ô¬ëì‡#«§§§ XÀ·{¶ný½{[b:ëí ðå—JJ6sß}%äæåõ×ÑØØLIÉΞ }^Ži£¤d3 ‘••Î /å½÷Z™1#Ÿyó&õϳþòÓÏ*Rl‘àÅIgÆ“J©ûN:—àÎ ˆœÈW瀩 gú7†`OˆÈ³Ð/ãt:¬ýT·ƒ<ìR~/Ðç‹>P×÷±ìÃ÷Ù"ò±ÙN¶¤Xh,üÄ´±ˆÈp‰H)"–üèÑ£ÏO‰È³Oy´‡•ȯÀãVâëëë3€õÑ·C”——û!æIÌùh¿À2ºlœmÈËV.\¸Íf³­‰¾DŒù‘‘ëb_l¸óÀ¿øeòz#ð¡z¨Õœ• g†ñ€uWu;Ƚ —ï%:h?ìnYK¼ˆ,‘˜å˜ˆÈk@ÛÀã×™¶I€8ÄÀkÄâh5ÀD¹Vû|? ãÕ®öÇâÄ•ç†q‡Rê ˆ˜óó°Bð|ÐÂÅPÕ ´ÁÕ' Ü7˜‡úúú ŸÏgçÎ8®²‰®ë­@`³ˆTˆÈ³¥—Ðá;áS;€Ëåšrþüù'ív»HÝ¥wßöU__Ÿ±fÍš«Ræ8Œp¡ ·Û}í–-[â>H%œ*‹È RÓ´³N§óÅDí£Q[[›ÝÓÓ³2ì/F6 WÞDÄT‡ï‘›4M»CÓ´=æ Ÿ ¶æææéJ©›œN熞žžn`ÓéìÌÖ ))ÞŠÈ`¬ˆ|ìr¹¦ƒÁû5Mku:/¹Ýî<¿ß¿8'"µáÿ‡¸8Š·ù?7¡Qè9a IEND®B`‚aoflagger-v3.4.0/data/icons/hicolor/48x48/actions/showsmoothedvisibilities.png0000644000175000017500000000343614507760372026135 0ustar olesoles‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEß 'Â&Êì«IDAThÞíÙ¬×eð×ý¢•™Ê¹&Eš1@¿¤„YÖP¡XZiRPFö“‡ HÐR22Ò­¶Â4?Œ¼¨³Z ~hæ”M£šÊ¯ ÷öÇ÷|ñsŸû½Üïå—µq¶ïv÷œó<Ÿó<Ï9çý>Ï刑#ò-uûÔ&õèbÇœõø%nÇVIËëµúNô_ij¸#p,Þ„á˜çð¥ÿÍHšp^ë<(Õl»ÿ’#Ù¶ï $Gã É4;±#þî£2ýã.ÙyÈœgÞŒ=áÃWê3£:ü¨Šó«q1ŽßÅX™Ùœ;ÌÒpˆÎÿB\‹)¸ïÅö¶+™‡Of¿©’ š´Äï)%ËÑŒRÁöt Ôäçfª³ö þñ;öN fIîo(MŠd-Êm˜Q5,šìVòpÜÈ; šAJúšåWíìKîÀÂÈFLÔ¤¥!œŠ»ÑX0ú .“4w¸p“V%«£¼,h†*yI“uáô/Áç §ï—1 J‘>ˆ¾»# kD/É–‡ 8© ‰÷t åß$„ÓmËq2YR×!—éKC`Á¹™¶/NÀ™æ°£¡@[4Ù&é€qrv}ÅŒhp Òvlázc˜’»$O*é–9q–’ºèµ;âý øu•^|¼äq%×G¤|0~{ÚÆõõv»+ªJQæãºvÏ'É7ƒCë÷šøàvÉòŒbë“ œfšÙ’¯Ç*Ró]\—-²S³® é(^§á;Y’7E’6F wA·#ÂkQ$øà©·GR©Ç­Ä­QŠäîufsàRÜ™¹w>ßéÃU²0ªQQÇX¥)ÐErX>ùòúË¢VdÎ’l®ƒ3¢Tæ¹çë$S)`BY>«$ÿÁ‡¢(Ô"Ï㊂ó£ðáÌfºd34À,ËNèiŒ’ìêôsM{p%N¨ÈX%%+•Ü!uN+í r8]²&œï¥ Y*™S²~x¢@%¶áÌJÓ¼=ìúØHE^ŽòúPØhÜ?ªØ¦`¡KÚ•×2;^Xyƒ+§_²ÞÑ㎠xý4â=#\údüf´ä…h)[£‚-jÿ¸›lç‹1Ub¹«øw¼¢ý³Í[Ë»°Æ9ñÊQ”‡ñ½®=¯ØF&GaèÖæ‰2uÒª&§àÑìa`'zJ{ßf÷JÃ!Û@“?*é…a…ÑS•t7Êíð8iT268ÐqYo0Bò\µÏº ”7±JÉ Yï<ý”lÔäIO%c0;úìÆl•‰R;^uB赓}CÄóE™f[„FC<ÕUeö8ÉŠýûÇÁÝD¯è†Ô8ãY\"y¬3Ãúô7úq'–[ã‘`d-ξhÛs Â¥˜ü~O¼äÝôåÅ×óŸ†G䈑Ã,ÿÁ)ÝG›ŸIEND®B`‚aoflagger-v3.4.0/data/deprecated/0000755000175000017500000000000014516225226015337 5ustar olesolesaoflagger-v3.4.0/data/deprecated/strategy.py0000644000175000017500000000613414507760372017565 0ustar olesolesimport aoflagger import copy import numpy def flag(input): # Values below can be tweaked flag_polarizations = input.polarizations() flag_representations = [aoflagger.ComplexRepresentation.AmplitudePart] iteration_count = 3 threshold_factor_step = 2.0 base_threshold = 1.4 # Use above values to calculate thresholds in each iteration r = range((iteration_count - 1), 0, -1) threshold_factors = numpy.power(threshold_factor_step, r) inpPolarizations = input.polarizations() input.clear_mask() for polarization in flag_polarizations: data = input.convert_to_polarization(polarization) for representation in flag_representations: data = data.convert_to_complex(representation) original_image = copy.copy(data) for threshold_factor in threshold_factors: # print('Flagging polarization ' + str(polarization) + ' (' + str(representation) + ', ' + str(threshold_factor) + ')') thr = threshold_factor * base_threshold aoflagger.sumthreshold(data, thr, thr, True, True) chdata = copy.copy(data) aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms( chdata, 3.0 * threshold_factor, True ) data.join_mask(chdata) data.set_image(original_image) resized_data = aoflagger.shrink(data, 3, 3) aoflagger.low_pass_filter(resized_data, 21, 31, 1.6, 2.2) aoflagger.enlarge(resized_data, data, 3, 3) data = original_image - data aoflagger.sumthreshold( data, base_threshold, base_threshold, True, True ) if polarization in inpPolarizations: data = data.make_complex() input.set_polarization_data(polarization, data) else: input.join_mask(polarization, data) aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) def test_sumthreshold(input): # Values below can be tweaked flag_polarizations = input.polarizations() flag_representations = [aoflagger.ComplexRepresentation.AmplitudePart] iteration_count = 3 threshold_factor_step = 2.0 base_threshold = 1.4 # Use above values to calculate thresholds in iteration r = range((iteration_count - 1), 0, -1) threshold_factors = numpy.power(threshold_factor_step, r) inpPolarizations = input.polarizations() input.clear_mask() for polarization in flag_polarizations: data = input.convert_to_polarization(polarization) for representation in flag_representations: data = data.convert_to_complex(representation) aoflagger.sumthreshold(data, base_threshold, True, True) if polarization in inpPolarizations: data = data.make_complex() input.set_polarization_data(polarization, data) else: input.join_mask(polarization, data) aoflagger.set_flag_function(flag) print("strategy.py parsed") aoflagger-v3.4.0/data/falsepositives.py0000644000175000017500000000204014507760372016653 0ustar olesolesimport aoflagger import numpy import sys nch = 256 ntimes = 1000 count = 50 # number of trials in the false-positives test flagger = aoflagger.AOFlagger() path = flagger.find_strategy_file(aoflagger.TelescopeId.Generic) strategy = flagger.load_strategy_file(path) data = flagger.make_image_set(ntimes, nch, 8) ratiosum = 0.0 ratiosumsq = 0.0 for repeat in range(count): for imgindex in range(8): # Initialize data with random numbers values = numpy.random.normal(0, 1, [nch, ntimes]) data.set_image_buffer(imgindex, values) flags = strategy.run(data) flagvalues = flags.get_buffer() ratio = float(sum(sum(flagvalues))) / (nch * ntimes) ratiosum += ratio ratiosumsq += ratio * ratio sys.stdout.write(".") sys.stdout.flush() print("") print( "Percentage flags (false-positive rate) on Gaussian data: " + str(ratiosum * 100.0 / count) + "% +/- " + str( numpy.sqrt( (ratiosumsq / count - ratiosum * ratiosum / (count * count)) ) * 100.0 ) ) aoflagger-v3.4.0/data/strategies/0000755000175000017500000000000014516225226015411 5ustar olesolesaoflagger-v3.4.0/data/strategies/lofar-lba-wideband.lua0000644000175000017500000001277514507760372021550 0ustar olesoles--[[ This is a LBA AOFlagger strategy for combined subbands, version 2021-03-30 Author: André Offringa ]] aoflagger.require_min_version("3.1") function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() local base_threshold = 1.2 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } local iteration_count = 5 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = true local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() if not exclude_original_flags then input:clear_mask() end -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() aoflagger.normalize_bandpass(input) for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local converted_data local converted_copy for _, representation in ipairs(flag_representations) do converted_data = pol_data:convert_to_complex(representation) converted_copy = converted_data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end -- Do timestep & channel flagging local chdata = converted_data:copy() aoflagger.threshold_timestep_rms(converted_data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) converted_data:join_mask(chdata) -- High pass filtering steps converted_data:set_visibilities(converted_copy) if exclude_original_flags then converted_data:join_mask(converted_copy) end aoflagger.low_pass_filter(converted_data, 21, 31, 1.0, 1.0) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(converted_data, "Fit #" .. i, i - 1) local tmp = converted_copy - converted_data tmp:set_mask(converted_data) converted_data = tmp aoflagger.visualize(converted_data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then converted_data:join_mask(converted_copy) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then converted_data = converted_data:convert_to_complex("complex") end input:set_polarization_data(polarization, converted_data) else input:join_mask(converted_data) end aoflagger.visualize(converted_data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end aoflagger.threshold_timestep_rms(input, 4.0) if input:is_complex() and input:has_metadata() then -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end input:flag_nans() end aoflagger-v3.4.0/data/strategies/nenufar-default.lua0000644000175000017500000001336014507760372021205 0ustar olesoles--[[ This is a NenuFAR strategy. It was made by Florent Mertens by tweaking the LOFAR strategy. Version 2021-03-30. Author: Florent Mertens ]] aoflagger.require_min_version("3.0") function execute(input) -- -- Generic settings -- -- What polarizations to flag? local flag_polarizations = input:get_polarizations() if input:is_auto_correlation() then flag_polarizations = { "XY", "YX" } end local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } -- LOFAR uses 3 iterations, but Florent found that 4 is better for NenuFAR. local iteration_count = 4 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = false local frequency_resize_factor = 1.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() if not exclude_original_flags then input:clear_mask() end -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local converted_data local converted_copy for _, representation in ipairs(flag_representations) do converted_data = pol_data:convert_to_complex(representation) converted_copy = converted_data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end -- Do timestep & channel flagging local chdata = converted_data:copy() aoflagger.threshold_timestep_rms(converted_data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) converted_data:join_mask(chdata) -- High pass filtering steps converted_data:set_visibilities(converted_copy) if exclude_original_flags then converted_data:join_mask(converted_copy) end local resized_data = aoflagger.downsample(converted_data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, converted_data, 3, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(converted_data, "Fit #" .. i, i - 1) local tmp = converted_copy - converted_data tmp:set_mask(converted_data) converted_data = tmp aoflagger.visualize(converted_data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then converted_data:join_mask(converted_copy) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then converted_data = converted_data:convert_to_complex("complex") end input:set_polarization_data(polarization, converted_data) else input:join_mask(converted_data) end aoflagger.visualize(converted_data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end aoflagger.threshold_timestep_rms(input, 4.0) if input:is_complex() and input:has_metadata() then -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end input:flag_nans() end aoflagger-v3.4.0/data/strategies/atca-default.lua0000644000175000017500000001443114507760372020457 0ustar olesoles--[[ This is a strategy for ATCA wideband L-band, data version 2021-03-30 Author: André Offringa It's based on 3 observations provided by Björn Adebahr and Ancla Müller. It works well on both the target as calibrator observations. Baseline CA4 x CA5 has so much RFI that it probably should be flagged in full -- This strategy flags 70% of that baseline, but the other 30% seems also bad. Changes compared to the generic strategy: - Don't flag on Stokes I, only on Q, U and V. The bandpass structure has too many features. - Base theshold is set to 1.2. This can be further tweaked to control the level of flagged data vs. the level of residual RFI. - frequency resize factor is set to 3, which makes the background fit somewhat more stable. The large bandwidth vs. the "resolved" RFI features make this necessary. ]] aoflagger.require_min_version("3.0") function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations if #input:get_polarizations() == 4 then flag_polarizations = { "Q", "U", "V" } else flag_polarizations = input:get_polarizations() end local base_threshold = 1.6 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } local iteration_count = 6 -- how many iterations to perform? local threshold_factor_step = 1.5 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = true local frequency_resize_factor = 3.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() if not exclude_original_flags then input:clear_mask() end -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local original_data for _, representation in ipairs(flag_representations) do data = pol_data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( data, original_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) if exclude_original_flags then data:join_mask(original_data) end local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 51, 51, 2.5, 5.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(data, "Fit #" .. i, i - 1) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations if exclude_original_flags then aoflagger.sumthreshold_masked( data, original_data, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then data:join_mask(original_data) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) else input:join_mask(data) end aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end aoflagger.threshold_timestep_rms(input, 4.0) if input:is_complex() and input:has_metadata() then -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end end aoflagger-v3.4.0/data/strategies/apertif-2021-03-09.lua0000644000175000017500000001650714507760372020615 0ustar olesoles--[[ This is the Apertif Lua strategy, version 2021-03-09 Author: André Offringa Compared to the standard AOFlagger strategy, it has roughly the following changes: - Take input flags into account (e.g. when the correlator produces missing data) - Any 'exact' zero visibility is flagged, as these are produced in case of correlator failure - Apply a bandpass file. The bandpass can be set with the "-preamble bandpass_filename='..'" parameter - Auto-correlations are flagged, and flagged with a different (less sensitive) strategy - Channels in the range 1418-1424 MHz are flagged differently, as they are mostly without RFI and might contain strong HI in case a nearby Galaxy is observed. - Apart from that, settings like the thresholds and the smoothing filter strength have been tweaked to work well for Apertif. - Time thresholding is made dependent of iteration threshold ]] aoflagger.require_min_version("3.0.4") if bandpass_filename == nil then bandpass_filename = "Bpass.txt" end -- Main flagging function that is called for every baseline. The input parameter represents the data for -- a single baseline. Any changes to the flagging of 'input' are written back to the measurement set. function execute(input) aoflagger.apply_bandpass(input, bandpass_filename) -- Any visibilities that are exactly zero? Flag them. for _, polarization in ipairs(input:get_polarizations()) do data = input:convert_to_polarization(polarization) data:flag_zeros() input:set_polarization_data(polarization, data) end local copy_of_input = input:copy() detect_rfi(input, false) local trimmed = aoflagger.trim_frequencies(copy_of_input, 1412, 1426) detect_rfi(trimmed, true) local trimmed = aoflagger.trim_frequencies(trimmed, 1418, 1424) aoflagger.copy_to_frequency(input, trimmed, 1418) aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end function detect_rfi(input, avoid_lines) -- -- Generic settings -- local iteration_count = 3 -- slowly increase sensitivity: how many iterations to do this? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 175 -- Amount of "extra" smoothing in frequency direction -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local flag_representations = { "amplitude" } local channel_window_size = 31 local channel_window_kernel = 5.0 local sumthr_level_time = 1.2 local sumthr_level_freq = 1.2 local timestep_threshold1 = 3.5 local timestep_threshold2 = 4.0 -- -- End of generic settings -- -- Some variables that we need later on: local isAutocorrelation = (input:get_antenna1_index() == input:get_antenna2_index()) local inpPolarizations = input:get_polarizations() if isAutocorrelation then iteration_count = 5 -- Auto-correlations have more dynamic range, so converge slightly slower frequency_resize_factor = 50 -- Auto-correlations have more structure in frequency direction, so smooth less transient_threshold_factor = 0.25 -- More emphasis on transients (~less emphasis on frequency structure) sumthr_level_time = 2 sumthr_level_freq = 8 -- Because of the high S/N of autos, less sensitive detection is required -- XY=YX for amplitude of autos, so there's no need to flag both for i, v in ipairs(flag_polarizations) do if v == "YX" then table.remove(flag_polarizations, i) break end end end if avoid_lines then -- Make sure that first iteration has a very high threshold, so that all HI is avoided iteration_count = 5 threshold_factor_step = 4.0 frequency_resize_factor = 1 channel_window_size = 21 channel_window_kernel = 0.05 sumthr_level_time = 2.8 sumthr_level_freq = 4.8 timestep_threshold1 = 6.0 timestep_threshold2 = 8.0 end for ipol, polarization in ipairs(flag_polarizations) do data = input:convert_to_polarization(polarization) local original_data for _, representation in ipairs(flag_representations) do data = data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) aoflagger.sumthreshold_masked( data, original_data, sumthr_level_freq * threshold_factor, sumthr_level_time * threshold_factor, true, true ) -- Do timestep & channel flagging if not isAutocorrelation then local chdata = data:copy() aoflagger.threshold_timestep_rms(data, timestep_threshold1 * threshold_factor) if not avoid_lines then aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) end end -- High pass filtering steps data:set_visibilities(original_data) data:join_mask(original_data) local resized_data = aoflagger.downsample(data, 1, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, channel_window_size, 2.5, channel_window_kernel) aoflagger.upsample(resized_data, data, 1, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. if not avoid_lines then aoflagger.visualize(data, "Fit #" .. i, i - 1) end local tmp = original_data - data tmp:set_mask(data) data = tmp if not avoid_lines then aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end end -- end of iterations aoflagger.sumthreshold_masked(data, original_data, sumthr_level_freq, sumthr_level_time, true, true) end -- end of complex representation iteration data:join_mask(original_data) if not isAutocorrelation then aoflagger.threshold_timestep_rms(data, timestep_threshold2) end -- Helper function function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) else input:join_mask(data) end if not avoid_lines then aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end end -- end of polarization iterations end aoflagger-v3.4.0/data/strategies/arecibo-default.lua0000644000175000017500000000534214507760372021154 0ustar olesoles--[[ This is the Arecibo strategy, version 2020-07-18. Author: André Offringa ]] function options() arecibo = {} arecibo.baselines = "all" return { arecibo } end function execute(input) -- -- Generic settings -- local base_threshold = 1.2 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 3.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(inpPolarizations) do local data = input:convert_to_polarization(polarization) data = data:convert_to_complex(representation) local original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) input:flag_nans() end aoflagger-v3.4.0/data/strategies/apertif-2020-02-26-with-autocorrelations.lua0000644000175000017500000001434114507760372025150 0ustar olesoles--[[ This is the Apertif Lua strategy, version 2020-02-27 Author: André Offringa Compared to the standard AOFlagger strategy, it has roughly the following changes: - Take input flags into account (e.g. when the correlator produces missing data) - Any 'exact' zero visibility is flagged, as these are produced in case of correlator failure - Apply a bandpass file. The bandpass can be set with the "-preamble bandpass_filename='..'" parameter - Auto-correlations are flagged, and flagged with a different (less sensitive) strategy - Channels in the range 1418-1424 MHz are excluded from detection, as they are mostly without RFI and might contain strong HI in case a nearby Galaxy is observed. - Apart from that, settings like the thresholds and the smoothing filter strength have been tweaked to work well for Apertif. ]] -- Helper function used in the strategy function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if bandpass_filename == nil then bandpass_filename = "bandpass.txt" print("bandpass_filename not set, using " .. bandpass_filename) end -- Main flagging function that is called for every baseline. The input parameter represents the data for -- a single baseline. Any changes to the flagging of 'input' are written back to the measurement set. function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() -- Options are: phase, amplitude, real, imaginary, complex local flag_representations = { "amplitude" } local base_threshold = 1.2 -- lower means more sensitive detection local iteration_count = 3 -- slowly increase sensitivity: how many iterations to do this? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 175 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1 -- decreasing this value puts more emphasis on detection of transient RFI -- -- End of generic settings -- -- Some variables that we need later on: local isAutocorrelation = (input:get_antenna1_index() == input:get_antenna2_index()) local inpPolarizations = input:polarizations() aoflagger.apply_bandpass(input, bandpass_filename) if isAutocorrelation then base_threshold = 8 -- Because of the high S/N of autos, less sensitive detection is required iteration_count = 5 -- Auto-correlations have more dynamic range, so converge slightly slower frequency_resize_factor = 50 -- Auto-correlations have more structure in frequency direction, so smooth less transient_threshold_factor = 0.25 -- More emphasis on transients (~less emphasis on frequency structure) -- XY=YX for amplitude of autos, so there's no need to flag both for i, v in ipairs(flag_polarizations) do if v == "YX" then table.remove(flag_polarizations, i) break end end end local copy_of_input = input:copy() for _, polarization in ipairs(flag_polarizations) do data = input:convert_to_polarization(polarization) for _, representation in ipairs(flag_representations) do data = data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do threshold_factor = threshold_factor_step ^ (iteration_count - i) sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold_with_missing( data, original_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) -- Do timestep & channel flagging if not isAutocorrelation then local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) end -- High pass filtering steps data:set_visibilities(original_data) data:join_mask(original_data) data:flag_zeros() local resized_data = aoflagger.downsample(data, 1, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 1, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(data, "Fit #" .. i, i - 1) tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) end -- end of iterations aoflagger.sumthreshold_with_missing( data, original_data, base_threshold, base_threshold * transient_threshold_factor, true, true ) end -- end of complex representation iteration data:join_mask(original_data) if not isAutocorrelation then aoflagger.threshold_timestep_rms(data, 4.0) end if contains(inpPolarizations, polarization) then data = data:make_complex() input:set_polarization_data(polarization, data) else input:join_mask(polarization, data) end aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator_with_missing(input, copy_of_input, 0.2, 0.2) -- The following statement restores the flagging as it was before RFI detection -- for the frequency range 1418-1424 MHz. This range is considered clean for Apertif, -- hence any flags there are more likely to be false positives. This is in -- particular important when observing bright Galaxies that might show HI lines that -- are bright enough to get flagged. input:set_mask_for_channel_range(copy_of_input, 1418, 1424) -- Any visibilities that are exactly zero? Flag them. input:flag_zeros() end aoflagger-v3.4.0/data/strategies/mwa-default.lua0000644000175000017500000001214614507760372020334 0ustar olesoles--[[ This is the MWA AOFlagger strategy, version 2021-03-30 Author: André Offringa ]] aoflagger.require_min_version("3.0") function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = true local frequency_resize_factor = 3 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() local copy_of_input if exclude_original_flags then -- For collecting statistics copy_of_input = input:copy() else input:clear_mask() end for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local data local original_data for _, representation in ipairs(flag_representations) do data = pol_data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( data, original_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) if exclude_original_flags then data:join_mask(original_data) end local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, false) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(data, "Fit #" .. i, i - 1) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations aoflagger.normalize_subbands(data, 48) if exclude_original_flags then aoflagger.sumthreshold_masked( data, original_data, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then data:join_mask(original_data) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) else input:join_mask(data) end aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end aoflagger.threshold_timestep_rms(input, 4.0) end aoflagger-v3.4.0/data/strategies/lofar-beamformed.lua0000644000175000017500000001552414507760372021333 0ustar olesoles--[[ This is a strategy for LOFAR high-time resolution beam-formed data, version 2022-08-17 Author: André Offringa It is based on the 'generic' strategy, but adds dynamic thresholding based on the time-frequency local RMS. ]] aoflagger.require_min_version("3.2.1") function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() local base_threshold = 1.5 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } local iteration_count = 10 -- how many iterations to perform? local threshold_factor_step = 3.0 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = false local frequency_resize_factor = 5.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() if not exclude_original_flags then input:clear_mask() end -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local converted_data local converted_copy for _, representation in ipairs(flag_representations) do converted_data = pol_data:convert_to_complex(representation) converted_copy = converted_data:copy() for i = 1, iteration_count - 1 do s = i if i < iteration_count - 3 then s = i + 3 + 0.6 else s = iteration_count - 0.4 end local threshold_factor = threshold_factor_step ^ (iteration_count - s) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(converted_data, converted_copy, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(converted_data, 0.2, 0.2) end aoflagger.threshold_channel_rms(converted_data, 3.0 * threshold_factor, true) -- High pass filtering steps converted_data:set_visibilities(converted_copy) if exclude_original_flags then converted_data:join_mask(converted_copy) end local resized_data = aoflagger.downsample(converted_data, 1, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, converted_data, 1, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(converted_data, "Fit #" .. i, i - 1) local tmp = converted_copy - converted_data tmp:set_mask(converted_data) converted_data = tmp aoflagger.visualize(converted_data, "Residual #" .. i, i + iteration_count * 2) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) -- Calculate sqrt |x|^2, then smooth it to calculate the local (unnormalized) RMS local deviation = aoflagger.norm(converted_data) local resized_data = aoflagger.downsample(deviation, 2, 5, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, deviation, 2, 5) deviation = aoflagger.sqrt(deviation) aoflagger.visualize(deviation, "Deviation #" .. i, i + iteration_count) -- Divide the data by the local deviation to make the thresholding be relative to the -- local deviation. converted_data = converted_data / deviation aoflagger.visualize(converted_data, "Deviation normalized #" .. i, i + iteration_count * 3) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then converted_data:join_mask(converted_copy) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then converted_data = converted_data:convert_to_complex("complex") end input:set_polarization_data(polarization, converted_data) else input:join_mask(converted_data) end aoflagger.visualize(converted_data, "Residual #" .. iteration_count, 4 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end if input:is_complex() and input:has_metadata() then -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end input:flag_nans() end aoflagger-v3.4.0/data/strategies/apertif-2020-05-19.lua0000644000175000017500000001532214507760372020611 0ustar olesoles--[[ This is the Apertif Lua strategy, version 2020-05-19 Author: André Offringa Compared to the standard AOFlagger strategy, it has roughly the following changes: - Take input flags into account (e.g. when the correlator produces missing data) - Any 'exact' zero visibility is flagged, as these are produced in case of correlator failure - Apply a bandpass file. The bandpass can be set with the "-preamble bandpass_filename='..'" parameter - Auto-correlations are flagged, and flagged with a different (less sensitive) strategy - Channels in the range 1418-1424 MHz are excluded from detection, as they are mostly without RFI and might contain strong HI in case a nearby Galaxy is observed. [Currently turned off] - Apart from that, settings like the thresholds and the smoothing filter strength have been tweaked to work well for Apertif. ]] -- Helper function used in the strategy function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if bandpass_filename == nil then bandpass_filename = "bandpass.txt" print("bandpass_filename not set, using " .. bandpass_filename) end -- Main flagging function that is called for every baseline. The input parameter represents the data for -- a single baseline. Any changes to the flagging of 'input' are written back to the measurement set. function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() -- Options are: phase, amplitude, real, imaginary, complex local flag_representations = { "amplitude" } local base_threshold = 1.2 -- lower means more sensitive detection local iteration_count = 3 -- slowly increase sensitivity: how many iterations to do this? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 175 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1 -- decreasing this value puts more emphasis on detection of transient RFI -- -- End of generic settings -- -- Some variables that we need later on: local isAutocorrelation = (input:get_antenna1_index() == input:get_antenna2_index()) local inpPolarizations = input:polarizations() if isAutocorrelation then base_threshold = 8 -- Because of the high S/N of autos, less sensitive detection is required iteration_count = 5 -- Auto-correlations have more dynamic range, so converge slightly slower frequency_resize_factor = 50 -- Auto-correlations have more structure in frequency direction, so smooth less transient_threshold_factor = 0.25 -- More emphasis on transients (~less emphasis on frequency structure) -- XY=YX for amplitude of autos, so there's no need to flag both for i, v in ipairs(flag_polarizations) do if v == "YX" then table.remove(flag_polarizations, i) break end end end aoflagger.apply_bandpass(input, bandpass_filename) -- Any visibilities that are exactly zero? Flag them. input:flag_zeros() local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do data = input:convert_to_polarization(polarization) local original_data for _, representation in ipairs(flag_representations) do data = data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do threshold_factor = threshold_factor_step ^ (iteration_count - i) sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold_with_missing( data, original_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) -- Do timestep & channel flagging if not isAutocorrelation then chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) end -- High pass filtering steps data:set_visibilities(original_data) data:join_mask(original_data) resized_data = aoflagger.downsample(data, 1, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 1, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(data, "Fit #" .. i, i - 1) tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) --aoflagger.set_progress((ipol-1)*iteration_count+i, #flag_polarizations*iteration_count ) end -- end of iterations aoflagger.sumthreshold_with_missing( data, original_data, base_threshold, base_threshold * transient_threshold_factor, true, true ) end -- end of complex representation iteration data:join_mask(original_data) if not isAutocorrelation then aoflagger.threshold_timestep_rms(data, 4.0) end if contains(inpPolarizations, polarization) then data = data:make_complex() input:set_polarization_data(polarization, data) else input:join_mask(polarization, data) end aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) --aoflagger.set_progress(ipol, #flag_polarizations ) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator_with_missing(input, copy_of_input, 0.2, 0.2) -- The following statement restores the flagging as it was before RFI detection -- for the frequency range 1418-1424 MHz. This range is considered clean for Apertif, -- hence any flags there are more likely to be false positives. This is in -- particular important when observing bright Galaxies that might show HI lines that -- are bright enough to get flagged. -- Turned off after testing 2020-05-19: broadband RFI causes the images to have striping -- input:set_mask_for_channel_range(copy_of_input, 1418, 1424) -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end aoflagger-v3.4.0/data/strategies/apertif-default.lua0000644000175000017500000001646214507760372021207 0ustar olesoles--[[ This is the Apertif Lua strategy, version 2021-03-09 Author: André Offringa Compared to the standard AOFlagger strategy, it has roughly the following changes: - Take input flags into account (e.g. when the correlator produces missing data) - Any 'exact' zero visibility is flagged, as these are produced in case of correlator failure - Apply a bandpass file. The bandpass can be set with the "-preamble bandpass_filename='..'" parameter - Auto-correlations are flagged, and flagged with a different (less sensitive) strategy - Channels in the range 1418-1424 MHz are flagged differently, as they are mostly without RFI and might contain strong HI in case a nearby galaxy is observed. - Apart from that, settings like the thresholds and the smoothing filter strength have been tweaked to work well for Apertif. - Time thresholding is made dependent of iteration threshold ]] aoflagger.require_min_version("3.0.4") -- Main flagging function that is called for every baseline. The input parameter represents the data for -- a single baseline. Any changes to the flagging of 'input' are written back to the measurement set. function execute(input) if bandpass_filename ~= nil then aoflagger.apply_bandpass(input, bandpass_filename) end -- Any visibilities that are exactly zero? Flag them. for _, polarization in ipairs(input:get_polarizations()) do data = input:convert_to_polarization(polarization) data:flag_zeros() input:set_polarization_data(polarization, data) end local copy_of_input = input:copy() detect_rfi(input, false) local trimmed = aoflagger.trim_frequencies(copy_of_input, 1412, 1426) detect_rfi(trimmed, true) local trimmed = aoflagger.trim_frequencies(trimmed, 1418, 1424) aoflagger.copy_to_frequency(input, trimmed, 1418) aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. if input:has_metadata() then aoflagger.collect_statistics(input, copy_of_input) end end function detect_rfi(input, avoid_lines) -- -- Generic settings -- local iteration_count = 3 -- slowly increase sensitivity: how many iterations to do this? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 175 -- Amount of "extra" smoothing in frequency direction -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local flag_representations = { "amplitude" } local channel_window_size = 31 local channel_window_kernel = 5.0 local sumthr_level_time = 1.2 local sumthr_level_freq = 1.2 local timestep_threshold1 = 3.5 local timestep_threshold2 = 4.0 -- -- End of generic settings -- -- Some variables that we need later on: local isAutocorrelation = input:is_auto_correlation() local inpPolarizations = input:get_polarizations() if isAutocorrelation then iteration_count = 5 -- Auto-correlations have more dynamic range, so converge slightly slower frequency_resize_factor = 50 -- Auto-correlations have more structure in frequency direction, so smooth less transient_threshold_factor = 0.25 -- More emphasis on transients (~less emphasis on frequency structure) sumthr_level_time = 2 sumthr_level_freq = 8 -- Because of the high S/N of autos, less sensitive detection is required -- XY=YX for amplitude of autos, so there's no need to flag both for i, v in ipairs(flag_polarizations) do if v == "YX" then table.remove(flag_polarizations, i) break end end end if avoid_lines then -- Make sure that first iteration has a very high threshold, so that all HI is avoided iteration_count = 5 threshold_factor_step = 4.0 frequency_resize_factor = 1 channel_window_size = 21 channel_window_kernel = 0.05 sumthr_level_time = 2.8 sumthr_level_freq = 4.8 timestep_threshold1 = 6.0 timestep_threshold2 = 8.0 end for ipol, polarization in ipairs(flag_polarizations) do data = input:convert_to_polarization(polarization) local original_data for _, representation in ipairs(flag_representations) do data = data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) aoflagger.sumthreshold_masked( data, original_data, sumthr_level_freq * threshold_factor, sumthr_level_time * threshold_factor, true, true ) -- Do timestep & channel flagging if not isAutocorrelation then local chdata = data:copy() aoflagger.threshold_timestep_rms(data, timestep_threshold1 * threshold_factor) if not avoid_lines then aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) end end -- High pass filtering steps data:set_visibilities(original_data) data:join_mask(original_data) local resized_data = aoflagger.downsample(data, 1, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, channel_window_size, 2.5, channel_window_kernel) aoflagger.upsample(resized_data, data, 1, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. if not avoid_lines then aoflagger.visualize(data, "Fit #" .. i, i - 1) end local tmp = original_data - data tmp:set_mask(data) data = tmp if not avoid_lines then aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end end -- end of iterations aoflagger.sumthreshold_masked(data, original_data, sumthr_level_freq, sumthr_level_time, true, true) end -- end of complex representation iteration data:join_mask(original_data) if not isAutocorrelation then aoflagger.threshold_timestep_rms(data, timestep_threshold2) end -- Helper function function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) else input:join_mask(data) end if not avoid_lines then aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end end -- end of polarization iterations end aoflagger-v3.4.0/data/strategies/parkes-default.lua0000644000175000017500000000531214507760372021032 0ustar olesoles--[[ This is the Parkes strategy, version 2020-07-18. Author: André Offringa ]] function options() parkes = {} parkes.baselines = "all" return { parkes } end function execute(input) -- -- Generic settings -- local base_threshold = 1.4 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 3.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(inpPolarizations) do local data = input:convert_to_polarization(polarization) data = data:convert_to_complex(representation) local original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) end aoflagger-v3.4.0/data/strategies/jvla-default.lua0000644000175000017500000000516514507760372020507 0ustar olesoles--[[ This is the JVLA strategy, version 2020-06-14 It is based on the generic "minimal" AOFlagger strategy, version 2020-06-14 Author: André Offringa ]] function execute(input) -- -- Generic settings -- local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 1.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(inpPolarizations) do local data = input:convert_to_polarization(polarization) data = data:convert_to_complex(representation) local original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) -- Do timestep & channel flagging aoflagger.threshold_timestep_rms(data, 3.5) -- High pass filtering steps data:set_visibilities(original_data) local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 1.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.normalize_subbands(data, 48) aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) input:flag_nans() end aoflagger-v3.4.0/data/strategies/apertif-2021-02-14.lua0000644000175000017500000001601714507760372020604 0ustar olesoles--[[ This is the Apertif Lua strategy, version 2021-02-14 Author: André Offringa Compared to the standard AOFlagger strategy, it has roughly the following changes: - Take input flags into account (e.g. when the correlator produces missing data) - Any 'exact' zero visibility is flagged, as these are produced in case of correlator failure - Apply a bandpass file. The bandpass can be set with the "-preamble bandpass_filename='..'" parameter - Auto-correlations are flagged, and flagged with a different (less sensitive) strategy - Channels in the range 1418-1424 MHz are excluded from detection, as they are mostly without RFI and might contain strong HI in case a nearby Galaxy is observed. [Currently turned off] - Apart from that, settings like the thresholds and the smoothing filter strength have been tweaked to work well for Apertif. ]] aoflagger.require_min_version("3.0.4") -- Main flagging function that is called for every baseline. The input parameter represents the data for -- a single baseline. Any changes to the flagging of 'input' are written back to the measurement set. function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() local base_threshold = 1.2 -- lower means more sensitive detection local iteration_count = 3 -- slowly increase sensitivity: how many iterations to do this? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 175 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1 -- decreasing this value puts more emphasis on detection of transient RFI -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local flag_representations = { "amplitude" } -- -- End of generic settings -- -- Some variables that we need later on: local isAutocorrelation = input:is_auto_correlation() local inpPolarizations = input:get_polarizations() if isAutocorrelation then base_threshold = 8 -- Because of the high S/N of autos, less sensitive detection is required iteration_count = 5 -- Auto-correlations have more dynamic range, so converge slightly slower frequency_resize_factor = 50 -- Auto-correlations have more structure in frequency direction, so smooth less transient_threshold_factor = 0.25 -- More emphasis on transients (~less emphasis on frequency structure) -- XY=YX for amplitude of autos, so there's no need to flag both for i, v in ipairs(flag_polarizations) do if v == "YX" then table.remove(flag_polarizations, i) break end end end if bandpass_filename ~= nil then aoflagger.apply_bandpass(input, bandpass_filename) end -- Any visibilities that are exactly zero? Flag them. for _, polarization in ipairs(input:get_polarizations()) do data = input:convert_to_polarization(polarization) data:flag_zeros() input:set_polarization_data(polarization, data) end local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do data = input:convert_to_polarization(polarization) local original_data for _, representation in ipairs(flag_representations) do data = data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold_masked( data, original_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) -- Do timestep & channel flagging if not isAutocorrelation then local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) end -- High pass filtering steps data:set_visibilities(original_data) data:join_mask(original_data) local resized_data = aoflagger.downsample(data, 1, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 1, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(data, "Fit #" .. i, i - 1) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.sumthreshold_masked( data, original_data, base_threshold, base_threshold * transient_threshold_factor, true, true ) end -- end of complex representation iteration data:join_mask(original_data) if not isAutocorrelation then aoflagger.threshold_timestep_rms(data, 4.0) end -- Helper function used in the strategy function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) else input:join_mask(polarization, data) end input:set_polarization_data(polarization, data) aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) -- The following statement restores the flagging as it was before RFI detection -- for the frequency range 1418-1424 MHz. This range is considered clean for Apertif, -- hence any flags there are more likely to be false positives. This is in -- particular important when observing bright Galaxies that might show HI lines that -- are bright enough to get flagged. -- Turned off after testing 2020-05-19: broadband RFI causes the images to have striping -- input:set_mask_for_channel_range(copy_of_input, 1418, 1424) -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. if input:has_metadata() then aoflagger.collect_statistics(input, copy_of_input) end end aoflagger-v3.4.0/data/strategies/lofar-default.lua0000644000175000017500000000531114507760372020647 0ustar olesoles--[[ This is the LOFAR strategy. It is almost equal to the generic "minimal" AOFlagger strategy, version 2020-06-14. Author: André Offringa ]] function execute(input) -- -- Generic settings -- local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 3.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(inpPolarizations) do local data = input:convert_to_polarization(polarization) data = data:convert_to_complex(representation) local original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) input:flag_nans() end aoflagger-v3.4.0/data/strategies/generic-default.lua0000644000175000017500000001360614507760372021166 0ustar olesoles--[[ This is the default AOFlagger strategy, version 2021-03-30 Author: André Offringa This strategy is made as generic / easy to tweak as possible, with the most important 'tweaking' parameters available as variables at the beginning of function 'execute'. ]] aoflagger.require_min_version("3.0") function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = true local frequency_resize_factor = 1.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() if not exclude_original_flags then input:clear_mask() end -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local converted_data local converted_copy for _, representation in ipairs(flag_representations) do converted_data = pol_data:convert_to_complex(representation) converted_copy = converted_data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end -- Do timestep & channel flagging local chdata = converted_data:copy() aoflagger.threshold_timestep_rms(converted_data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) converted_data:join_mask(chdata) -- High pass filtering steps converted_data:set_visibilities(converted_copy) if exclude_original_flags then converted_data:join_mask(converted_copy) end local resized_data = aoflagger.downsample(converted_data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, converted_data, 3, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(converted_data, "Fit #" .. i, i - 1) local tmp = converted_copy - converted_data tmp:set_mask(converted_data) converted_data = tmp aoflagger.visualize(converted_data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then converted_data:join_mask(converted_copy) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then converted_data = converted_data:convert_to_complex("complex") end input:set_polarization_data(polarization, converted_data) else input:join_mask(converted_data) end aoflagger.visualize(converted_data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end aoflagger.threshold_timestep_rms(input, 4.0) if input:is_complex() and input:has_metadata() then -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end input:flag_nans() end aoflagger-v3.4.0/data/strategies/lofar-hba-wideband.lua0000644000175000017500000001320014507760372021524 0ustar olesoles--[[ This is a HBA AOFlagger strategy for combined subbands, version 2023-07-27 It is designed for the LINC pipeline. Author: André Offringa This strategy is a modification of the default LOFAR strategy, tested on averaged datasets with a resolution of 10s and 2ch/sb. ]] aoflagger.require_min_version("3.1") function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = input:get_polarizations() local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = true local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() if not exclude_original_flags then input:clear_mask() end -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local converted_data local converted_copy for _, representation in ipairs(flag_representations) do converted_data = pol_data:convert_to_complex(representation) converted_copy = converted_data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end -- Do timestep & channel flagging local chdata = converted_data:copy() aoflagger.threshold_timestep_rms(converted_data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) converted_data:join_mask(chdata) -- High pass filtering steps converted_data:set_visibilities(converted_copy) if exclude_original_flags then converted_data:join_mask(converted_copy) end aoflagger.low_pass_filter(converted_data, 21, 31, 2.5, 5.0) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(converted_data, "Fit #" .. i, i - 1) local tmp = converted_copy - converted_data tmp:set_mask(converted_data) converted_data = tmp aoflagger.visualize(converted_data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations if exclude_original_flags then aoflagger.sumthreshold_masked( converted_data, converted_copy, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(converted_data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then converted_data:join_mask(converted_copy) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then converted_data = converted_data:convert_to_complex("complex") end input:set_polarization_data(polarization, converted_data) else input:join_mask(converted_data) end aoflagger.visualize(converted_data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end aoflagger.threshold_timestep_rms(input, 4.0) if input:is_complex() and input:has_metadata() then -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end input:flag_nans() end aoflagger-v3.4.0/data/strategies/atca-l-band.lua0000644000175000017500000001423014507760372020165 0ustar olesoles--[[ This is a strategy for ATCA wideband L-band, data version 2021-03-30 Author: André Offringa It's based on 3 observations provided by Björn Adebahr and Ancla Müller. It works well on both the target as calibrator observations. Baseline CA4 x CA5 has so much RFI that it probably should be flagged in full -- This strategy flags 70% of that baseline, but the other 30% seems also bad. Changes compared to the generic strategy: - Don't flag on Stokes I, only on Q, U and V. The bandpass structure has too many features. - Base theshold is set to 1.2. This can be further tweaked to control the level of flagged data vs. the level of residual RFI. - frequency resize factor is set to 3, which makes the background fit somewhat more stable. The large bandwidth vs. the "resolved" RFI features make this necessary. ]] aoflagger.require_min_version("3.0") function execute(input) -- -- Generic settings -- -- What polarizations to flag? Default: input:get_polarizations() (=all that are in the input data) -- Other options are e.g.: -- { 'XY', 'YX' } to flag only XY and YX, or -- { 'I', 'Q' } to flag only on Stokes I and Q local flag_polarizations = { "Q", "U", "V" } local base_threshold = 1.6 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex -- May have multiple values to perform detection multiple times local flag_representations = { "amplitude" } local iteration_count = 6 -- how many iterations to perform? local threshold_factor_step = 1.5 -- How much to increase the sensitivity each iteration? -- If the following variable is true, the strategy will consider existing flags -- as bad data. It will exclude flagged data from detection, and make sure that any existing -- flags on input will be flagged on output. If set to false, existing flags are ignored. local exclude_original_flags = true local frequency_resize_factor = 3.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() if not exclude_original_flags then input:clear_mask() end -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(flag_polarizations) do local pol_data = input:convert_to_polarization(polarization) local original_data for _, representation in ipairs(flag_representations) do data = pol_data:convert_to_complex(representation) original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold if exclude_original_flags then aoflagger.sumthreshold_masked( data, original_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) end -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) if exclude_original_flags then data:join_mask(original_data) end local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 51, 51, 2.5, 5.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(data, "Fit #" .. i, i - 1) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #flag_polarizations * iteration_count) end -- end of iterations if exclude_original_flags then aoflagger.sumthreshold_masked( data, original_data, base_threshold, base_threshold * transient_threshold_factor, true, true ) else aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) end end -- end of complex representation iteration if exclude_original_flags then data:join_mask(original_data) end -- Helper function used below function contains(arr, val) for _, v in ipairs(arr) do if v == val then return true end end return false end if contains(inpPolarizations, polarization) then if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) else input:join_mask(data) end aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #flag_polarizations) end -- end of polarization iterations if exclude_original_flags then aoflagger.scale_invariant_rank_operator_masked(input, copy_of_input, 0.2, 0.2) else aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) end aoflagger.threshold_timestep_rms(input, 4.0) if input:is_complex() and input:has_metadata() then -- This command will calculate a few statistics like flag% and stddev over -- time, frequency and baseline and write those to the MS. These can be -- visualized with aoqplot. aoflagger.collect_statistics(input, copy_of_input) end end aoflagger-v3.4.0/data/strategies/aartfaac-default.lua0000644000175000017500000000532714507760372021315 0ustar olesoles--[[ This is the default Aartfaac strategy, which is based on the generic "minimal" AOFlagger strategy, version 2020-06-14 Author: André Offringa ]] aoflagger.require_min_version("3.0") function execute(input) -- -- Generic settings -- local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 1.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() for ipol, polarization in ipairs(inpPolarizations) do local converted_data = input:convert_to_polarization(polarization):convert_to_complex(representation) local converted_copy = converted_data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(converted_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) -- Do timestep & channel flagging local chdata = converted_data:copy() aoflagger.threshold_timestep_rms(converted_data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) converted_data:join_mask(chdata) -- High pass filtering steps converted_data:set_visibilities(converted_copy) local resized_data = aoflagger.downsample(converted_data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, converted_data, 3, frequency_resize_factor) local tmp = converted_copy - converted_data tmp:set_mask(converted_data) converted_data = tmp aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.sumthreshold(converted_data, base_threshold, base_threshold * transient_threshold_factor, true, true) if input:is_complex() then converted_data = converted_data:convert_to_complex("complex") end input:set_polarization_data(polarization, converted_data) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) input:flag_nans() end aoflagger-v3.4.0/data/strategies/generic-minimal.lua0000644000175000017500000000556014507760372021170 0ustar olesoles--[[ This is the generic "minimal" AOFlagger strategy, version 2020-06-14 Author: André Offringa It is functionally equal to the default generic strategy, but removes some of the tweaking parameters and visualization. It is therefore less easy to tweak, but smaller and possibly slightly faster. ]] aoflagger.require_min_version("3.0") function execute(input) -- -- Generic settings -- local base_threshold = 1.0 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 1.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() for ipol, polarization in ipairs(inpPolarizations) do local converted_data = input:convert_to_polarization(polarization):convert_to_complex(representation) local converted_copy = converted_data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(converted_data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) -- Do timestep & channel flagging local chdata = converted_data:copy() aoflagger.threshold_timestep_rms(converted_data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) converted_data:join_mask(chdata) -- High pass filtering steps converted_data:set_visibilities(converted_copy) local resized_data = aoflagger.downsample(converted_data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, converted_data, 3, frequency_resize_factor) local tmp = converted_copy - converted_data tmp:set_mask(converted_data) converted_data = tmp aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.sumthreshold(converted_data, base_threshold, base_threshold * transient_threshold_factor, true, true) if input:is_complex() then converted_data = converted_data:convert_to_complex("complex") end input:set_polarization_data(polarization, converted_data) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) input:flag_nans() end aoflagger-v3.4.0/data/strategies/wsrt-default.lua0000644000175000017500000000541714507760372020552 0ustar olesoles--[[ This is the WSRT strategy, version 2020-07-18. Author: André Offringa ]] function execute(input) -- -- Generic settings -- local base_threshold = 1.4 -- lower means more sensitive detection -- Options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 3 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(inpPolarizations) do local data = input:convert_to_polarization(polarization) data = data:convert_to_complex(representation) local original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(data, sumthr_level, sumthr_level, true, true) -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) local resized_data = aoflagger.downsample(data, 3, 3, false) aoflagger.low_pass_filter(resized_data, 21, 31, 1.6, 2.2) aoflagger.upsample(resized_data, data, 3, 3) -- In case this script is run from inside rfigui, calling -- the following visualize function will add the current result -- to the list of displayable visualizations. -- If the script is not running inside rfigui, the call is ignored. aoflagger.visualize(data, "Fit #" .. i, i - 1) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.visualize(data, "Residual #" .. i, i + iteration_count) aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.sumthreshold(data, base_threshold, base_threshold, true, true) if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) aoflagger.visualize(data, "Residual #" .. iteration_count, 2 * iteration_count) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) input:flag_nans() end aoflagger-v3.4.0/data/strategies/bighorns-default.lua0000644000175000017500000000551314507760372021363 0ustar olesoles--[[ This is the BigHorns strategy, version 2020-06-14. It is based on the generic "minimal" AOFlagger strategy, version 2020-06-14 Author: André Offringa ]] function options() bighorns = {} bighorns.baselines = "all" return { bighorns } end function execute(input) -- -- Generic settings -- local base_threshold = 1.2 -- lower means more sensitive detection -- How to flag complex values, options are: phase, amplitude, real, imaginary, complex local representation = "amplitude" local iteration_count = 5 -- how many iterations to perform? local threshold_factor_step = 2.0 -- How much to increase the sensitivity each iteration? local frequency_resize_factor = 1.0 -- Amount of "extra" smoothing in frequency direction local transient_threshold_factor = 1.0 -- decreasing this value makes detection of transient RFI more aggressive -- -- End of generic settings -- local inpPolarizations = input:get_polarizations() input:clear_mask() -- For collecting statistics. Note that this is done after clear_mask(), -- so that the statistics ignore any flags in the input data. local copy_of_input = input:copy() for ipol, polarization in ipairs(inpPolarizations) do local data = input:convert_to_polarization(polarization) data = data:convert_to_complex(representation) local original_data = data:copy() for i = 1, iteration_count - 1 do local threshold_factor = threshold_factor_step ^ (iteration_count - i) local sumthr_level = threshold_factor * base_threshold aoflagger.sumthreshold(data, sumthr_level, sumthr_level * transient_threshold_factor, true, true) -- Do timestep & channel flagging local chdata = data:copy() aoflagger.threshold_timestep_rms(data, 3.5) aoflagger.threshold_channel_rms(chdata, 3.0 * threshold_factor, true) data:join_mask(chdata) -- High pass filtering steps data:set_visibilities(original_data) local resized_data = aoflagger.downsample(data, 3, frequency_resize_factor, true) aoflagger.low_pass_filter(resized_data, 21, 31, 2.5, 5.0) aoflagger.upsample(resized_data, data, 3, frequency_resize_factor) local tmp = original_data - data tmp:set_mask(data) data = tmp aoflagger.set_progress((ipol - 1) * iteration_count + i, #inpPolarizations * iteration_count) end -- end of iterations aoflagger.normalize_subbands(data, 48) aoflagger.sumthreshold(data, base_threshold, base_threshold * transient_threshold_factor, true, true) if input:is_complex() then data = data:convert_to_complex("complex") end input:set_polarization_data(polarization, data) aoflagger.set_progress(ipol, #inpPolarizations) end -- end of polarization iterations aoflagger.scale_invariant_rank_operator(input, 0.2, 0.2) aoflagger.threshold_timestep_rms(input, 4.0) end aoflagger-v3.4.0/scripts/0000755000175000017500000000000014516225226014015 5ustar olesolesaoflagger-v3.4.0/scripts/docker/0000755000175000017500000000000014516225226015264 5ustar olesolesaoflagger-v3.4.0/scripts/docker/Ubuntu200000644000175000017500000000117714507760372016647 0ustar olesolesFROM ubuntu:20.04 RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ apt-get install -y \ cmake \ build-essential \ pkg-config \ casacore-data casacore-dev \ libblas-dev liblapack-dev \ liblua5.3-dev \ python3 \ libpython3-dev \ libboost-date-time-dev libboost-system-dev \ libgtkmm-3.0-dev \ libcfitsio-dev \ libfftw3-dev \ libgsl-dev \ libhdf5-serial-dev \ libpng-dev ADD . /src WORKDIR /src RUN mkdir /build && cd /build && cmake ../src RUN cd /build && make -j`nproc --all` && make install RUN cd /build/python && echo "import aoflagger" | python3 aoflagger-v3.4.0/scripts/docker/Ubuntu22-clang-libcxx0000644000175000017500000000355414507760372021223 0ustar olesolesFROM ubuntu:22.04 RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ apt-get install -y \ bison \ cmake \ build-essential \ pkg-config \ clang \ flex \ gfortran \ libc++-dev \ libc++abi-dev \ libblas-dev liblapack-dev \ liblua5.3-dev \ libpython3-dev \ libcfitsio-dev \ libfftw3-dev \ libgsl-dev \ libpng-dev \ python3 \ python3-distutils \ wcslib-dev \ wget RUN \ mkdir -p /software && \ cd /software && \ wget -nv -O - https://boostorg.jfrog.io/artifactory/main/release/1.78.0/source/boost_1_78_0.tar.bz2 | tar xj && \ cd boost_1_78_0/ && \ ./bootstrap.sh --with-toolset=clang && \ ./b2 toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" install RUN \ mkdir -p /software && \ cd /software && \ wget -nv -O - https://github.com/HDFGroup/hdf5/archive/refs/tags/hdf5-1_12_1.tar.gz | tar xz && \ cd /software/hdf5-hdf5-1_12_1 && \ CC=/usr/bin/clang CXX=/usr/bin/clang++ CXXFLAGS="-stdlib=libc++" LDFLAGS="-stdlib=libc++" ./configure --prefix /usr/local --enable-cxx && \ make -j`nproc` install RUN \ mkdir -p /software/casacore/build && \ cd /software/casacore && \ wget -nv -O - https://github.com/casacore/casacore/archive/refs/tags/v3.4.0.tar.gz | tar xz && \ cd build && \ cmake \ -DBUILD_TESTING=OFF -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_CXX_FLAGS="-stdlib=libc++" \ -DBUILD_PYTHON=OFF -DBUILD_PYTHON3=OFF \ ../casacore-3.4.0 && \ make install -j`nproc` ADD . /src WORKDIR /src RUN mkdir /build && cd /build && cmake ../src -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_CXX_FLAGS="-stdlib=libc++" RUN cd /build && make -j`nproc --all` && make install RUN cd /build/python && echo "import aoflagger" | python3 aoflagger-v3.4.0/scripts/docker/Debian0000644000175000017500000000120014507760372016370 0ustar olesolesFROM debian:testing RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ apt-get install -y \ cmake \ build-essential \ pkg-config \ casacore-data casacore-dev \ libblas-dev liblapack-dev \ liblua5.3-dev \ python3 \ libpython3-dev \ libboost-date-time-dev libboost-system-dev \ libgtkmm-3.0-dev \ libcfitsio-dev \ libfftw3-dev \ libgsl-dev \ libhdf5-serial-dev \ libpng-dev ADD . /src WORKDIR /src RUN mkdir /build && cd /build && cmake ../src RUN cd /build && make -j`nproc --all` && make install RUN cd /build/python && echo "import aoflagger" | python3.10 aoflagger-v3.4.0/scripts/docker/run.sh0000755000175000017500000000004414507760372016433 0ustar olesolessudo docker build -f Ubuntu22 ../.. aoflagger-v3.4.0/scripts/docker/Ubuntu18-gcc-110000644000175000017500000000154414507760372017625 0ustar olesolesFROM ubuntu:18.04 RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ apt-get install -y \ cmake \ build-essential \ pkg-config \ casacore-data casacore-dev \ libblas-dev liblapack-dev \ liblua5.3-dev \ python3 \ libpython3-dev \ libboost-date-time-dev libboost-system-dev \ libgtkmm-3.0-dev \ libcfitsio-dev \ libfftw3-dev \ libgsl-dev \ libhdf5-serial-dev \ libpng-dev \ software-properties-common && \ echo -ne "\n \n"| add-apt-repository ppa:ubuntu-toolchain-r/test && \ apt-get update -qq && \ apt-get install -y gcc-11 g++-11 gfortran-11 ENV CC=/usr/bin/gcc-11 ENV CXX=/usr/bin/g++-11 ADD . /src WORKDIR /src RUN \ mkdir /build && cd /build && cmake ../src && \ cd /build && make -j`nproc` && make install && \ cd /build/python && echo "import aoflagger" | python3 aoflagger-v3.4.0/scripts/docker/Ubuntu220000644000175000017500000000116114507760372016642 0ustar olesolesFROM ubuntu:22.04 RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ apt-get install -y \ cmake \ build-essential \ pkg-config \ casacore-data casacore-dev \ libblas-dev liblapack-dev \ liblua5.3-dev \ libpython3-dev \ libboost-date-time-dev libboost-system-dev \ libgtkmm-3.0-dev \ libcfitsio-dev \ libfftw3-dev \ libgsl-dev \ libhdf5-serial-dev \ libpng-dev ADD . /src WORKDIR /src RUN mkdir /build && cd /build && cmake ../src RUN cd /build && make -j`nproc --all` && make install RUN cd /build/python && echo "import aoflagger" | python3 aoflagger-v3.4.0/scripts/docker/install_lua.sh0000644000175000017500000000614114507760372020137 0ustar olesoles# Script to install lua set -euo pipefail pushd /tmp echo "Downloading Lua" curl -fsSLO https://www.lua.org/ftp/lua-${LUA_VERSION}.tar.gz tar zxf lua-${LUA_VERSION}.tar.gz echo "Building & installing Lua" pushd lua-${LUA_VERSION} # Modify Makefiles to build shared library, as explained in # https://stackoverflow.com/questions/20848275/compiling-lua-create-so-files patch -p1 <<'EOF' diff -Naur lua-5.3.6.orig/Makefile lua-5.3.6/Makefile --- lua-5.3.6.orig/Makefile 2022-11-17 11:19:00.069298984 +0100 +++ lua-5.3.6/Makefile 2022-11-17 11:32:10.759562052 +0100 @@ -6,6 +6,10 @@ # Your platform. See PLATS for possible values. PLAT= none +# Lua version and release. +V= 5.3 +R= $V.6 + # Where to install. The installation starts in the src and doc directories, # so take care if INSTALL_TOP is not an absolute path. See the local target. # You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with @@ -41,18 +45,14 @@ # What to install. TO_BIN= lua luac TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp -TO_LIB= liblua.a +TO_LIB= liblua.a liblua.so.$(R) TO_MAN= lua.1 luac.1 -# Lua version and release. -V= 5.3 -R= $V.6 - # Targets start here. all: $(PLAT) $(PLATS) clean: - cd src && $(MAKE) $@ + cd src && $(MAKE) $@ V=$(V) R=$(R) test: dummy src/lua -v @@ -63,6 +63,8 @@ cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) + ln -s $(INSTALL_LIB)/liblua.so.$(R) $(INSTALL_LIB)/liblua.so.$(V) + ln -s $(INSTALL_LIB)/liblua.so.$(R) $(INSTALL_LIB)/liblua.so uninstall: cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN) diff -Naur lua-5.3.6.orig/src/Makefile lua-5.3.6/src/Makefile --- lua-5.3.6.orig/src/Makefile 2022-11-17 11:19:00.118298380 +0100 +++ lua-5.3.6/src/Makefile 2022-11-17 11:30:42.499648924 +0100 @@ -7,7 +7,7 @@ PLAT= none CC= gcc -std=gnu99 -CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 $(SYSCFLAGS) $(MYCFLAGS) +CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 $(SYSCFLAGS) $(MYCFLAGS) -fPIC LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS) LIBS= -lm $(SYSLIBS) $(MYLIBS) @@ -29,6 +29,7 @@ PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris LUA_A= liblua.a +LUA_SO= liblua.so CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ ltm.o lundump.o lvm.o lzio.o @@ -43,7 +44,7 @@ LUAC_O= luac.o ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O) -ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) +ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) $(LUA_SO) ALL_A= $(LUA_A) # Targets start here. @@ -59,6 +60,11 @@ $(AR) $@ $(BASE_O) $(RANLIB) $@ +$(LUA_SO): $(CORE_O) $(LIB_O) + $(CC) -shared -ldl -Wl,-soname,$(LUA_SO).$(V) -o $@.$(R) $? -lm $(MYLDFLAGS) + ln -sf $(LUA_SO).$(R) $(LUA_SO).$(V) + ln -sf $(LUA_SO).$(R) $(LUA_SO) + $(LUA_T): $(LUA_O) $(LUA_A) $(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) EOF echo "Configuring, building & installing LUA ${LUA_VERSION} to ${LUA_DIR}" make linux -j $(nproc) make install INSTALL_TOP=${LUA_DIR} # Clean up the files from the build popd rm -rf lua-${LUA_VERSION} lua-${LUA_VERSION}.tar.gzaoflagger-v3.4.0/scripts/docker/make_wheels.sh0000755000175000017500000000242114507760372020114 0ustar olesoles#!/usr/bin/bash # Script to make python wheels for several versions # The working directory matters, script should be run with ./make_wheels.sh # The setup.py file containing the build instructions is located two directories up. # Below are some instructions on how to create new binary wheels for AOFlagger using this script. # 1. Modify the file aoflagger/setup.py if you want to apply changes to the wheel file (update version, documentation, ..) # 2. Go to the scripts/docker folder and run ./make_wheels.sh # This will create wheels for python 3.6, 3.7, 3.8, 3.9 and 3.10 and copy them outside the docker container to the respective output folders, which will be automatically generated. # 3. Update the .whl files to pyPI, using 'twine upload package_name.whl' # You may need to install twine, which can be done with 'pip install twine' # You need an account on PyPI to upload wheels. set -euo pipefail for py_version in 310 39 38 37 36 do pushd ../.. sed -i "s/master_wheel.*/master_wheel${py_version}/" scripts/docker/py310_wheel.docker docker build -t aoflagger-py${py_version} -f scripts/docker/py310_wheel.docker . dockerid=$(docker create aoflagger-py${py_version}) docker cp $dockerid:/output/ output-${py_version} docker rm ${dockerid} popd done aoflagger-v3.4.0/scripts/docker/Centos80000644000175000017500000000262314507760372016543 0ustar olesolesFROM centos:8 # Because Centos8 is EOL, we need to use the repos Vault where old things are archived: RUN \ sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && \ sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* # Enable epel & power tools repositories RUN yum -y install epel-release dnf-plugins-core && \ yum config-manager --set-enabled powertools RUN yum -y install \ blas-devel \ boost-devel \ cfitsio-devel \ cmake libarchive \ fftw-devel \ gcc-c++ \ git \ gsl-devel \ gtkmm30-devel \ hdf5-devel \ lapack-devel \ libpng-devel \ lua-devel \ make \ python3 \ python3-devel # casacore dependencies RUN \ yum -y install \ bison \ bzip2 \ flex \ gcc-gfortran \ ncurses-devel \ python3-libs \ readline-devel \ wcslib-devel \ wget \ && \ mkdir /external RUN \ cd /external && \ git clone https://github.com/casacore/casacore.git --branch v3.3.0 --depth 1 && \ cd /external/casacore && \ mkdir build && \ cd build && \ cmake .. -DBUILD_PYTHON=OFF -DBUILD_TESTING=OFF && \ make -j`nproc --all` && \ make install -j`nproc --all` ADD . /src WORKDIR /src RUN mkdir /build && cd /build && cmake ../src RUN cd /build && make -j`nproc --all` && make install RUN cd /build/python && echo "import aoflagger" | python3 aoflagger-v3.4.0/scripts/docker/Ubuntu18-nogui0000644000175000017500000000154214507760372017771 0ustar olesolesFROM ubuntu:18.04 RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ apt-get install -y \ cmake \ build-essential \ pkg-config \ casacore-data casacore-dev \ libblas-dev liblapack-dev \ liblua5.3-dev \ python3 \ python3-distutils \ libpython3-dev \ libboost-date-time-dev libboost-system-dev \ libcfitsio-dev \ libfftw3-dev \ libgsl-dev \ libhdf5-serial-dev \ libpng-dev \ software-properties-common && \ echo -ne "\n \n"| add-apt-repository ppa:ubuntu-toolchain-r/test && \ apt-get update -qq && \ apt-get install -y gcc-11 g++-11 gfortran-11 ENV CC=/usr/bin/gcc-11 ENV CXX=/usr/bin/g++-11 ADD . /src WORKDIR /src RUN \ mkdir /build && \ cd /build && \ cmake ../src && \ make -j`nproc` && \ make install RUN cd /build/python && echo "import aoflagger" | python3 aoflagger-v3.4.0/scripts/docker/install_boost.sh0000644000175000017500000000047314507760372020506 0ustar olesoles# Script to install extra boost libraries from source set -euo pipefail # Boost is already in the container as leftover from casacore install pushd /build/boost_${BOOST_} ./bootstrap.sh --prefix=/opt/boost --with-libraries=math,date_time,system ./b2 -j${THREADS} cxxflags="-fPIC" link=static,shared install popd aoflagger-v3.4.0/scripts/docker/install_fftw.sh0000644000175000017500000000120514507760372020320 0ustar olesoles# Script to install FFTW from source (single precision only). set -euo pipefail pushd /tmp echo "Downloading & unpacking FFTW ${FFTW_VERSION}" curl https://fftw.org/pub/fftw/fftw-${FFTW_VERSION}.tar.gz --output fftw-${FFTW_VERSION}.tar.gz tar xf fftw-${FFTW_VERSION}.tar.gz pushd fftw-${FFTW_VERSION} echo "Configuring, building & installing FFTW ${FFTW_VERSION} to ${FFTW_DIR}" ./configure --prefix=${FFTW_DIR} --enable-threads --enable-shared --enable-float make -j $(nproc) make install popd # Clean up to limit the size of the Docker image echo "Cleaning up unnecessary files" rm -r fftw-${FFTW_VERSION} rm fftw-${FFTW_VERSION}.tar.gz aoflagger-v3.4.0/scripts/docker/Debian-hdf5-1.140000644000175000017500000000167014507760372017610 0ustar olesolesFROM debian:experimental RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ apt-get install -y \ cmake \ build-essential \ pkg-config \ casacore-data casacore-dev \ libblas-dev liblapack-dev \ liblua5.3-dev \ python3 \ libpython3-dev \ libboost-date-time-dev libboost-system-dev \ libgtkmm-3.0-dev \ libcfitsio-dev \ libfftw3-dev \ libgsl-dev \ libpng-dev RUN apt-get install -y git && \ mkdir /software && \ cd /software && \ git clone --single-branch https://github.com/HDFGroup/hdf5.git -b hdf5-1_14_2 && \ mkdir hdf5/build && \ cd hdf5/build && \ cmake ../ -DHDF5_BUILD_CPP_LIB=ON && \ make install -j25 ADD . /src WORKDIR /src RUN mkdir /build && cd /build && cmake ../src -DCMAKE_PREFIX_PATH=/usr/local/HDF_Group/HDF5/1.14.2/ RUN cd /build && make -j`nproc --all` && make install RUN cd /build/python && echo "import aoflagger" | python3 aoflagger-v3.4.0/scripts/docker/install_hdf5.sh0000644000175000017500000000147014507760372020204 0ustar olesoles# Script to install HDF5 from source set -euo pipefail echo "Installing zlib-devel with yum" yum -y install zlib-devel pushd /tmp echo "Downloading & unpacking HDF5 ${HDF5_VERSION}" # Remove trailing .*, to get e.g. '1.12' ↓ curl -fsSLO "https://www.hdfgroup.org/ftp/HDF5/releases/hdf5-${HDF5_VERSION%.*}/hdf5-${HDF5_VERSION}/src/hdf5-${HDF5_VERSION}.tar.gz" tar -xzvf hdf5-${HDF5_VERSION}.tar.gz pushd hdf5-${HDF5_VERSION} echo "Configuring, building & installing HDF5 ${HDF5_VERSION} to ${HDF5_DIR}" ./configure --prefix ${HDF5_DIR} --enable-build-mode=production --enable-cxx make -j $(nproc) make install popd # Clean up to limit the size of the Docker image echo "Cleaning up unnecessary files" rm -r hdf5-${HDF5_VERSION} rm hdf5-${HDF5_VERSION}.tar.gz yum -y erase zlib-develaoflagger-v3.4.0/scripts/docker/py310_wheel.docker0000644000175000017500000000322514507760372020525 0ustar olesolesFROM quay.io/casacore/casacore:master_wheel36 ENV HDF5_VERSION 1.12.2 ENV HDF5_DIR /opt/hdf5 ENV LUA_VERSION 5.3.6 ENV LUA_DIR /opt/lua ENV FFTW_VERSION 3.3.8 ENV FFTW_DIR /opt/fftw3 COPY scripts/docker/install_*.sh / # Install AOFlagger dependencies RUN bash /install_lua.sh RUN bash /install_hdf5.sh RUN bash /install_fftw.sh RUN bash /install_boost.sh ENV CFLAGS="-I /opt/hdf5/include -L/opt/hdf5/lib -I/usr/include/cfitsio" ENV LD_LIBRARY_PATH="/usr/local/lib" ENV CMAKE_ARGS="-DCMAKE_PREFIX_PATH='${HDF5_DIR};${LUA_DIR};${FFTW_DIR};/opt/boost' -DCMAKE_CXX_FLAGS='-Wl,--unresolved-symbols=ignore-all'" # Create fake libpython to stop the linker from complaining. The wheel should find the user's libpython at runtime. RUN touch /usr/lib64/libpython${PYMAJOR}.${PYMINOR}${PYUNICODE}.so # Wheels should not actually link to libpython, since they find the user's python at runtime. # So prevent aoflagger to even find libpython (which is not even included in the manylinux images) RUN yum install -y libpng-devel ADD . /aoflagger WORKDIR /aoflagger # Change the following lines from CMakeLists.txt: # find_package( # Python # COMPONENTS Interpreter Development # REQUIRED) # - Add a specific exact Python version. # - Use "Development.Module" instead of "Development" RUN sed -i -z "s=\(find_package(\n Python\)\(\n COMPONENTS Interpreter Development\)=\1 ${PYMAJOR}.${PYMINOR} EXACT\2.Module=" CMakeLists.txt # Build and copy wheel outside of Docker container RUN /opt/python/${TARGET}/bin/python ./setup.py build_ext -j${THREADS} RUN /opt/python/${TARGET}/bin/python ./setup.py bdist_wheel -d . RUN auditwheel repair --plat manylinux2014_x86_64 -w /output *.whl aoflagger-v3.4.0/scripts/run-cpplint.sh0000755000175000017500000000036114507760372016635 0ustar olesolescd .. cpplint --verbose=1 --filter=-legal/copyright,-build/header_guard,-build/c++11,-build/include_subdir,-build/include_order,-readability/casting,-runtime/int --recursive --exclude=build --exclude=external --extensions=cpp,h . cd scripts aoflagger-v3.4.0/scripts/run-format.sh0000755000175000017500000000251214507760372016454 0ustar olesoles#!/bin/bash # Copyright (C) 2021 ASTRON (Netherlands Institute for Radio Astronomy) # SPDX-License-Identifier: GPL-3.0-or-later #Script configuration for this repo. Adjust it when copying to a different repo. #The directory that contains the source files. SOURCE_DIR=$(dirname "$0")/.. #Directories that must be excluded from formatting. These paths are #relative to SOURCE_DIR. EXCLUDE_DIRS=(external build CMake) # Use a specific clang-format version, since formatting differs between versions. CLANG_FORMAT_BINARY=clang-format-14 #End script configuration. #The common formatting script has further documentation. source $(dirname "$0")/../external/aocommon/scripts/format.sh # Run the Lua formatter. if ! which stylua &>/dev/null; then echo Warning: stylua not found, not running Lua formatting. else echo Running StyLua... STYLUA_ARGS="--indent-type spaces --indent-width 2 ${SOURCE_DIR}/data/strategies" if [ -n "$DRYRUN" ]; then if ! stylua --check $STYLUA_ARGS; then # Print in bold-face red echo -e "\e[1m\e[31mAt least one LUA file is not properly formatted!\e[0m" echo -e "\e[1m\e[31mRun $0 for formatting all files!\e[0m" exit 1 else # print in bold-face green echo -e "\e[1m\e[32mGreat job, all LUA files are properly formatted!\e[0m" fi else stylua $STYLUA_ARGS fi fi aoflagger-v3.4.0/scripts/makerelease.sh0000755000175000017500000000142014507760372016635 0ustar olesoles#! /bin/bash if [[ "$1" == "" ]] ; then echo Usage: ${0} \ else VERSION="$1" echo Check if these values inside src/version.h are right: cat ../src/version.h curdir=`pwd` cd ${curdir%/scripts} # To use current work tree attributes: "--worktree-attributes" git archive --format=tar --prefix=aoflagger-${VERSION}/ master | bzip2 -9 > ${curdir}/aoflagger-${VERSION}.tar.bz2 && mkdir /tmp/buildaoflagger${VERSION} cd /tmp/buildaoflagger${VERSION} tar -xjvf ${curdir}/aoflagger-${VERSION}.tar.bz2 cd aoflagger-${VERSION} mkdir build cd build cmake ../ -DPORTABLE=True make -j 4 && make check -j 4 cd ${curdir} rm -rf /tmp/buildaoflagger${VERSION} echo Wrote ${curdir}/aoflagger-${VERSION}.tar.bz2 fi aoflagger-v3.4.0/scripts/test/0000755000175000017500000000000014516225226014774 5ustar olesolesaoflagger-v3.4.0/scripts/test/testconfig.py.in0000644000175000017500000000052514507760372020130 0ustar olesolesSRC_DIR = "@CMAKE_SOURCE_DIR@/test/integration" BIN_DIR = "@CMAKE_BINARY_DIR@" RESOURCE_DIR = "@CMAKE_BINARY_DIR@/test_data" aoflagger = "@CMAKE_BINARY_DIR@/aoflagger" aoqplot = "@CMAKE_BINARY_DIR@/aoqplot" aoquality = "@CMAKE_BINARY_DIR@/aoquality" rfigui = "@CMAKE_BINARY_DIR@/rfigui" taql = "@TAQL_EXECUTABLE@" enable_gui = "@ENABLE_GUI@"aoflagger-v3.4.0/scripts/test/utils.py.in0000644000175000017500000000067514507760372017131 0ustar olesolesimport os from subprocess import check_call, check_output from testconfig import taql def assert_taql(command, expected_rows=0): result = check_output([taql, "-noph", command]).decode().strip() assert result == f"select result of {expected_rows} rows" def untar_ms(source): if not os.path.isfile(source): raise IOError(f"Not able to find {source} containing the reference solutions.") check_call(["tar", "xf", source]) aoflagger-v3.4.0/version.h.in0000644000175000017500000000066714507760372014610 0ustar olesoles#ifndef AOFLAGGER_VERSION_H #define AOFLAGGER_VERSION_H #define AOFLAGGER_VERSION_STR "@AOFLAGGER_VERSION_STR@" #define AOFLAGGER_VERSION_MAJOR @AOFLAGGER_VERSION_MAJOR@ #define AOFLAGGER_VERSION_MINOR @AOFLAGGER_VERSION_MINOR@ #define AOFLAGGER_VERSION_SUBMINOR @AOFLAGGER_VERSION_SUBMINOR@ #define AOFLAGGER_VERSION_DATE_STR "@AOFLAGGER_VERSION_DATE_STR@" #define AOFLAGGER_INSTALL_PATH "@CMAKE_INSTALL_PREFIX@" #endif aoflagger-v3.4.0/structures/0000755000175000017500000000000014516225226014551 5ustar olesolesaoflagger-v3.4.0/structures/image2d.h0000644000175000017500000004034414507760372016245 0ustar olesoles/** @file * This is the header file for the Image2D class. * @author André Offringa */ #ifndef IMAGE2D_H #define IMAGE2D_H #include "types.h" #include #include #include #include #include #include typedef boost::intrusive_ptr Image2DPtr; typedef boost::intrusive_ptr Image2DCPtr; void swap(Image2D& left, Image2D& right); void swap(Image2D& left, Image2D&& right); void swap(Image2D&& left, Image2D& right); /** * This class represents a two dimensional single-valued (=gray scale) image. It * can be read from and written to a @c .fits file and written to a @c .png * file. A new Image2D can be constructed with e.g. the MakeFromFits(), * MakeUnsetImage() or MakeFromDiff() static methods. * * Internally, the data is stored such that the x-axis is moving the fastest, * so "y-major". */ class Image2D : public boost::intrusive_ref_counter { public: Image2D() noexcept; Image2D(size_t width, size_t height, std::initializer_list values); Image2D(const Image2D& source); Image2D(Image2D&& source) noexcept; Image2D& operator=(const Image2D& rhs); Image2D& operator=(Image2D&& rhs) noexcept; template static Image2DPtr MakePtr(Args&&... args) { // This function is to have a generic 'make_' function, that e.g. calls // the more efficient make_shared() when Image2DPtr is a shared_ptr, but // also works when Image2DPtr is a boost::intrusive_ptr. return Image2DPtr(new Image2D(std::forward(args)...)); } static Image2DPtr MakePtr(size_t width, size_t height, std::initializer_list values) { // The above function using forwarding reference does not automatically // capture std::initializer_list, hence an explicit overload. return Image2DPtr(new Image2D(width, height, values)); } /** * Destructor. */ ~Image2D() noexcept; static Image2D MakeUnsetImage(size_t width, size_t height) { return Image2D(width, height); } static Image2D MakeUnsetImage(size_t width, size_t height, size_t widthCapacity) { return Image2D(width, height, widthCapacity); } static Image2D MakeSetImage(size_t width, size_t height, num_t initialValue) { Image2D image(width, height); image.SetAll(initialValue); return image; } /** * Construct an image with initialized values. * @param widthCapacity Minimum capacity to which the image can be * horizontally resized without reallocation; see also * @ref ResizeWithoutReallocation(). */ static Image2D MakeSetImage(size_t width, size_t height, num_t initialValue, size_t widthCapacity) { Image2D image(width, height, widthCapacity); image.SetAll(initialValue); return image; } /** * Return a copy of this image in which non-finite values have been * replaced by zero. */ Image2D MakeFiniteCopy() const; /** * Creates an image containing unset values. * @param width Width of the new image. * @param height Height of the new image. * @return The new image. Should be deleted by the caller. */ static Image2D* CreateUnsetImage(size_t width, size_t height) { return new Image2D(width, height); } /** * Creates an image containing unset values. * @param width Width of the new image. * @param height Height of the new image. * @param widthCapacity Minimum capacity to which the image can be * horizontally resized without reallocation * @return The new image. Should be deleted by the caller. */ static Image2D* CreateUnsetImage(size_t width, size_t height, size_t widthCapacity) { return new Image2D(width, height, widthCapacity); } /** * As CreateUnsetImage(size_t,size_t), but returns a smart pointer instead. * @param width Width of the new image. * @param height Height of the new image. * @return A (unique) smart pointer to the new image. */ static Image2DPtr CreateUnsetImagePtr(size_t width, size_t height) { return Image2DPtr(CreateUnsetImage(width, height)); } /** * As CreateUnsetImage(size_t,size_t,size_t), but returns a smart pointer * instead. * @param width Width of the new image. * @param height Height of the new image. * @param widthCapacity Minimum capacity to which the image can be * horizontally resized without reallocation * @return A (unique) smart pointer to the new image. */ static Image2DPtr CreateUnsetImagePtr(size_t width, size_t height, size_t widthCapacity) { return Image2DPtr(CreateUnsetImage(width, height)); } static Image2D* CreateSetImage(size_t width, size_t height, num_t initialValue); static Image2D* CreateSetImage(size_t width, size_t height, num_t initialValue, size_t widthCapacity); static Image2DPtr CreateSetImagePtr(size_t width, size_t height, num_t initialValue) { return Image2DPtr(CreateSetImage(width, height, initialValue)); } static Image2DPtr CreateSetImagePtr(size_t width, size_t height, num_t initialValue, size_t widthCapacity) { return Image2DPtr( CreateSetImage(width, height, initialValue, widthCapacity)); } /** * Creates an image containing zeros. * @param width Width of the new image. * @param height Height of the new image. * @return The new created image. */ static Image2D MakeZeroImage(size_t width, size_t height) { return MakeSetImage(width, height, 0.0); } /** * As CreateZeroImage(), but returns a smart pointer instead. * @param width Width of the new image. * @param height Height of the new image. * @return The (unique) smart pointer to the new image. */ static Image2DPtr CreateZeroImagePtr(size_t width, size_t height) { // TODO make this more efficient & use make_shared return Image2DPtr(new Image2D(MakeZeroImage(width, height))); } bool Empty() const { return _width == 0 || _height == 0; } Image2D& operator+=(const Image2D& rhs); /** * Creates a new image by adding two images of the same size together. * @param imageA first image. * @param imageB second image. * @return The new created image. * @throws runtime_error if the images do not match in size. */ static Image2D MakeFromSum(const Image2D& imageA, const Image2D& imageB); /** * Creates a new image by subtracting two images of the same size. * @param imageA first image. * @param imageB second image. * @return The new created image. Should be deleted by the caller. * @throws runtime_error if the images do not match in size. */ static Image2D MakeFromDiff(const Image2D& imageA, const Image2D& imageB); /** * Retrieves the average value of the image. * @return The average value. */ num_t GetAverage() const; /** * Returns the maximum value in the image. * @return The maximimum value. */ num_t GetMaximum() const; /** * Returns the maximum value in the specified range. * @return The maximimum value. */ num_t GetMaximum(size_t xOffset, size_t yOffset, size_t width, size_t height) const; /** * Returns the minimum value in the image. * @return The minimum value. */ num_t GetMinimum() const; /** * Returns the minimum value in the specified range. * @return The minimum value. */ num_t GetMinimum(size_t xOffset, size_t yOffset, size_t width, size_t height) const; /** * Returns the maximum finite value in the image. * @return The maximimum value. */ num_t GetMaximumFinite() const; /** * Returns the minimum finite value in the image. * @return The minimum value. */ num_t GetMinimumFinite() const; /** * Retrieves the value at a specific position. * @param x x-coordinate * @param y y-coordinate * @return The value. */ num_t Value(size_t x, size_t y) const { return _dataPtr[y][x]; } /** * Get the width of the image. * @return Width of the image. */ size_t Width() const { return _width; } /** * Get the height of the image. * @return Height of the image. */ size_t Height() const { return _height; } /** * Change a value at a specific position. * @param x x-coordinate of value to change. * @param y y-coordinate of value to change. * @param newValue New value. */ void SetValue(size_t x, size_t y, num_t newValue) { _dataPtr[y][x] = newValue; } void SetAll(num_t value); void AddValue(size_t x, size_t y, num_t addValue) { _dataPtr[y][x] += addValue; } /** * Returns true if object contains no non-finite values. */ bool AllFinite() const; /** * Check whether this image is completely zero. * @return @c true if the value only contains zeros. */ bool ContainsOnlyZeros() const; /** * Compute the sum of all values */ num_t Sum() const { num_t sum = 0.0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) sum += Value(x, y); } return sum; } void SetToAbs() { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) SetValue(x, y, fabsn(Value(x, y))); } } /** * Retrieve a factor to multiply the values with to normalise them. * @return Normalisation factor. */ num_t GetMaxMinNormalizationFactor() const; num_t GetStdDev() const; num_t GetRMS() const { return GetRMS(0, 0, _width, _height); } num_t GetMode() const; num_t GetRMS(size_t xOffset, size_t yOffset, size_t width, size_t height) const; /** * Normalize the data so that the variance is 1. */ void NormalizeVariance(); /** * Save the image to a fits file. * @param filename Fits filename. * @throws IOException if something goes wrong during writing */ void SaveToFitsFile(const std::string& filename) const; /** * Count the number of values that are above a specified value. */ size_t GetCountAbove(num_t value) const; size_t GetCountBelowOrEqual(num_t value) const { return _width * _height - GetCountAbove(value); } /** * Returns a threshold for which @c count values are above the * the threshold. That is, GetCountAbove(GetTresholdForCountAbove(x)) = x. */ num_t GetTresholdForCountAbove(size_t count) const; /** * Copies all values to the specified array. The array should be of size * width*height. */ void CopyData(num_t* destination) const; /** * Multiply all values with a factor. */ void MultiplyValues(num_t factor); /** * Will set all values to lhs - this. */ void SubtractAsRHS(const Image2DCPtr& lhs); /** * Flips the image w.r.t. the diagonal, i.e., x becomes y and y becomes x. */ Image2D GetTransposed() const { Image2D image(_height, _width); for (unsigned y = 0; y < _height; ++y) { for (unsigned x = 0; x < _width; ++x) image._dataPtr[x][y] = _dataPtr[y][x]; } return image; } void Transpose() { *this = GetTransposed(); } /** * Resample the image horizontally by decreasing the width * with an integer factor. */ Image2D ShrinkHorizontally(size_t factor) const; /** * Resample the image vertically by decreasing the height * with an integer factor. */ Image2D ShrinkVertically(size_t factor) const; /** * Resample the image horizontally by increasing the width * with an integer factor. */ Image2D EnlargeHorizontally(size_t factor, size_t newWidth) const; /** * Resample the image vertically by increasing the width * with an integer factor. */ Image2D EnlargeVertically(size_t factor, size_t newHeight) const; Image2D Trim(size_t startX, size_t startY, size_t endX, size_t endY) const; void SetTrim(size_t startX, size_t startY, size_t endX, size_t endY); /** * Copies source onto this image at the given position */ void CopyFrom(const Image2D& source, size_t destX, size_t destY) { size_t x2 = source._width + destX, y2 = source._height + destY; if (x2 > _width) x2 = _width; if (y2 > _height) y2 = _height; for (size_t y = destY; y < y2; ++y) { for (size_t x = destX; x < x2; ++x) SetValue(x, y, source.Value(x - destX, y - destY)); } } /** * Returns a pointer to one row of data. This can be used to step * quickly over the data in x direction. Note that the next row * is not exactly at "one times width", because the number of * samples in a row is made divisable by four. This makes it * possible to execute SSE instruction easily. * * If you want to skip over a whole row, use the Stride() method * to determine the intrinsicly used width of one row. * * @see Stride() */ num_t* ValuePtr(unsigned x, unsigned y) { return &_dataPtr[y][x]; } /** * Returns a constant pointer to one row of data. This can be used to * step quickly over the data in x direction. Note that the next row * is not exactly at "one times width", because the number of * samples in a row is made divisable by four. This makes it * possible to execute SSE instruction easily. * * If you want to skip over a whole row, use the Stride() method * to determine the intrinsicly used width of one row. * * @see Stride() */ const num_t* ValuePtr(unsigned x, unsigned y) const { return &_dataPtr[y][x]; } num_t* Data() { return _dataConsecutive; } const num_t* Data() const { return _dataConsecutive; } /** * This value specifies the intrinsic width of one row. It is * normally the first number that is >= Width() and divisable by * 8. When using the ValuePtr(unsigned, unsigned) method, * this value can be used to step over one row. * * @see ValuePtr(unsigned, unsigned) */ size_t Stride() const { return _stride; } /** * This call will set the width of the image to a new value. It won't * reallocate the memory: this call is meant to be fast and avoid * memory fragmentation. A new width should therefore be smaller or * equal than the current available allocated space. The currently * allocated space in horizontal direction is equal to Stride(). * On constructing an image, a larger capacity can be requested so * that the image can be quickly resized later to a larger dimension. * If the image is enlarged, the new space will be uninitialized. * * @param newWidth The new width of the image. Should satisfy newWidth <= * Stride(). */ void ResizeWithoutReallocation(size_t newWidth); private: friend void swap(Image2D&, Image2D&); friend void swap(Image2D&, Image2D&&); friend void swap(Image2D&&, Image2D&); friend bool operator==(const Image2D& lhs, const Image2D& rhs); Image2D(size_t width, size_t height) : Image2D(width, height, width) {} Image2D(size_t width, size_t height, size_t widthCapacity); void allocate(); /** * Calculate the space taken up by one row of data. This is rounded * upwards to make SSE/AVX operations faster. See the image factory * functions (like @ref MakeSetImage() ) for an explanation of * @c width_capacity. */ static size_t CalculateStride(size_t width_capacity) { return width_capacity == 0 ? 0 : (((width_capacity - 1) / 8) + 1) * 8; } size_t _width, _height; size_t _stride; num_t **_dataPtr, *_dataConsecutive; }; inline void swap(Image2D& left, Image2D& right) { std::swap(left._width, right._width); std::swap(left._stride, right._stride); std::swap(left._height, right._height); std::swap(left._dataPtr, right._dataPtr); std::swap(left._dataConsecutive, right._dataConsecutive); } inline void swap(Image2D& left, Image2D&& right) { std::swap(left._width, right._width); std::swap(left._stride, right._stride); std::swap(left._height, right._height); std::swap(left._dataPtr, right._dataPtr); std::swap(left._dataConsecutive, right._dataConsecutive); } inline void swap(Image2D&& left, Image2D& right) { std::swap(left._width, right._width); std::swap(left._stride, right._stride); std::swap(left._height, right._height); std::swap(left._dataPtr, right._dataPtr); std::swap(left._dataConsecutive, right._dataConsecutive); } #endif aoflagger-v3.4.0/structures/antennainfo.h0000644000175000017500000002264214507760372017236 0ustar olesoles#ifndef ANTENNAINFO_H #define ANTENNAINFO_H #include #include #include #include #include #include "types.h" #include "../util/serializable.h" class EarthPosition { public: EarthPosition() : x(0.0), y(0.0), z(0.0) {} double x, y, z; std::string ToString() { std::stringstream s; s.setf(std::ios::fixed, std::ios::floatfield); s.width(16); s.precision(16); s << x << "," << y << "," << z << " (alt " << sqrtl(x * x + y * y + z * z) << "), or " << "N" << Latitude() * 180 / M_PI << " E" << Longitude() * 180 / M_PI; return s.str(); } double Longitude() const { return atan2l(y, x); } long double LongitudeL() const { return atan2l(y, x); } double Latitude() const { return atan2l(z, sqrtl((long double)x * x + y * y)); } long double LatitudeL() const { return atan2l(z, sqrtl((long double)x * x + y * y)); } double Altitude() const { return sqrtl((long double)x * x + y * y + z * z); } double AltitudeL() const { return sqrtl((long double)x * x + y * y + z * z); } void Serialize(std::ostream& stream) const { Serializable::SerializeToDouble(stream, x); Serializable::SerializeToDouble(stream, y); Serializable::SerializeToDouble(stream, z); } void Unserialize(std::istream& stream) { x = Serializable::UnserializeDouble(stream); y = Serializable::UnserializeDouble(stream); z = Serializable::UnserializeDouble(stream); } double Distance(const EarthPosition& other) const { return sqrt(DistanceSquared(other)); } double DistanceSquared(const EarthPosition& other) const { double dx = x - other.x, dy = y - other.y, dz = z - other.z; return dx * dx + dy * dy + dz * dz; } friend bool operator==(const EarthPosition& lhs, const EarthPosition& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z; } }; class UVW { public: UVW() : u(0.0), v(0.0), w(0.0) {} UVW(num_t _u, num_t _v, num_t _w) : u(_u), v(_v), w(_w) {} num_t u, v, w; }; class AntennaInfo { public: AntennaInfo() {} unsigned id; EarthPosition position; std::string name; double diameter; std::string mount; std::string station; void Serialize(std::ostream& stream) const { Serializable::SerializeToUInt32(stream, id); position.Serialize(stream); Serializable::SerializeToString(stream, name); Serializable::SerializeToDouble(stream, diameter); Serializable::SerializeToString(stream, mount); Serializable::SerializeToString(stream, station); } void Unserialize(std::istream& stream) { id = Serializable::UnserializeUInt32(stream); position.Unserialize(stream); Serializable::UnserializeString(stream, name); diameter = Serializable::UnserializeDouble(stream); Serializable::UnserializeString(stream, mount); Serializable::UnserializeString(stream, station); } friend bool operator==(const AntennaInfo& lhs, const AntennaInfo& rhs) { return lhs.id == rhs.id && lhs.position == rhs.position && lhs.name == rhs.name && lhs.diameter == rhs.diameter && lhs.mount == rhs.mount && lhs.station == rhs.station; } }; class ChannelInfo { public: unsigned frequencyIndex; double frequencyHz; double channelWidthHz; double effectiveBandWidthHz; double resolutionHz; double MetersToLambda(double meters) const { return meters * frequencyHz / 299792458.0L; } void Serialize(std::ostream& stream) const { Serializable::SerializeToUInt32(stream, frequencyIndex); Serializable::SerializeToDouble(stream, frequencyHz); Serializable::SerializeToDouble(stream, channelWidthHz); Serializable::SerializeToDouble(stream, effectiveBandWidthHz); Serializable::SerializeToDouble(stream, resolutionHz); } void Unserialize(std::istream& stream) { frequencyIndex = Serializable::UnserializeUInt32(stream); frequencyHz = Serializable::UnserializeDouble(stream); channelWidthHz = Serializable::UnserializeDouble(stream); effectiveBandWidthHz = Serializable::UnserializeDouble(stream); resolutionHz = Serializable::UnserializeDouble(stream); } }; class BandInfo { public: unsigned windowIndex; std::vector channels; BandInfo() : windowIndex(0) {} num_t CenterFrequencyHz() const { num_t total = 0.0; for (std::vector::const_iterator i = channels.begin(); i != channels.end(); ++i) total += i->frequencyHz; return total / channels.size(); } void Serialize(std::ostream& stream) const { Serializable::SerializeToUInt32(stream, windowIndex); Serializable::SerializeToUInt32(stream, channels.size()); for (std::vector::const_iterator i = channels.begin(); i != channels.end(); ++i) i->Serialize(stream); } void Unserialize(std::istream& stream) { windowIndex = Serializable::UnserializeUInt32(stream); size_t channelCount = Serializable::UnserializeUInt32(stream); channels.resize(channelCount); for (size_t i = 0; i < channelCount; ++i) channels[i].Unserialize(stream); } std::pair GetChannelRange(double startFrequencyHz, double endFrequencyHz) const { size_t first = channels.size(), last = 0; for (size_t ch = 0; ch != channels.size(); ++ch) { if (channels[ch].frequencyHz >= startFrequencyHz && channels[ch].frequencyHz < endFrequencyHz) { first = std::min(first, ch); last = std::max(last, ch); } } if (first == channels.size()) return std::make_pair(0u, 0u); else return std::make_pair(first, last + 1); } }; class FieldInfo { public: FieldInfo() {} FieldInfo(const FieldInfo& source) : fieldId(source.fieldId), delayDirectionRA(source.delayDirectionRA), delayDirectionDec(source.delayDirectionDec), name(source.name) {} FieldInfo& operator=(const FieldInfo& source) { fieldId = source.fieldId; delayDirectionRA = source.delayDirectionRA; delayDirectionDec = source.delayDirectionDec; name = source.name; return *this; } friend bool operator==(const FieldInfo& lhs, const FieldInfo& rhs) { return lhs.fieldId == rhs.fieldId && lhs.delayDirectionRA == rhs.delayDirectionRA && lhs.delayDirectionDec == rhs.delayDirectionDec && lhs.name == rhs.name; } unsigned fieldId; num_t delayDirectionRA; num_t delayDirectionDec; std::string name; }; class Baseline { public: EarthPosition antenna1, antenna2; Baseline() : antenna1(), antenna2() {} Baseline(const AntennaInfo& _antenna1, const AntennaInfo& _antenna2) : antenna1(_antenna1.position), antenna2(_antenna2.position) {} Baseline(const EarthPosition& _antenna1, const EarthPosition& _antenna2) : antenna1(_antenna1), antenna2(_antenna2) {} num_t Distance() const { num_t dx = antenna1.x - antenna2.x; num_t dy = antenna1.y - antenna2.y; num_t dz = antenna1.z - antenna2.z; return sqrtn(dx * dx + dy * dy + dz * dz); } num_t Angle() const { num_t dz = antenna1.z - antenna2.z; // baseline is either orthogonal to the earths axis, or // the length of the baseline is zero. if (dz == 0.0) return 0.0; num_t transf = 1.0 / (antenna1.z - antenna2.z); num_t dx = (antenna1.x - antenna2.x) * transf; num_t dy = (antenna1.y - antenna2.y) * transf; num_t length = sqrtn(dx * dx + dy * dy + 1.0); return acosn(1.0 / length); } num_t DeltaX() const { return antenna2.x - antenna1.x; } num_t DeltaY() const { return antenna2.y - antenna1.y; } num_t DeltaZ() const { return antenna2.z - antenna1.z; } }; class Frequency { public: static std::string ToString(num_t value) { std::stringstream s; if (fabs(value) >= 1000000000.0L) s << round(value / 10000000.0L) / 100.0L << " GHz"; else if (fabs(value) >= 1000000.0L) s << round(value / 10000.0L) / 100.0L << " MHz"; else if (fabs(value) >= 1000.0L) s << round(value / 10.0L) / 100.0L << " KHz"; else s << value << " Hz"; return s.str(); } }; class RightAscension { public: static std::string ToString(numl_t value) { value = fmod(value, 2.0 * M_PInl); if (value < 0.0) value += 2.0 * M_PInl; std::stringstream s; s << (int)floorn(value * 12.0 / M_PInl) << ':'; int d2 = (int)floornl(fmodnl(value * 12.0 * 60.0 / M_PInl, 60.0)); if (d2 < 10) s << '0'; s << d2 << ':'; numl_t d3 = fmodnl(value * 12.0 * 60.0 * 60.0 / M_PInl, 60.0); if (d3 < 10.0) s << '0'; s << d3; return s.str(); } }; class Declination { public: static std::string ToString(numl_t value) { value = fmod(value, 2.0 * M_PInl); if (value < 0.0) value += 2.0 * M_PInl; if (value > M_PInl * 0.5) value = M_PInl - value; std::stringstream s; if (value > 0.0) s << '+'; else s << '-'; value = fabsnl(value); s << (int)floornl(value * 180.0 / M_PIn) << '.'; int d2 = (int)fmodnl(value * 180.0 * 60.0 / M_PIn, 60.0); if (d2 < 10) s << '0'; s << d2 << '.'; numl_t d3 = fmodnl(value * 180.0 * 60.0 * 60.0 / M_PIn, 60.0); if (d3 < 10.0) s << '0'; s << d3; return s.str(); } }; class Angle { public: static std::string ToString(numl_t valueRad) { std::stringstream s; numl_t deg = valueRad * 180.0 / M_PI; if (std::abs(deg) > 3) s << deg << " deg"; else if (std::abs(deg) > 3.0 / 60.0) s << (deg / 60.0) << " arcmin"; else s << (deg / 3600.0) << " arcsec"; return s.str(); } }; #endif aoflagger-v3.4.0/structures/msmetadata.cpp0000644000175000017500000003237114507760372017411 0ustar olesoles#include #include #include #include "msmetadata.h" #include "date.h" #include "../util/logger.h" MSMetaData::~MSMetaData() {} size_t MSMetaData::BandCount(const std::string& location) { casacore::MeasurementSet ms(location); return ms.spectralWindow().nrow(); } void MSMetaData::initializeOtherData() { casacore::MeasurementSet ms(_path); initializeAntennas(ms); initializeBands(ms); initializeFields(ms); } void MSMetaData::initializeAntennas(casacore::MeasurementSet& ms) { const casacore::MSAntenna antennaTable = ms.antenna(); const size_t count = antennaTable.nrow(); const casacore::ArrayColumn positionCol(antennaTable, "POSITION"); const casacore::ScalarColumn nameCol(antennaTable, "NAME"); const casacore::ScalarColumn diameterCol(antennaTable, "DISH_DIAMETER"); const casacore::ScalarColumn mountCol(antennaTable, "MOUNT"); const casacore::ScalarColumn stationCol(antennaTable, "STATION"); _antennas.resize(count); for (size_t row = 0; row != count; ++row) { AntennaInfo info; info.diameter = diameterCol(row); info.id = row; info.name = nameCol(row); casacore::Array position = positionCol(row); casacore::Array::iterator i = position.begin(); info.position.x = *i; ++i; info.position.y = *i; ++i; info.position.z = *i; info.mount = mountCol(row); info.station = stationCol(row); _antennas[row] = info; } } void MSMetaData::initializeBands(casacore::MeasurementSet& ms) { const casacore::MSSpectralWindow spectralWindowTable = ms.spectralWindow(); const casacore::ScalarColumn numChanCol(spectralWindowTable, "NUM_CHAN"); const casacore::ArrayColumn frequencyCol(spectralWindowTable, "CHAN_FREQ"); _bands.resize(spectralWindowTable.nrow()); for (size_t bandIndex = 0; bandIndex != spectralWindowTable.nrow(); ++bandIndex) { BandInfo band; band.windowIndex = bandIndex; const size_t channelCount = numChanCol(bandIndex); const casacore::Array& frequencies = frequencyCol(bandIndex); casacore::Array::const_iterator frequencyIterator = frequencies.begin(); for (unsigned channel = 0; channel < channelCount; ++channel) { ChannelInfo channelInfo; channelInfo.frequencyIndex = channel; channelInfo.frequencyHz = frequencies(casacore::IPosition(1, channel)); channelInfo.channelWidthHz = 0.0; channelInfo.effectiveBandWidthHz = 0.0; channelInfo.resolutionHz = 0.0; band.channels.push_back(channelInfo); ++frequencyIterator; } _bands[bandIndex] = band; } } void MSMetaData::initializeFields(casacore::MeasurementSet& ms) { const casacore::MSField fieldTable = ms.field(); const casacore::ArrayColumn delayDirectionCol( fieldTable, fieldTable.columnName(casacore::MSFieldEnums::DELAY_DIR)); const casacore::ScalarColumn nameCol( fieldTable, fieldTable.columnName(casacore::MSFieldEnums::NAME)); _fields.resize(fieldTable.nrow()); for (size_t row = 0; row != fieldTable.nrow(); ++row) { const casacore::Array& delayDirection = delayDirectionCol(row); casacore::Array::const_iterator delayDirectionIterator = delayDirection.begin(); FieldInfo field; field.fieldId = row; field.delayDirectionRA = *delayDirectionIterator; ++delayDirectionIterator; field.delayDirectionDec = *delayDirectionIterator; field.name = nameCol(row); _fields[row] = field; } } std::string MSMetaData::GetTelescopeName(casacore::MeasurementSet& ms) { const casacore::MSObservation obsTable = ms.observation(); const casacore::ScalarColumn telescopeNameCol( obsTable, obsTable.columnName(casacore::MSObservationEnums::TELESCOPE_NAME)); if (obsTable.nrow() != 0) { std::string telescopeName = telescopeNameCol(0); for (size_t row = 1; row != obsTable.nrow(); ++row) { if (std::string(telescopeNameCol(row)) != telescopeName) throw std::runtime_error( "The OBSERVATION table contains multiple entries from different " "telescopes. I do not know how to handle such sets."); } return telescopeName; } throw std::runtime_error("Measurement set contains no observations"); } void MSMetaData::GetDataDescToBandVector(std::vector& dataDescToBand) { casacore::MeasurementSet ms(_path); const casacore::MSDataDescription dataDescTable = ms.dataDescription(); const casacore::ScalarColumn spwIdCol( dataDescTable, dataDescTable.columnName( casacore::MSDataDescriptionEnums::SPECTRAL_WINDOW_ID)); dataDescToBand.resize(dataDescTable.nrow()); for (size_t dataDescId = 0; dataDescId != dataDescTable.nrow(); ++dataDescId) { dataDescToBand[dataDescId] = spwIdCol(dataDescId); } } void MSMetaData::InitializeMainTableData() { if (!_isMainTableDataInitialized) { Logger::Debug << "Initializing ms metadata cache data...\n"; const casacore::MeasurementSet ms(_path); const casacore::ScalarColumn antenna1Col( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::ANTENNA1)); const casacore::ScalarColumn antenna2Col( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::ANTENNA2)); const casacore::ScalarColumn fieldIdCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::FIELD_ID)); const casacore::ScalarColumn dataDescIdCol( ms, casacore::MeasurementSet::columnName( casacore::MeasurementSet::DATA_DESC_ID)); const casacore::ScalarColumn timeCol( ms, casacore::MeasurementSet::columnName(casacore::MeasurementSet::TIME)); double time = -1.0; std::set> baselineSet; std::set sequenceSet; size_t prevFieldId = size_t(-1), sequenceId = size_t(-1); for (size_t row = 0; row != ms.nrow(); ++row) { size_t a1 = antenna1Col(row), a2 = antenna2Col(row), fieldId = fieldIdCol(row), spw = dataDescIdCol(row); const double cur_time = timeCol(row); const bool isNewTime = cur_time != time; if (fieldId != prevFieldId) { prevFieldId = fieldId; sequenceId++; _observationTimesPerSequence.emplace_back(); } if (isNewTime) { time = cur_time; _observationTimesPerSequence[sequenceId].insert(cur_time); _observationTimes.emplace_hint(_observationTimes.end(), cur_time); } baselineSet.insert(std::pair(a1, a2)); sequenceSet.insert(Sequence(a1, a2, spw, sequenceId, fieldId)); } _baselines.assign(baselineSet.begin(), baselineSet.end()); _sequences.assign(sequenceSet.begin(), sequenceSet.end()); if (_intervalEnd) { for (std::set& seq : _observationTimesPerSequence) { if (seq.size() > *_intervalEnd) seq.erase(std::next(seq.begin(), *_intervalEnd), seq.end()); } _observationTimes.erase( std::next(_observationTimes.begin(), *_intervalEnd), _observationTimes.end()); } if (_intervalStart) { for (std::set& seq : _observationTimesPerSequence) { if (seq.size() > *_intervalStart) seq.erase(seq.begin(), std::next(seq.begin(), *_intervalStart)); else seq.clear(); } _observationTimes.erase( _observationTimes.begin(), std::next(_observationTimes.begin(), *_intervalStart)); } _isMainTableDataInitialized = true; } } size_t MSMetaData::PolarizationCount(const std::string& filename) { casacore::MeasurementSet ms(filename); const casacore::Table polTable = ms.polarization(); const casacore::ArrayColumn corTypeColumn(polTable, "CORR_TYPE"); casacore::Array corType = corTypeColumn(0); const casacore::Array::iterator iterend(corType.end()); size_t polarizationCount = 0; for (casacore::Array::iterator iter = corType.begin(); iter != iterend; ++iter) { ++polarizationCount; } return polarizationCount; } bool MSMetaData::HasAOFlaggerHistory() { casacore::MeasurementSet ms(_path); const casacore::Table histtab(ms.history()); const casacore::ScalarColumn application(histtab, "APPLICATION"); for (unsigned i = 0; i < histtab.nrow(); ++i) { if (application(i) == "AOFlagger") return true; } return false; } void MSMetaData::GetAOFlaggerHistory(std::ostream& stream) { casacore::MeasurementSet ms(_path); const casacore::MSHistory histtab(ms.history()); const casacore::ScalarColumn time(histtab, "TIME"); const casacore::ScalarColumn application(histtab, "APPLICATION"); const casacore::ArrayColumn cli(histtab, "CLI_COMMAND"); const casacore::ArrayColumn parms(histtab, "APP_PARAMS"); for (unsigned i = 0; i < histtab.nrow(); ++i) { if (application(i) == "AOFlagger") { stream << "====================\n" "Command: " << *cli(i).begin() << "\n" "Date: " << Date::AipsMJDToDateString(time(i)) << "\n" "Time: " << Date::AipsMJDToTimeString(time(i)) << "\n" "Strategy: \n ---------- \n"; const casacore::Vector appParamsVec = parms(i); for (casacore::Vector::const_iterator j = appParamsVec.begin(); j != appParamsVec.end(); ++j) { stream << *j << '\n'; } stream << " ---------- \n"; } } } void MSMetaData::AddAOFlaggerHistory(const std::string& strategy, const std::string& commandline) { // This has been copied from MSWriter.cc of NDPPP and altered (thanks, Ger!) casacore::MeasurementSet ms(_path); casacore::Table histtab(ms.history()); histtab.reopenRW(); casacore::ScalarColumn time(histtab, "TIME"); casacore::ScalarColumn obsId(histtab, "OBSERVATION_ID"); casacore::ScalarColumn message(histtab, "MESSAGE"); casacore::ScalarColumn application(histtab, "APPLICATION"); casacore::ScalarColumn priority(histtab, "PRIORITY"); casacore::ScalarColumn origin(histtab, "ORIGIN"); casacore::ArrayColumn parms(histtab, "APP_PARAMS"); casacore::ArrayColumn cli(histtab, "CLI_COMMAND"); // Put all parset entries in a Vector. // Some WSRT MSs have a FixedShape APP_PARAMS and CLI_COMMAND column. // For them, put the xml file in a single vector element (with newlines). const bool fixedShaped = (parms.columnDesc().options() & casacore::ColumnDesc::FixedShape) != 0; casacore::Vector appParamsVec; casacore::Vector clivec; clivec.resize(1); clivec[0] = commandline; if (fixedShaped) { appParamsVec.resize(1); appParamsVec[0] = strategy; } else { // Tokenize the string on '\n' const std::string str = strategy; const size_t lineCount = std::count(str.begin(), str.end(), '\n'); appParamsVec.resize(lineCount + 1); casacore::Array::contiter viter = appParamsVec.cbegin(); size_t curStringPos = 0; for (size_t i = 0; i < lineCount; ++i) { const size_t endPos = str.find('\n', curStringPos); *viter = str.substr(curStringPos, endPos - curStringPos); ++viter; curStringPos = endPos + 1; } if (curStringPos < str.size()) { *viter = str.substr(curStringPos, str.size() - curStringPos); } } const uint rownr = histtab.nrow(); histtab.addRow(); time.put(rownr, casacore::Time().modifiedJulianDay() * 24.0 * 3600.0); obsId.put(rownr, 0); message.put(rownr, "parameters"); application.put(rownr, "AOFlagger"); priority.put(rownr, "NORMAL"); origin.put(rownr, "standalone"); parms.put(rownr, appParamsVec); cli.put(rownr, clivec); } std::string MSMetaData::GetStationName() const { casacore::MeasurementSet ms(_path); const casacore::Table antennaTable(ms.antenna()); if (antennaTable.nrow() == 0) throw std::runtime_error("GetStationName() : no rows in Antenna table"); const casacore::ScalarColumn stationColumn(antennaTable, "STATION"); return stationColumn(0); } bool MSMetaData::IsChannelZeroRubish() { try { const std::string station = GetStationName(); if (station != "LOFAR") return false; // This is of course a hack, but its the best estimate we can make :-/ // (easily) const BandInfo bandInfo = GetBandInfo(0); return (bandInfo.channels.size() == 256 || bandInfo.channels.size() == 64); } catch (std::exception& e) { return false; } } aoflagger-v3.4.0/structures/msiterator.h0000644000175000017500000000461614507760372017130 0ustar olesoles#ifndef MS_ITERATOR_H #define MS_ITERATOR_H #include "antennainfo.h" #include #include #include #include class [[deprecated]] MSIterator { public: MSIterator(const casacore::MeasurementSet& ms, bool hasCorrectedData = true); MSIterator& operator++() { _row++; return *this; } casacore::Complex Data(unsigned frequencyIndex, unsigned polarisation) { return ( _dataCol)(_row)(casacore::IPosition(2, frequencyIndex, polarisation)); } bool Flag(unsigned frequencyIndex, unsigned polarisation) { return ( _flagCol)(_row)(casacore::IPosition(2, frequencyIndex, polarisation)); } casacore::Array::const_iterator FlagIterator() { return (_flagCol)(_row).begin(); } casacore::Complex CorrectedData(unsigned frequencyIndex, unsigned polarisation) { return (*_correctedDataCol)( _row)(casacore::IPosition(2, frequencyIndex, polarisation)); } casacore::Array::const_iterator CorrectedDataIterator() { return (*_correctedDataCol)(_row).begin(); } int Field() { return (_fieldCol)(_row); } double Time() { return (_timeCol)(_row); } unsigned Antenna1() { return (_antenna1Col)(_row); } unsigned Antenna2() { return (_antenna2Col)(_row); } unsigned ScanNumber() { return (_scanNumberCol)(_row); } class UVW UVW() { class UVW uvw; casacore::Array arr = (_uvwCol)(_row); casacore::Array::const_iterator i = arr.begin(); uvw.u = *i; ++i; uvw.v = *i; ++i; uvw.w = *i; return uvw; } unsigned Window() { return (_windowCol)(_row); } private: MSIterator(const MSIterator&) = delete; MSIterator& operator=(const MSIterator&) = delete; unsigned long _row; casacore::MeasurementSet _ms; casacore::ScalarColumn _antenna1Col; casacore::ScalarColumn _antenna2Col; casacore::ArrayColumn _dataCol; casacore::ArrayColumn _flagCol; std::unique_ptr> _correctedDataCol; casacore::ScalarColumn _timeCol; casacore::ScalarColumn _fieldCol; casacore::ScalarColumn _scanNumberCol; casacore::ArrayColumn _uvwCol; casacore::ScalarColumn _windowCol; }; #endif aoflagger-v3.4.0/structures/versionstring.h0000644000175000017500000000353614507760372017653 0ustar olesoles#ifndef VERSION_STRING_H #define VERSION_STRING_H #include #include class VersionString { public: VersionString() : _major(0), _minor(0), _subminor(0), _hasMinor(0), _hasSubminor(0) {} explicit VersionString(const std::string& str) { if (str.empty()) throw std::runtime_error("Empty version string specified"); for (size_t i = 0; i != str.size(); ++i) if (str[i] != '.' && (str[i] < '0' || str[i] > '9')) throw std::runtime_error("Invalid version specified: '" + str + "'"); const size_t pos1 = str.find('.'); if (pos1 == std::string::npos) { _major = std::atoi(str.c_str()); _minor = 0; _subminor = 0; _hasMinor = false; _hasSubminor = false; } else { _major = std::atoi(str.substr(0, pos1).c_str()); _hasMinor = true; const size_t pos2 = str.find('.', pos1 + 1); if (pos2 == std::string::npos) { _minor = std::atoi(str.substr(pos1 + 1).c_str()); _subminor = 0; _hasSubminor = false; } else { _minor = std::atoi(str.substr(pos1 + 1, pos2 - pos1).c_str()); _subminor = std::atoi(str.substr(pos2 + 1).c_str()); _hasSubminor = true; } } } int Major() const { return _major; } int Minor() const { return _minor; } int Subminor() const { return _subminor; } bool HasMinor() const { return _hasMinor; } bool HasSubminor() const { return _hasSubminor; } std::string String() const { if (_hasMinor) { if (_hasSubminor) { return std::to_string(_major) + '.' + std::to_string(_minor) + '.' + std::to_string(_subminor); } else { return std::to_string(_major) + '.' + std::to_string(_minor); } } else { return std::to_string(_major); } } private: int _major, _minor, _subminor; bool _hasMinor, _hasSubminor; }; #endif aoflagger-v3.4.0/structures/types.h0000644000175000017500000000403114507760372016072 0ustar olesoles#ifndef MSIO_TYPES #define MSIO_TYPES class AntennaInfo; class BandInfo; class FieldInfo; class TimeFrequencyData; class TimeFrequencyImager; class FitsFile; #define NUM_T_IS_FLOAT #ifdef NUM_T_IS_FLOAT typedef float num_t; #define sqrtn(X) sqrtf(X) #define expn(X) expf(X) #define logn(X) logf(X) #define sinn(X) sinf(X) #define asinn(X) asinf(X) #define cosn(X) cosf(X) #define acosn(X) acosf(X) #define tann(X) tanf(X) #define atann(X) atanf(X) #define atan2n(X, Y) atan2(X, Y) #define fabsn(X) fabsf(X) #define floorn(X) floorf(X) #define ceiln(X) ceilf(X) #define roundn(X) roundf(X) #define pown(X, Y) powf(X, Y) #define fmodn(X, Y) fmodf(X, Y) #define M_PIn M_PI #else // NOT NUM_T_IS_FLOAT typedef double num_t; #define sqrtn(X) sqrt(X) #define expn(X) exp(X) #define logn(X) log(X) #define sinn(X) sin(X) #define asinn(X) asin(X) #define cosn(X) cos(X) #define acosn(X) acos(X) #define tann(X) tan(X) #define atann(X) atan(X) #define atan2n(X, Y) atan2(X, Y) #define fabsn(X) fabs(X) #define floorn(X) floor(X) #define ceiln(X) ceil(X) #define roundn(X) round(X) #define pown(X, Y) pow(X, Y) #define fmodn(X, Y) fmod(X, Y) #define M_PIn M_PI #endif // numl_t is the numeric type for high precision, intermediate calculations typedef long double numl_t; #define sqrtnl(X) sqrtl(X) #define expnl(X) expl(X) #define lognl(X) logl(X) #define sinnl(X) sinl(X) #define asinnl(X) asinl(X) #define cosnl(X) cosl(X) #define tannl(X) tanl(X) #define atannl(X) atanl(X) #define atan2nl(X, Y) atan2l(X, Y) #define fabsnl(X) fabsl(X) #define floornl(X) floorl(X) #define ceilnl(X) ceill(X) #define roundnl(X) roundl(X) #define pownl(X, Y) powl(X, Y) #define fmodnl(X, Y) fmodl(X, Y) // M_PIl is not defined on some OS-X systems #ifndef M_PIl #define M_PIl 3.1415926535897932384626433832795029L /* pi */ #endif #define M_PInl M_PIl enum DataKind { ObservedData, CorrectedData, ResidualData, ModelData, WeightData }; class ParmTable; enum BaselineIOMode { DirectReadMode, ReorderingReadMode, MemoryReadMode, AutoReadMode }; #endif // MSIO_TYPES aoflagger-v3.4.0/structures/image2d.cpp0000644000175000017500000003731714507760372016606 0ustar olesoles#include "image2d.h" #include "../msio/fitsfile.h" #include #include #include #include #include #include #include #include #ifdef __SSE__ #define USE_INTRINSICS #endif #ifdef USE_INTRINSICS #include #endif Image2D::Image2D() noexcept : _width(0), _height(0), _stride(0), _dataPtr(nullptr), _dataConsecutive(nullptr) {} Image2D::Image2D(size_t width, size_t height, size_t widthCapacity) : _width(width), _height(height), _stride(CalculateStride(widthCapacity)) { allocate(); } void Image2D::allocate() { // The height is made divisable by 4 (128 bits) to allow 128-bit vector // operations to be executed in the vertical direction. unsigned allocHeight = ((((_height - 1) / 4) + 1) * 4); if (_height == 0) allocHeight = 0; #ifdef __APPLE__ // OS-X has no posix_memalign, but malloc always uses 16-byte alignment. // This is not enough for AVX instructions, so those cannot be executed on // apple machines. _dataConsecutive = (num_t*)malloc(_stride * allocHeight * sizeof(num_t)); #else if (posix_memalign((void**)&_dataConsecutive, 32, _stride * allocHeight * sizeof(num_t)) != 0) throw std::bad_alloc(); #endif _dataPtr = new num_t*[allocHeight]; for (size_t y = 0; y < _height; ++y) { _dataPtr[y] = &_dataConsecutive[_stride * y]; // Even though the values after the requested width are never relevant, we // will initialize them to zero to prevent valgrind to report unset values // when they are used in SSE instructions. for (size_t x = _width; x < _stride; ++x) { _dataPtr[y][x] = 0.0; } } for (size_t y = _height; y < allocHeight; ++y) { _dataPtr[y] = &_dataConsecutive[_stride * y]; // (see remark above about initializing to zero) for (size_t x = 0; x < _stride; ++x) { _dataPtr[y][x] = 0.0; } } } Image2D::Image2D(size_t width, size_t height, std::initializer_list values) : _width(width), _height(height), _stride(CalculateStride(width)) { assert(width * height == values.size()); allocate(); std::initializer_list::iterator i = values.begin(); for (size_t y = 0; y != height; ++y) { std::copy_n(i, width, _dataPtr[y]); i += width; } } Image2D::Image2D(const Image2D& source) : boost::intrusive_ref_counter(*this), _width(source._width), _height(source._height), _stride(source._stride) { allocate(); std::copy(source._dataConsecutive, source._dataConsecutive + _stride * _height, _dataConsecutive); } Image2D::Image2D(Image2D&& source) noexcept : _width(source._width), _height(source._height), _stride(source._stride), _dataPtr(source._dataPtr), _dataConsecutive(source._dataConsecutive) { source._width = 0; source._stride = 0; source._height = 0; source._dataPtr = nullptr; source._dataConsecutive = nullptr; } Image2D::~Image2D() noexcept { delete[] _dataPtr; free(_dataConsecutive); } Image2D& Image2D::operator=(const Image2D& rhs) { if (_width != rhs._width || _height != rhs._height || _stride != rhs._stride) { delete[] _dataPtr; free(_dataConsecutive); _width = rhs._width; _height = rhs._height; _stride = rhs._stride; allocate(); } std::copy(rhs._dataConsecutive, rhs._dataConsecutive + _stride * _height, _dataConsecutive); return *this; } Image2D& Image2D::operator=(Image2D&& rhs) noexcept { std::swap(rhs._width, _width); std::swap(rhs._stride, _stride); std::swap(rhs._height, _height); std::swap(rhs._dataPtr, _dataPtr); std::swap(rhs._dataConsecutive, _dataConsecutive); return *this; } bool operator==(const Image2D& lhs, const Image2D& rhs) { if (lhs._width != rhs._width || lhs._height != rhs._height) return false; for (size_t y = 0; y != lhs._height; ++y) { if (!std::equal(lhs._dataPtr[y], lhs._dataPtr[y] + lhs._width, rhs._dataPtr[y])) return false; } return true; } Image2D Image2D::MakeFiniteCopy() const { Image2D copy = Image2D::MakeUnsetImage(_width, _height); for (size_t y = 0; y != _height; ++y) { std::transform(_dataPtr[y], _dataPtr[y] + _width, copy._dataPtr[y], [](num_t v) { return std::isfinite(v) ? v : 0.0; }); } return copy; } Image2D* Image2D::CreateSetImage(size_t width, size_t height, num_t initialValue) { Image2D* image = new Image2D(width, height); image->SetAll(initialValue); return image; } Image2D* Image2D::CreateSetImage(size_t width, size_t height, num_t initialValue, size_t widthCapacity) { Image2D* image = new Image2D(width, height, widthCapacity); image->SetAll(initialValue); return image; } Image2D Image2D::MakeFromSum(const Image2D& imageA, const Image2D& imageB) { if (imageA.Width() != imageB.Width() || imageA.Height() != imageB.Height()) throw std::runtime_error("Images do not match in size"); Image2D image(imageA.Width(), imageA.Height()); const size_t total = imageA._stride * imageA.Height(); for (size_t i = 0; i < total; ++i) { image._dataConsecutive[i] = imageA._dataConsecutive[i] + imageB._dataConsecutive[i]; } return image; } Image2D Image2D::MakeFromDiff(const Image2D& imageA, const Image2D& imageB) { if (imageA.Width() != imageB.Width() || imageA.Height() != imageB.Height()) throw std::runtime_error("Images do not match in size"); Image2D image(imageA.Width(), imageA.Height()); const float* lhsPtr = &(imageA._dataConsecutive[0]); const float* rhsPtr = &(imageB._dataConsecutive[0]); float* destPtr = &(image._dataConsecutive[0]); const float* end = lhsPtr + imageA._stride * imageA._height; while (lhsPtr < end) { #ifdef USE_INTRINSICS _mm_store_ps(destPtr, _mm_sub_ps(_mm_load_ps(lhsPtr), _mm_load_ps(rhsPtr))); lhsPtr += 4; rhsPtr += 4; destPtr += 4; #else (*destPtr) = (*lhsPtr) - (*rhsPtr); lhsPtr++; rhsPtr++; destPtr++; #endif } return image; } void Image2D::SetAll(num_t value) { float* ptr = &_dataConsecutive[0]; float* end = ptr + _stride * _height; std::fill(ptr, end, value); } num_t Image2D::GetAverage() const { size_t count = 0; num_t total = 0.0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { total += _dataPtr[y][x]; count++; } } return total / (num_t)count; } num_t Image2D::GetMaximum() const { num_t max = _dataPtr[0][0]; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (_dataPtr[y][x] > max) { max = _dataPtr[y][x]; } } } return max; } num_t Image2D::GetMinimum() const { num_t min = _dataPtr[0][0]; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (_dataPtr[y][x] < min) { min = _dataPtr[y][x]; } } } return min; } num_t Image2D::GetMaximumFinite() const { num_t max = boost::numeric::bounds::lowest(); for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (std::isfinite(_dataPtr[y][x]) && _dataPtr[y][x] > max) { max = _dataPtr[y][x]; } } } return max; } num_t Image2D::GetMinimumFinite() const { num_t min = std::numeric_limits::max(); for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (std::isfinite(_dataPtr[y][x]) && _dataPtr[y][x] < min) { min = _dataPtr[y][x]; } } } return min; } bool Image2D::AllFinite() const { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (!std::isfinite(_dataPtr[y][x])) return false; } } return true; } bool Image2D::ContainsOnlyZeros() const { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (_dataPtr[y][x] != 0.0) return false; } } return true; } num_t Image2D::GetMaxMinNormalizationFactor() const { num_t max = GetMaximum(), min = GetMinimum(); const num_t range = (-min) > max ? (-min) : max; return 1.0 / range; } num_t Image2D::GetStdDev() const { const num_t mean = GetAverage(); size_t count = 0; num_t total = 0.0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { total += (_dataPtr[y][x] - mean) * (_dataPtr[y][x] - mean); count++; } } return sqrt(total / (num_t)count); } num_t Image2D::GetMode() const { const size_t size = _width * _height; num_t mode = 0.0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { const num_t value = _dataPtr[y][x]; mode += value * value; } } return sqrtn(mode / (2.0L * (num_t)size)); } num_t Image2D::GetRMS(size_t xOffset, size_t yOffset, size_t width, size_t height) const { size_t count = 0; num_t total = 0.0; for (size_t y = yOffset; y < height + yOffset; ++y) { for (size_t x = xOffset; x < width + xOffset; ++x) { const num_t v = Value(x, y); total += v * v; count++; } } return sqrtn(total / (num_t)count); } void Image2D::NormalizeVariance() { const num_t variance = GetStdDev(); for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { _dataPtr[y][x] /= variance; } } } void Image2D::SaveToFitsFile(const std::string& filename) const { FitsFile file(filename); file.Create(); file.AppendImageHUD(FitsFile::Double64ImageType, _width, _height); const long bufferSize = (long)_width * (long)_height; double* buffer = new double[bufferSize]; size_t i = 0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { buffer[i] = _dataPtr[y][x]; ++i; } } try { file.WriteImage(0, buffer, bufferSize); file.Close(); } catch (FitsIOException& exception) { delete[] buffer; throw; } delete[] buffer; } size_t Image2D::GetCountAbove(num_t value) const { size_t count = 0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (_dataPtr[y][x] > value) count++; } } return count; } num_t Image2D::GetTresholdForCountAbove(size_t count) const { const size_t size = _width * _height; num_t* sorted = new num_t[size]; size_t i = 0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { sorted[i] = _dataPtr[y][x]; ++i; } } std::sort(sorted, sorted + size); const num_t v = sorted[size - count - 1]; delete[] sorted; return v; } void Image2D::CopyData(num_t* destination) const { size_t i = 0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { destination[i] = _dataPtr[y][x]; ++i; } } } void Image2D::MultiplyValues(num_t factor) { const size_t size = _stride * _height; for (size_t i = 0; i < size; ++i) { _dataConsecutive[i] *= factor; } } void Image2D::SubtractAsRHS(const Image2DCPtr& lhs) { float* thisPtr = &_dataConsecutive[0]; const float* otherPtr = &(lhs->_dataConsecutive[0]); float* end = thisPtr + _stride * _height; #ifdef USE_INTRINSICS /* #ifdef __AVX__ while(thisPtr < end) { // (*thisPtr) = (*otherPtr) - (*thisPtr); _mm_store256_ps(thisPtr, _mm_sub256_ps(_mm_load256_ps(otherPtr), _mm_load256_ps(thisPtr))); thisPtr += 8; otherPtr += 8; } #else // Use slower SSE instructions */ while (thisPtr < end) { // (*thisPtr) = (*otherPtr) - (*thisPtr); _mm_store_ps(thisPtr, _mm_sub_ps(_mm_load_ps(otherPtr), _mm_load_ps(thisPtr))); thisPtr += 4; otherPtr += 4; } #else while (thisPtr < end) { (*thisPtr) = (*otherPtr) - (*thisPtr); thisPtr++; otherPtr++; } #endif } Image2D Image2D::ShrinkHorizontally(size_t factor) const { const size_t newWidth = (_width + factor - 1) / factor; Image2D newImage(newWidth, _height); for (size_t x = 0; x < newWidth; ++x) { size_t binSize = factor; if (binSize + x * factor > _width) binSize = _width - x * factor; for (size_t y = 0; y < _height; ++y) { num_t sum = 0.0; for (size_t binX = 0; binX < binSize; ++binX) { const size_t curX = x * factor + binX; sum += Value(curX, y); } newImage.SetValue(x, y, sum / (num_t)binSize); } } return newImage; } Image2D Image2D::ShrinkVertically(size_t factor) const { const size_t newHeight = (_height + factor - 1) / factor; Image2D newImage(_width, newHeight); for (size_t y = 0; y < newHeight; ++y) { size_t binSize = factor; if (binSize + y * factor > _height) binSize = _height - y * factor; for (size_t x = 0; x < _width; ++x) { num_t sum = 0.0; for (size_t binY = 0; binY < binSize; ++binY) { const size_t curY = y * factor + binY; sum += Value(x, curY); } newImage.SetValue(x, y, sum / (num_t)binSize); } } return newImage; } Image2D Image2D::EnlargeHorizontally(size_t factor, size_t newWidth) const { Image2D newImage(newWidth, _height); for (size_t x = 0; x < newWidth; ++x) { const size_t xOld = x / factor; for (size_t y = 0; y < _height; ++y) { newImage.SetValue(x, y, Value(xOld, y)); } } return newImage; } Image2D Image2D::EnlargeVertically(size_t factor, size_t newHeight) const { Image2D newImage(_width, newHeight); for (size_t x = 0; x < _width; ++x) { for (size_t y = 0; y < newHeight; ++y) { const size_t yOld = y / factor; newImage.SetValue(x, y, Value(x, yOld)); } } return newImage; } Image2D Image2D::Trim(size_t startX, size_t startY, size_t endX, size_t endY) const { size_t width = endX - startX, height = endY - startY; Image2D image(width, height); for (size_t y = startY; y < endY; ++y) { num_t* newPtr = image._dataPtr[y - startY]; num_t* oldPtr = &_dataPtr[y][startX]; for (size_t x = startX; x < endX; ++x) { *newPtr = *oldPtr; ++newPtr; ++oldPtr; } } return image; } void Image2D::SetTrim(size_t startX, size_t startY, size_t endX, size_t endY) { *this = Trim(startX, startY, endX, endY); } /** * Returns the maximum value in the specified range. * @return The maximimum value. */ num_t Image2D::GetMaximum(size_t xOffset, size_t yOffset, size_t width, size_t height) const { size_t count = 0; num_t max = 0.0; for (size_t y = yOffset; y < height + yOffset; ++y) { for (size_t x = xOffset; x < width + xOffset; ++x) { if (Value(x, y) > max || count == 0) { max = Value(x, y); ++count; } } } if (count == 0) return std::numeric_limits::quiet_NaN(); return max; } /** * Returns the minimum value in the specified range. * @return The minimum value. */ num_t Image2D::GetMinimum(size_t xOffset, size_t yOffset, size_t width, size_t height) const { size_t count = 0; num_t min = 0.0; for (size_t y = yOffset; y < height + yOffset; ++y) { for (size_t x = xOffset; x < width + xOffset; ++x) { if (Value(x, y) < min || count == 0) { min = Value(x, y); ++count; } } } if (count == 0) return std::numeric_limits::quiet_NaN(); return min; } void Image2D::ResizeWithoutReallocation(size_t newWidth) { if (newWidth > _stride) throw std::runtime_error( "Bug: ResizeWithoutReallocation called with newWidth > Stride !"); _width = newWidth; } Image2D& Image2D::operator+=(const Image2D& rhs) { if (Width() != rhs.Width() || Height() != rhs.Height() || Stride() != rhs.Stride()) throw std::runtime_error("Images do not match in size"); const size_t total = rhs._stride * rhs.Height(); for (size_t i = 0; i < total; ++i) { _dataConsecutive[i] += rhs._dataConsecutive[i]; } return *this; } aoflagger-v3.4.0/structures/xyswappedmask2d.h0000644000175000017500000000367014507760372020064 0ustar olesoles#ifndef XYSWAPPEDMASK2D_H #define XYSWAPPEDMASK2D_H #include "mask2d.h" #include "image2d.h" /** * This class wraps a mask and swappes the x and y axes. It provides only the * trivial @ref Mask2D functions, and swappes x and y in there, such that the * original width becomes the new height, etc. It is useful to convert an * algorithm that works originally only in one direction to work in the other * direction without rewriting it. If a template parameter is used, the overhead * should be negligable. * * Note that this method uses references to the original mask. However, masks * are normally wrapped in a smart pointer. The caller should make sure the * mask exists as long as the XYSwappedMask2D exists. * * @author Andre Offringa */ template class XYSwappedMask2D { public: explicit XYSwappedMask2D(MaskLike& mask) : _mask(mask) {} XYSwappedMask2D& operator=( const XYSwappedMask2D& source) { _mask = source._mask; return *this; } bool Value(unsigned x, unsigned y) const { return _mask.Value(y, x); } void SetValue(unsigned x, unsigned y, bool newValue) { _mask.SetValue(y, x, newValue); } void SetHorizontalValues(unsigned x, unsigned y, bool value, unsigned count) { _mask.SetVerticalValues(y, x, value, count); } unsigned Width() const { return _mask.Height(); } unsigned Height() const { return _mask.Width(); } private: MaskLike& _mask; }; template class XYSwappedImage2D { public: explicit XYSwappedImage2D(ImageLike& image) : _image(image) {} inline num_t Value(unsigned x, unsigned y) const { return _image.Value(y, x); } inline void SetValue(unsigned x, unsigned y, num_t newValue) { _image.SetValue(y, x, newValue); } inline unsigned Width() const { return _image.Height(); } inline unsigned Height() const { return _image.Width(); } private: ImageLike& _image; }; #endif // XYSWAPPEDMASK2D_H aoflagger-v3.4.0/structures/timefrequencydata.cpp0000644000175000017500000003706514507760372021010 0ustar olesoles#include "timefrequencydata.h" #include "stokesimager.h" #include "../util/ffttools.h" namespace { /// Performs complex division and updates lhs void DivideComplexSinglePolarization(TimeFrequencyData& lhs, const TimeFrequencyData& rhs) { const size_t width = lhs.ImageWidth(); const size_t height = lhs.ImageHeight(); const Image2DCPtr& l_real = lhs.GetImage(0); const Image2DCPtr& l_imag = lhs.GetImage(1); const Image2DCPtr& r_real = rhs.GetImage(0); const Image2DCPtr& r_imag = rhs.GetImage(1); Image2DPtr real_result = Image2D::CreateUnsetImagePtr(width, height); Image2DPtr imag_result = Image2D::CreateUnsetImagePtr(width, height); for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { const std::complex lhs_value(l_real->Value(x, y), l_imag->Value(x, y)); const std::complex rhs_value(r_real->Value(x, y), r_imag->Value(x, y)); const std::complex result_value = lhs_value / rhs_value; real_result->SetValue(x, y, result_value.real()); imag_result->SetValue(x, y, result_value.imag()); } } lhs.SetImage(0, std::move(real_result)); lhs.SetImage(1, std::move(imag_result)); } /// Performs real division and updates lhs void DivideRealSinglePolarization(TimeFrequencyData& lhs, const TimeFrequencyData& rhs) { const size_t width = lhs.ImageWidth(); const size_t height = lhs.ImageHeight(); Image2DCPtr l_data = lhs.GetImage(0); Image2DCPtr r_data = rhs.GetImage(0); Image2DPtr result_image = Image2D::CreateUnsetImagePtr(width, height); for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { result_image->SetValue(x, y, l_data->Value(x, y) / r_data->Value(x, y)); } } lhs.SetImage(0, std::move(result_image)); } } // namespace Image2DCPtr TimeFrequencyData::GetAbsoluteFromComplex( const Image2DCPtr& real, const Image2DCPtr& imag) const { return Image2DPtr(FFTTools::CreateAbsoluteImage(*real, *imag)); } Image2DCPtr TimeFrequencyData::GetSum(const Image2DCPtr& left, const Image2DCPtr& right) const { return StokesImager::CreateSum(left, right); } Image2DCPtr TimeFrequencyData::GetNegatedSum(const Image2DCPtr& left, const Image2DCPtr& right) const { return StokesImager::CreateNegatedSum(left, right); } Image2DCPtr TimeFrequencyData::GetDifference(const Image2DCPtr& left, const Image2DCPtr& right) const { return StokesImager::CreateDifference(left, right); } Image2DCPtr TimeFrequencyData::getSinglePhaseFromTwoPolPhase( size_t polA, size_t polB) const { return StokesImager::CreateAvgPhase(_data[polA]._images[0], _data[polB]._images[0]); } Mask2DCPtr TimeFrequencyData::GetCombinedMask() const { if (MaskCount() == 0) { return GetSetMask(); } else if (MaskCount() == 1) { return GetMask(0); } else { Mask2DPtr mask(new Mask2D(*GetMask(0))); size_t i = 0; while (i != MaskCount()) { const Mask2DCPtr& curMask = GetMask(i); for (unsigned y = 0; y < mask->Height(); ++y) { for (unsigned x = 0; x < mask->Width(); ++x) { const bool v = curMask->Value(x, y); if (v) mask->SetValue(x, y, true); } } ++i; } return mask; } } TimeFrequencyData TimeFrequencyData::MakeZeroLinearData(size_t width, size_t height) { const Image2DPtr zero = Image2D::CreateSetImagePtr(width, height, 0.0); TimeFrequencyData data; data._data.resize(4); data._data[0] = PolarizedTimeFrequencyData(aocommon::Polarization::XX, zero, zero); data._data[1] = PolarizedTimeFrequencyData(aocommon::Polarization::XY, zero, zero); data._data[2] = PolarizedTimeFrequencyData(aocommon::Polarization::YX, zero, zero); data._data[3] = PolarizedTimeFrequencyData(aocommon::Polarization::YY, zero, zero); return data; } TimeFrequencyData TimeFrequencyData::Make( enum ComplexRepresentation representation) const { if (representation == _complexRepresentation) { return TimeFrequencyData(*this); } else if (_complexRepresentation == ComplexParts) { TimeFrequencyData data; data._complexRepresentation = representation; data._data.resize(_data.size()); for (size_t i = 0; i != _data.size(); ++i) { const PolarizedTimeFrequencyData& source = _data[i]; PolarizedTimeFrequencyData& dest = data._data[i]; dest._polarization = source._polarization; dest._flagging = source._flagging; switch (representation) { case RealPart: dest._images[0] = source._images[0]; break; case ImaginaryPart: dest._images[0] = source._images[1]; break; case AmplitudePart: dest._images[0] = GetAbsoluteFromComplex(source._images[0], source._images[1]); break; case PhasePart: dest._images[0] = StokesImager::CreateAvgPhase(source._images[0], source._images[1]); break; case ComplexParts: break; // already handled above. } } return data; } else if (representation == ComplexParts && _complexRepresentation == AmplitudePart) { return MakeFromComplexCombination(*this, *this); } else { throw std::runtime_error( "Request for time/frequency data with a phase representation that can " "not be extracted from the source (source is not complex)"); } } TimeFrequencyData TimeFrequencyData::MakeFromComplexCombination( const TimeFrequencyData& real, const TimeFrequencyData& imaginary) { if (real.ComplexRepresentation() == ComplexParts || imaginary.ComplexRepresentation() == ComplexParts) throw std::runtime_error( "Trying to create complex TF data from incorrect phase " "representations"); if (real.Polarizations() != imaginary.Polarizations()) throw std::runtime_error( "Combining real/imaginary time frequency data from different " "polarisations"); TimeFrequencyData data; data._data.resize(real._data.size()); data._complexRepresentation = ComplexParts; for (size_t i = 0; i != real._data.size(); ++i) { data._data[i]._polarization = real._data[i]._polarization; data._data[i]._images[0] = real._data[i]._images[0]; data._data[i]._images[1] = imaginary._data[i]._images[0]; data._data[i]._flagging = real._data[i]._flagging; } return data; } TimeFrequencyData TimeFrequencyData::MakeFromPolarizationCombination( const TimeFrequencyData& xx, const TimeFrequencyData& xy, const TimeFrequencyData& yx, const TimeFrequencyData& yy) { if (xx.ComplexRepresentation() != xy.ComplexRepresentation() || xx.ComplexRepresentation() != yx.ComplexRepresentation() || xx.ComplexRepresentation() != yy.ComplexRepresentation()) throw std::runtime_error( "Trying to create dipole time frequency combination from data with " "different phase representations!"); TimeFrequencyData data; data._data.resize(4); data._complexRepresentation = xx._complexRepresentation; for (size_t i = 0; i != xx._data.size(); ++i) { data._data[0] = xx._data[0]; data._data[1] = xy._data[0]; data._data[2] = yx._data[0]; data._data[3] = yy._data[0]; } return data; } TimeFrequencyData TimeFrequencyData::MakeFromPolarizationCombination( const TimeFrequencyData& first, const TimeFrequencyData& second) { if (first.IsEmpty()) return second; if (second.IsEmpty()) return first; if (first.ComplexRepresentation() != second.ComplexRepresentation()) throw std::runtime_error( "Trying to create polarization combination from data with different " "phase representations!"); TimeFrequencyData data; data._data = first._data; data._complexRepresentation = first._complexRepresentation; data._data.insert(data._data.end(), second._data.begin(), second._data.end()); return data; } void TimeFrequencyData::SetImagesToZero() { if (!IsEmpty()) { const Image2DPtr zeroImage = Image2D::CreateZeroImagePtr(ImageWidth(), ImageHeight()); const Mask2DPtr mask = Mask2D::CreateSetMaskPtr(ImageWidth(), ImageHeight()); for (PolarizedTimeFrequencyData& data : _data) { data._images[0] = zeroImage; if (data._images[1]) data._images[1] = zeroImage; data._flagging = mask; } } } void TimeFrequencyData::MultiplyImages(long double factor) { for (PolarizedTimeFrequencyData& data : _data) { if (data._images[0]) { const Image2DPtr newImage(new Image2D(*data._images[0])); newImage->MultiplyValues(factor); data._images[0] = newImage; } if (data._images[1]) { const Image2DPtr newImage(new Image2D(*data._images[1])); newImage->MultiplyValues(factor); data._images[1] = newImage; } } } void TimeFrequencyData::JoinMask(const TimeFrequencyData& other) { if (other.MaskCount() == 0) { // Nothing to be done; other has no flags } else if (other.MaskCount() == MaskCount()) { for (size_t i = 0; i < MaskCount(); ++i) { Mask2D mask(*GetMask(i)); mask.Join(*other.GetMask(i)); SetMask(i, Mask2DPtr(new Mask2D(mask))); } } else if (other.MaskCount() == 1) { if (MaskCount() == 0) { for (size_t i = 0; i != _data.size(); ++i) _data[i]._flagging = other._data[0]._flagging; } else { for (size_t i = 0; i < MaskCount(); ++i) { Mask2D mask(*GetMask(i)); mask.Join(*other.GetMask(0)); SetMask(i, Mask2DPtr(new Mask2D(mask))); } } } else if (MaskCount() == 1) { Mask2D mask(*GetMask(0)); mask.Join(*other.GetSingleMask()); SetMask(0, Mask2DPtr(new Mask2D(mask))); } else if (MaskCount() == 0 && _data.size() == other._data.size()) { for (size_t i = 0; i != _data.size(); ++i) _data[i]._flagging = other._data[i]._flagging; } else { throw std::runtime_error( "Joining time frequency flagging with incompatible structures"); } } std::vector> ToComplexVector( const TimeFrequencyData& tf_data) { if (tf_data.ComplexRepresentation() != TimeFrequencyData::ComplexParts) throw std::runtime_error( "Can't convert non-complex data into a complex vector"); const size_t n_pol = tf_data.PolarizationCount(); const size_t width = tf_data.ImageWidth(); const size_t height = tf_data.ImageHeight(); std::vector> data(n_pol * width * height); for (size_t pol = 0; pol != n_pol; ++pol) { const TimeFrequencyData pol_data = tf_data.MakeFromPolarizationIndex(pol); const Image2DCPtr real = pol_data.GetImage(0); const Image2DCPtr imaginary = pol_data.GetImage(1); size_t index = pol * width * height; for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { data[index] = {real->Value(x, y), imaginary->Value(x, y)}; ++index; } } } return data; } TimeFrequencyData ElementWiseDivide(const TimeFrequencyData& lhs, const TimeFrequencyData& rhs) { if (lhs.ImageCount() != rhs.ImageCount() || lhs.ComplexRepresentation() != rhs.ComplexRepresentation()) { throw std::runtime_error( "Can not element-wise divide time-frequency data: inputs do not have " "the same number of polarizations or complex representation!"); } if (lhs.ImageWidth() != rhs.ImageWidth() || lhs.ImageHeight() != rhs.ImageHeight()) throw std::runtime_error( "Can not element-wise divide time-frequency data: inputs have " "different sizes."); TimeFrequencyData data(lhs); for (size_t pol_index = 0; pol_index != data.PolarizationCount(); ++pol_index) { TimeFrequencyData lhs_pol = lhs.MakeFromPolarizationIndex(pol_index); const TimeFrequencyData rhs_pol = rhs.MakeFromPolarizationIndex(pol_index); if (lhs_pol.ImageCount() == 2) { DivideComplexSinglePolarization(lhs_pol, rhs_pol); } else { DivideRealSinglePolarization(lhs_pol, rhs_pol); } data.SetPolarizationData(pol_index, std::move(lhs_pol)); } return data; } TimeFrequencyData ElementWiseNorm(const TimeFrequencyData& data) { if (data.ComplexRepresentation() == TimeFrequencyData::ComplexParts) { std::vector norm_images; norm_images.reserve(data.PolarizationCount()); for (size_t pol_index = 0; pol_index != data.PolarizationCount(); ++pol_index) { TimeFrequencyData pol = data.MakeFromPolarizationIndex(pol_index); Image2DCPtr real = pol.GetImage(0); Image2DCPtr imaginary = pol.GetImage(1); const size_t width = pol.ImageWidth(); const size_t height = pol.ImageHeight(); Image2DPtr norm_image = Image2D::CreateUnsetImagePtr(width, height); for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { const std::complex z(real->Value(x, y), imaginary->Value(x, y)); norm_image->SetValue(x, y, std::norm(z)); } } norm_images.emplace_back(std::move(norm_image)); } return TimeFrequencyData(TimeFrequencyData::AmplitudePart, data.Polarizations().data(), data.PolarizationCount(), norm_images.data()); } else { TimeFrequencyData result = data; for (size_t pol_index = 0; pol_index != data.PolarizationCount(); ++pol_index) { TimeFrequencyData pol = data.MakeFromPolarizationIndex(pol_index); Image2DCPtr values = pol.GetImage(0); const size_t width = values->Width(); const size_t height = values->Height(); Image2DPtr new_values = Image2D::CreateUnsetImagePtr(width, height); for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { new_values->SetValue(x, y, std::norm(values->Value(x, y))); } } pol.SetImage(0, new_values); result.SetPolarizationData(pol_index, pol); } return result; } } TimeFrequencyData ElementWiseSqrt(const TimeFrequencyData& data) { TimeFrequencyData result = data; for (size_t pol_index = 0; pol_index != data.PolarizationCount(); ++pol_index) { TimeFrequencyData pol = data.MakeFromPolarizationIndex(pol_index); const size_t width = pol.ImageWidth(); const size_t height = pol.ImageHeight(); if (pol.ImageCount() == 2) { Image2DCPtr real = pol.GetImage(0); Image2DCPtr imaginary = pol.GetImage(1); Image2DPtr new_real = Image2D::CreateUnsetImagePtr(width, height); Image2DPtr new_imaginary = Image2D::CreateUnsetImagePtr(width, height); for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { const std::complex z(real->Value(x, y), imaginary->Value(x, y)); const std::complex sqrt = std::sqrt(z); new_real->SetValue(x, y, sqrt.real()); new_imaginary->SetValue(x, y, sqrt.imag()); } } pol.SetImage(0, new_real); pol.SetImage(1, new_imaginary); } else { Image2DCPtr values = pol.GetImage(0); Image2DPtr new_values = Image2D::CreateUnsetImagePtr(width, height); for (size_t y = 0; y != height; ++y) { for (size_t x = 0; x != width; ++x) { new_values->SetValue(x, y, std::sqrt(values->Value(x, y))); } } pol.SetImage(0, new_values); } result.SetPolarizationData(pol_index, pol); } return result; } aoflagger-v3.4.0/structures/samplerow.cpp0000644000175000017500000000056714507760372017304 0ustar olesoles#include "samplerow.h" SampleRow SampleRow::MakeWithoutMissings() const { size_t newSize = 0; for (const num_t v : _values) { if (std::isfinite(v)) ++newSize; } SampleRow newRow(newSize); size_t indexToNew = 0; for (const num_t v : _values) { if (std::isfinite(v)) { newRow._values[indexToNew] = v; ++indexToNew; } } return newRow; } aoflagger-v3.4.0/structures/timefrequencydata.h0000644000175000017500000011041014507760372020437 0ustar olesoles#ifndef TIMEFREQUENCYDATA_H #define TIMEFREQUENCYDATA_H #include #include #include #include #include #include #include "image2d.h" #include "mask2d.h" #include class TimeFrequencyData { public: enum ComplexRepresentation { PhasePart, AmplitudePart, RealPart, ImaginaryPart, ComplexParts }; TimeFrequencyData() : _complexRepresentation(AmplitudePart), _data() {} TimeFrequencyData(ComplexRepresentation complexRepresentation, aocommon::PolarizationEnum polarizationType, const Image2DCPtr& image) : _complexRepresentation(complexRepresentation) { if (complexRepresentation == ComplexParts) throw std::runtime_error( "Incorrect construction of time/frequency data: trying to create " "complex representation from single image"); _data.emplace_back(polarizationType, image); } TimeFrequencyData(aocommon::PolarizationEnum polarizationType, const Image2DCPtr& real, const Image2DCPtr& imaginary) : _complexRepresentation(ComplexParts) { _data.emplace_back(polarizationType, real, imaginary); } TimeFrequencyData(ComplexRepresentation complexRepresentation, aocommon::PolarizationEnum polarizationA, const Image2DCPtr& imageA, aocommon::PolarizationEnum polarizationB, const Image2DCPtr& imageB) : _complexRepresentation(complexRepresentation) { _data.reserve(2); _data.emplace_back(polarizationA, imageA); _data.emplace_back(polarizationB, imageB); } TimeFrequencyData(aocommon::PolarizationEnum polarizationA, const Image2DCPtr& realA, const Image2DCPtr& imaginaryA, aocommon::PolarizationEnum polarizationB, const Image2DCPtr& realB, const Image2DCPtr& imaginaryB) : _complexRepresentation(ComplexParts) { _data.reserve(2); _data.emplace_back(polarizationA, realA, imaginaryA); _data.emplace_back(polarizationB, realB, imaginaryB); } TimeFrequencyData(ComplexRepresentation complexRepresentation, const aocommon::PolarizationEnum* polarizations, size_t polarizationCount, const Image2DCPtr* images) : _complexRepresentation(complexRepresentation) { _data.reserve(polarizationCount); if (complexRepresentation == ComplexParts) { for (size_t p = 0; p != polarizationCount; p++) _data.emplace_back(polarizations[p], images[p * 2], images[p * 2 + 1]); } else { for (size_t p = 0; p != polarizationCount; p++) _data.emplace_back(polarizations[p], images[p]); } } TimeFrequencyData(const aocommon::PolarizationEnum* polarizations, size_t polarizationCount, const Image2DCPtr* realImages, const Image2DCPtr* imaginaryImages) : _complexRepresentation(ComplexParts) { _data.reserve(polarizationCount); for (size_t p = 0; p != polarizationCount; p++) _data.emplace_back(polarizations[p], realImages[p], imaginaryImages[p]); } TimeFrequencyData(const aocommon::PolarizationEnum* polarizations, size_t polarizationCount, const Image2DPtr* realImages, const Image2DPtr* imaginaryImages) : _complexRepresentation(ComplexParts) { _data.reserve(polarizationCount); for (size_t p = 0; p != polarizationCount; p++) _data.emplace_back(polarizations[p], realImages[p], imaginaryImages[p]); } static TimeFrequencyData FromLinear( ComplexRepresentation complexRepresentation, const Image2DCPtr& xx, const Image2DCPtr& xy, const Image2DCPtr& yx, const Image2DCPtr& yy) { TimeFrequencyData data; data._complexRepresentation = complexRepresentation; if (complexRepresentation == ComplexParts) throw std::runtime_error( "Incorrect construction of time/frequency data: trying to create " "complex full-Stokes representation from four images"); data._data.reserve(4); data._data.emplace_back(aocommon::Polarization::XX, xx); data._data.emplace_back(aocommon::Polarization::XY, xy); data._data.emplace_back(aocommon::Polarization::YX, yx); data._data.emplace_back(aocommon::Polarization::YY, yy); return data; } static TimeFrequencyData FromLinear( const Image2DCPtr& xxReal, const Image2DCPtr& xxImag, const Image2DCPtr& xyReal, const Image2DCPtr& xyImag, const Image2DCPtr& yxReal, const Image2DCPtr& yxImag, const Image2DCPtr& yyReal, const Image2DCPtr& yyImag) { TimeFrequencyData data; data._complexRepresentation = ComplexParts; data._data.reserve(4); data._data.emplace_back(aocommon::Polarization::XX, xxReal, xxImag); data._data.emplace_back(aocommon::Polarization::XY, xyReal, xyImag); data._data.emplace_back(aocommon::Polarization::YX, yxReal, yxImag); data._data.emplace_back(aocommon::Polarization::YY, yyReal, yyImag); return data; } static TimeFrequencyData FromLinear(size_t polarizationCount, Image2DCPtr* realImages, Image2DCPtr* imagImages) { switch (polarizationCount) { case 1: return TimeFrequencyData(aocommon::Polarization::StokesI, realImages[0], imagImages[0]); case 2: return TimeFrequencyData(aocommon::Polarization::XX, realImages[0], imagImages[0], aocommon::Polarization::YY, realImages[1], imagImages[1]); case 4: return FromLinear(realImages[0], imagImages[0], realImages[1], imagImages[1], realImages[2], imagImages[2], realImages[3], imagImages[3]); default: throw std::runtime_error( "Can not create TimeFrequencyData structure with polarization type " "other than 1, 2 or 4 polarizations using FromLinear()."); } } bool IsEmpty() const { return _data.empty(); } bool HasPolarization(aocommon::PolarizationEnum polarization) const { for (const PolarizedTimeFrequencyData& data : _data) if (data._polarization == polarization) return true; return false; } aocommon::PolarizationEnum GetPolarization(size_t index) const { return _data[index]._polarization; } bool HasXX() const { return HasPolarization(aocommon::Polarization::XX); } bool HasXY() const { return HasPolarization(aocommon::Polarization::XY); } bool HasYX() const { return HasPolarization(aocommon::Polarization::YX); } bool HasYY() const { return HasPolarization(aocommon::Polarization::YY); } /** * This function returns a new Image2D that contains * an image that can be used best for thresholding-like * RFI methods, or visualization. The encapsulated data * may be converted in order to do so. * @return A new image containing the TF-data. */ Image2DCPtr GetSingleImage() const { switch (_complexRepresentation) { case PhasePart: case AmplitudePart: case RealPart: case ImaginaryPart: return GetSingleImageFromSingleComplexPart(); case ComplexParts: return GetSingleAbsoluteFromComplex(); } throw std::runtime_error("Incorrect complex representation"); } Mask2DCPtr GetSingleMask() const { return GetCombinedMask(); } std::array GetSingleComplexImage() const { if (_complexRepresentation != ComplexParts) throw std::runtime_error( "Trying to create single complex image, but no complex data " "available"); if (_data.size() != 1) { return std::array{ {Make(TimeFrequencyData::RealPart).GetSingleImage(), Make(TimeFrequencyData::ImaginaryPart).GetSingleImage()}}; } else { if (_data[0]._images[0] == nullptr || _data[0]._images[1] == nullptr) throw std::runtime_error("Requesting non-existing image"); return std::array{ {_data[0]._images[0], _data[0]._images[1]}}; } } void Set(aocommon::PolarizationEnum polarizationType, const Image2DCPtr& real, const Image2DCPtr& imaginary) { _complexRepresentation = ComplexParts; _data.clear(); _data.emplace_back(polarizationType, real, imaginary); } void SetNoMask() noexcept { for (PolarizedTimeFrequencyData& data : _data) data._flagging = nullptr; } void SetGlobalMask(const Mask2DCPtr& mask) { SetNoMask(); for (PolarizedTimeFrequencyData& data : _data) data._flagging = mask; } Mask2DCPtr GetMask(aocommon::PolarizationEnum polarization) const { for (const PolarizedTimeFrequencyData& data : _data) { if (data._polarization == polarization) { if (data._flagging == nullptr) return GetSetMask(); else return data._flagging; } } return GetSingleMask(); } void SetIndividualPolarizationMasks(const Mask2DCPtr* maskPerPolarization) { for (size_t p = 0; p != _data.size(); ++p) _data[p]._flagging = maskPerPolarization[p]; } void SetIndividualPolarizationMasks(const Mask2DPtr* maskPerPolarization) { for (size_t p = 0; p != _data.size(); ++p) _data[p]._flagging = maskPerPolarization[p]; } void SetIndividualPolarizationMasks(const Mask2DCPtr& maskA, const Mask2DCPtr& maskB) { if (_data.size() != 2) throw std::runtime_error( "Trying to set two individual mask in non-matching time frequency " "data"); _data[0]._flagging = maskA; _data[1]._flagging = maskB; } void SetIndividualPolarizationMasks(const Mask2DCPtr& maskA, const Mask2DCPtr& maskB, const Mask2DCPtr& maskC, const Mask2DCPtr& maskD) { if (_data.size() != 4) throw std::runtime_error( "Trying to set four individual masks in non-matching time frequency " "data"); _data[0]._flagging = maskA; _data[1]._flagging = maskB; _data[2]._flagging = maskC; _data[3]._flagging = maskD; } static TimeFrequencyData MakeZeroLinearData(size_t width, size_t height); TimeFrequencyData Make(ComplexRepresentation representation) const; TimeFrequencyData Make(aocommon::PolarizationEnum polarization) const { for (const PolarizedTimeFrequencyData& data : _data) { if (data._polarization == polarization) return TimeFrequencyData(_complexRepresentation, data); } TimeFrequencyData newData; size_t xxPol = GetPolarizationIndex(aocommon::Polarization::XX), xyPol = GetPolarizationIndex(aocommon::Polarization::XY), yxPol = GetPolarizationIndex(aocommon::Polarization::YX), yyPol = GetPolarizationIndex(aocommon::Polarization::YY); bool hasLinear = xxPol < _data.size() || xyPol < _data.size(); if (hasLinear) { if (_complexRepresentation == ComplexParts) { switch (polarization) { case aocommon::Polarization::StokesI: newData = TimeFrequencyData(aocommon::Polarization::StokesI, getFirstSum(xxPol, yyPol), getSecondSum(xxPol, yyPol)); break; case aocommon::Polarization::StokesQ: newData = TimeFrequencyData(aocommon::Polarization::StokesQ, getFirstDiff(xxPol, yyPol), getSecondDiff(xxPol, yyPol)); break; case aocommon::Polarization::StokesU: newData = TimeFrequencyData(aocommon::Polarization::StokesU, getFirstSum(xyPol, yxPol), getSecondSum(xyPol, yxPol)); break; case aocommon::Polarization::StokesV: newData = TimeFrequencyData(aocommon::Polarization::StokesV, getNegRealPlusImag(xyPol, yxPol), getRealMinusImag(xyPol, yxPol)); break; default: throw std::runtime_error( "Polarization not available or not implemented"); } } else { // _complexRepresentation != ComplexParts // TODO should be done on only real or imaginary switch (polarization) { case aocommon::Polarization::StokesI: newData = TimeFrequencyData(_complexRepresentation, aocommon::Polarization::StokesI, getFirstSum(xxPol, yyPol)); break; case aocommon::Polarization::StokesQ: newData = TimeFrequencyData(_complexRepresentation, aocommon::Polarization::StokesQ, getFirstDiff(xxPol, yyPol)); break; // this is not correct, but it is useful for visualization case aocommon::Polarization::StokesU: newData = TimeFrequencyData(_complexRepresentation, aocommon::Polarization::StokesU, getFirstSum(xyPol, yxPol)); break; default: throw std::runtime_error( "Requested polarization type not available in time frequency " "data"); } } } else { size_t rrPol = GetPolarizationIndex(aocommon::Polarization::RR), rlPol = GetPolarizationIndex(aocommon::Polarization::RL), lrPol = GetPolarizationIndex(aocommon::Polarization::LR), llPol = GetPolarizationIndex(aocommon::Polarization::LL); bool hasCircular = rrPol < _data.size() || rlPol < _data.size(); if (hasCircular) { if (_complexRepresentation == ComplexParts) { switch (polarization) { case aocommon::Polarization::StokesI: newData = TimeFrequencyData(aocommon::Polarization::StokesI, getFirstSum(rrPol, llPol), getSecondSum(rrPol, llPol)); break; case aocommon::Polarization::StokesQ: // Q = RL + LR newData = TimeFrequencyData(aocommon::Polarization::StokesQ, getFirstSum(rlPol, rlPol), getSecondSum(rlPol, lrPol)); break; case aocommon::Polarization::StokesU: // U_r = RL_i - LR_i, U_i = // -RL_r + LR_r newData = TimeFrequencyData(aocommon::Polarization::StokesU, getSecondDiff(rlPol, lrPol), getFirstDiff(lrPol, rlPol)); break; case aocommon::Polarization::StokesV: // V = RR - LL newData = TimeFrequencyData(aocommon::Polarization::StokesV, getFirstDiff(rrPol, llPol), getSecondDiff(rrPol, llPol)); break; default: throw std::runtime_error( "Requested polarization type not available in time frequency " "data"); break; } } else { switch (polarization) { case aocommon::Polarization::StokesI: newData = TimeFrequencyData(_complexRepresentation, aocommon::Polarization::StokesI, getFirstSum(rrPol, llPol)); break; default: throw std::runtime_error( "Requested conversion is not implemented for circular " "polarizations"); } } } else { throw std::runtime_error( "Trying to convert the polarization in time frequency data in an " "invalid way"); } } newData.SetGlobalMask(GetMask(polarization)); return newData; } Image2DCPtr GetRealPart() const { if (_data.size() != 1) { throw std::runtime_error( "This tfdata contains !=1 polarizations; which real part should I " "return?"); } else if (_complexRepresentation == ComplexParts || _complexRepresentation == RealPart) { return _data[0]._images[0]; } else { throw std::runtime_error( "Trying to retrieve real part from time frequency data in which " "values are not stored as complex or reals"); } } Image2DCPtr GetImaginaryPart() const { if (_data.size() != 1) { throw std::runtime_error( "This tfdata contains !=1 polarizations; which imaginary part should " "I return?"); } else if (_complexRepresentation == ComplexParts) { return _data[0]._images[1]; } else if (_complexRepresentation == ImaginaryPart) { return _data[0]._images[0]; } else { throw std::runtime_error( "Trying to retrieve imaginary part from time frequency data in which " "values are not stored as complex or imaginary representation"); } } size_t ImageWidth() const { if (!_data.empty() && _data[0]._images[0] != nullptr) return _data[0]._images[0]->Width(); else return 0; } size_t ImageHeight() const { if (!_data.empty() && _data[0]._images[0] != nullptr) return _data[0]._images[0]->Height(); else return 0; } enum ComplexRepresentation ComplexRepresentation() const { return _complexRepresentation; } std::vector Polarizations() const { std::vector pols; for (const PolarizedTimeFrequencyData& data : _data) pols.push_back(data._polarization); return pols; } void Subtract(const TimeFrequencyData& rhs) { if (rhs._data.size() != _data.size() || rhs._complexRepresentation != _complexRepresentation) { std::stringstream s; s << "Can not subtract time-frequency data: they do not have the same " "number of polarizations or complex representation! (" << rhs._data.size() << " vs. " << _data.size() << ")"; throw std::runtime_error(s.str()); } for (size_t i = 0; i != _data.size(); ++i) { if (_data[i]._images[0] == nullptr) throw std::runtime_error("Can't subtract TFs with unset image data"); _data[i]._images[0].reset(new Image2D(Image2D::MakeFromDiff( *_data[i]._images[0], *rhs._data[i]._images[0]))); if (_data[i]._images[1]) _data[i]._images[1].reset(new Image2D(Image2D::MakeFromDiff( *_data[i]._images[1], *rhs._data[i]._images[1]))); } } void SubtractAsRHS(const TimeFrequencyData& lhs) { if (lhs._data.size() != _data.size() || lhs._complexRepresentation != _complexRepresentation) { std::stringstream s; s << "Can not subtract time-frequency data: they do not have the same " "number of polarizations or complex representation! (" << lhs._data.size() << " vs. " << _data.size() << ")"; throw std::runtime_error(s.str()); } for (size_t i = 0; i != _data.size(); ++i) { if (_data[i]._images[0] == nullptr) throw std::runtime_error("Can't subtract TFs with unset image data"); _data[i]._images[0].reset(new Image2D(Image2D::MakeFromDiff( *lhs._data[i]._images[0], *_data[i]._images[0]))); if (_data[i]._images[1]) _data[i]._images[1].reset(new Image2D(Image2D::MakeFromDiff( *lhs._data[i]._images[1], *_data[i]._images[1]))); } } static TimeFrequencyData MakeFromDiff(const TimeFrequencyData& lhs, const TimeFrequencyData& rhs) { if (lhs._data.size() != rhs._data.size() || lhs._complexRepresentation != rhs._complexRepresentation) { std::stringstream s; s << "Can not subtract time-frequency data: they do not have the same " "number of polarizations or complex representation! (" << lhs._data.size() << " vs. " << rhs._data.size() << ")"; throw std::runtime_error(s.str()); } TimeFrequencyData data(lhs); for (size_t i = 0; i < lhs._data.size(); ++i) { if (lhs._data[i]._images[0] == nullptr) throw std::runtime_error("Can't subtract TFs with unset image data"); data._data[i]._images[0].reset(new Image2D(Image2D::MakeFromDiff( *lhs._data[i]._images[0], *rhs._data[i]._images[0]))); if (lhs._data[i]._images[1]) data._data[i]._images[1].reset(new Image2D(Image2D::MakeFromDiff( *lhs._data[i]._images[1], *rhs._data[i]._images[1]))); } return data; } static TimeFrequencyData MakeFromSum(const TimeFrequencyData& lhs, const TimeFrequencyData& rhs) { if (lhs._data.size() != rhs._data.size() || lhs._complexRepresentation != rhs._complexRepresentation) { std::stringstream s; s << "Can not add time-frequency data: they do not have the same number " "of polarizations or complex representation! (" << lhs._data.size() << " vs. " << rhs._data.size() << ")"; throw std::runtime_error(s.str()); } TimeFrequencyData data(lhs); for (size_t i = 0; i < lhs._data.size(); ++i) { if (lhs._data[i]._images[0] == nullptr) throw std::runtime_error("Can't add TFs with unset image data"); data._data[i]._images[0].reset(new Image2D(Image2D::MakeFromSum( *lhs._data[i]._images[0], *rhs._data[i]._images[0]))); if (lhs._data[i]._images[1]) data._data[i]._images[1].reset(new Image2D(Image2D::MakeFromSum( *lhs._data[i]._images[1], *rhs._data[i]._images[1]))); } return data; } size_t ImageCount() const { size_t images = 0; for (const PolarizedTimeFrequencyData& data : _data) { if (data._images[0]) ++images; if (data._images[1]) ++images; } return images; } size_t MaskCount() const { size_t masks = 0; for (const PolarizedTimeFrequencyData& data : _data) if (data._flagging) ++masks; return masks; } const Image2DCPtr& GetImage(size_t imageIndex) const { size_t index = 0; for (const PolarizedTimeFrequencyData& data : _data) { if (data._images[0]) { if (index == imageIndex) return data._images[0]; ++index; } if (data._images[1]) { if (index == imageIndex) return data._images[1]; ++index; } } throw std::runtime_error("Invalid image index in GetImage()"); } const Mask2DCPtr& GetMask(size_t maskIndex) const { size_t index = 0; for (const PolarizedTimeFrequencyData& data : _data) { if (data._flagging) { if (index == maskIndex) return data._flagging; ++index; } } std::ostringstream msg; msg << "Invalid mask index of " << maskIndex << " in GetMask(): mask count is " << MaskCount(); throw std::runtime_error(msg.str()); } void SetImage(size_t imageIndex, const Image2DCPtr& image) { size_t index = 0; for (PolarizedTimeFrequencyData& data : _data) { if (data._images[0]) { if (index == imageIndex) { data._images[0] = image; return; } ++index; } if (data._images[1]) { if (index == imageIndex) { data._images[1] = image; return; } ++index; } } throw std::runtime_error("Invalid image index in SetImage()"); } void SetImage(size_t imageIndex, Image2DCPtr&& image) { size_t index = 0; for (PolarizedTimeFrequencyData& data : _data) { if (data._images[0]) { if (index == imageIndex) { data._images[0] = std::move(image); return; } ++index; } if (data._images[1]) { if (index == imageIndex) { data._images[1] = std::move(image); return; } ++index; } } throw std::runtime_error("Invalid image index in SetImage()"); } void SetMask(size_t maskIndex, const Mask2DCPtr& mask) { size_t index = 0; for (PolarizedTimeFrequencyData& data : _data) { if (data._flagging) { if (index == maskIndex) { data._flagging = mask; return; } ++index; } } throw std::runtime_error("Invalid mask index in SetMask()"); } void SetMask(size_t maskIndex, Mask2DCPtr&& mask) { size_t index = 0; for (PolarizedTimeFrequencyData& data : _data) { if (data._flagging) { if (index == maskIndex) { data._flagging = std::move(mask); return; } ++index; } } throw std::runtime_error("Invalid mask index in SetMask()"); } void SetMask(const TimeFrequencyData& source) { source.CopyFlaggingTo(this); } static TimeFrequencyData MakeFromComplexCombination( const TimeFrequencyData& real, const TimeFrequencyData& imaginary); static TimeFrequencyData MakeFromPolarizationCombination( const TimeFrequencyData& xx, const TimeFrequencyData& xy, const TimeFrequencyData& yx, const TimeFrequencyData& yy); static TimeFrequencyData MakeFromPolarizationCombination( const TimeFrequencyData& first, const TimeFrequencyData& second); void SetImagesToZero(); template void SetMasksToValue() { if (!IsEmpty()) { Mask2DPtr mask = Mask2D::CreateSetMaskPtr(ImageWidth(), ImageHeight()); for (PolarizedTimeFrequencyData& data : _data) { data._flagging = mask; } } } void MultiplyImages(long double factor); void JoinMask(const TimeFrequencyData& other); void Trim(unsigned timeStart, unsigned freqStart, unsigned timeEnd, unsigned freqEnd) { for (PolarizedTimeFrequencyData& data : _data) { if (data._images[0]) data._images[0].reset(new Image2D( data._images[0]->Trim(timeStart, freqStart, timeEnd, freqEnd))); if (data._images[1]) data._images[1].reset(new Image2D( data._images[1]->Trim(timeStart, freqStart, timeEnd, freqEnd))); if (data._flagging) data._flagging.reset(new Mask2D( data._flagging->Trim(timeStart, freqStart, timeEnd, freqEnd))); } } std::string Description() const { std::ostringstream s; switch (_complexRepresentation) { case RealPart: s << "Real component of "; break; case ImaginaryPart: s << "Imaginary component of "; break; case PhasePart: s << "Phase of "; break; case AmplitudePart: s << "Amplitude of "; break; case ComplexParts: break; } if (_data.empty()) { s << "empty"; } else { s << "(" << aocommon::Polarization::TypeToFullString(_data[0]._polarization); for (size_t i = 1; i != _data.size(); ++i) s << "," << aocommon::Polarization::TypeToFullString(_data[i]._polarization); s << ")"; } return s.str(); } size_t PolarizationCount() const { return _data.size(); } TimeFrequencyData MakeFromPolarizationIndex(size_t index) const { return TimeFrequencyData(_complexRepresentation, _data[index]); } void SetPolarizationData(size_t polarizationIndex, const TimeFrequencyData& data) { if (data.PolarizationCount() != 1) throw std::runtime_error( "Trying to set multiple polarizations by single polarization index"); else if (data.ComplexRepresentation() != ComplexRepresentation()) throw std::runtime_error( "Trying to combine TFData's with different complex representations"); else _data[polarizationIndex] = data._data[0]; } void SetPolarizationData(size_t polarizationIndex, TimeFrequencyData&& data) { if (data.PolarizationCount() != 1) { throw std::runtime_error( "Trying to set multiple polarizations by single polarization index"); } else if (data.ComplexRepresentation() != ComplexRepresentation()) { throw std::runtime_error( "Trying to combine TFData's with different complex representations"); } else { _data[polarizationIndex] = std::move(data._data[0]); data._data.clear(); } } void SetImageSize(size_t width, size_t height) { for (size_t i = 0; i < _data.size(); ++i) { if (_data[i]._images[0]) _data[i]._images[0] = Image2D::CreateUnsetImagePtr(width, height); if (_data[i]._images[1]) _data[i]._images[1] = Image2D::CreateUnsetImagePtr(width, height); if (_data[i]._flagging) _data[i]._flagging = Mask2D::CreateUnsetMaskPtr(width, height); } } void CopyFrom(const TimeFrequencyData& source, size_t destX, size_t destY) { if (source._data.size() != _data.size()) throw std::runtime_error("CopyFrom: tf data do not match"); for (size_t i = 0; i < _data.size(); ++i) { if (_data[i]._images[0]) { Image2D image(*_data[i]._images[0]); image.CopyFrom(*source._data[i]._images[0], destX, destY); _data[i]._images[0].reset(new Image2D(std::move(image))); } if (_data[i]._images[1]) { Image2D image(*_data[i]._images[1]); image.CopyFrom(*source._data[i]._images[1], destX, destY); _data[i]._images[1].reset(new Image2D(std::move(image))); } if (_data[i]._flagging) { Mask2D mask(*_data[i]._flagging); mask.CopyFrom(*source._data[i]._flagging, destX, destY); _data[i]._flagging.reset(new Mask2D(std::move(mask))); } } } /** * Will return true when this is the imaginary part of the visibilities. Will * throw an exception when the data is neither real nor imaginary. */ bool IsImaginary() const { if (ComplexRepresentation() == RealPart) return false; else if (ComplexRepresentation() == ImaginaryPart) return true; else throw std::runtime_error("Data is not real or imaginary"); } /** * Returns the data index of the given polarization, or _data.size() if * not found. */ size_t GetPolarizationIndex(aocommon::PolarizationEnum polarization) const { for (size_t i = 0; i != _data.size(); ++i) if (_data[i]._polarization == polarization) return i; return _data.size(); } private: Image2DCPtr GetSingleAbsoluteFromComplex() const { if (_data.size() == 4) return GetAbsoluteFromComplex(getFirstSum(0, 3), getSecondSum(0, 3)); else if (_data.size() == 2) return GetAbsoluteFromComplex(getFirstSum(0, 1), getSecondSum(0, 1)); else return getAbsoluteFromComplex(0); } Image2DCPtr GetSingleImageFromSingleComplexPart() const { if (_data.size() == 4) { if (_complexRepresentation == PhasePart) return getSinglePhaseFromTwoPolPhase(0, 3); else return getFirstSum(0, 3); } if (_data.size() == 2) { if (_complexRepresentation == PhasePart) return getSinglePhaseFromTwoPolPhase(0, 1); else return getFirstSum(0, 1); } else { // if(_data.size() == 1) return _data[0]._images[0]; } } void CopyFlaggingTo(TimeFrequencyData* data) const { if (MaskCount() == 0) { data->SetNoMask(); } else if (MaskCount() == 1) { data->SetGlobalMask(GetMask(0)); } else { if (_data.size() == data->_data.size()) { for (size_t i = 0; i != _data.size(); ++i) data->_data[i]._flagging = _data[i]._flagging; } else { throw std::runtime_error( "Trying to copy flagging from incompatible time frequency data"); } } } Image2DCPtr getAbsoluteFromComplex(size_t polIndex) const { return GetAbsoluteFromComplex(_data[polIndex]._images[0], _data[polIndex]._images[1]); } Image2DCPtr GetAbsoluteFromComplex(const Image2DCPtr& real, const Image2DCPtr& imag) const; Image2DCPtr getFirstSum(size_t dataIndexA, size_t dataIndexB) const { if (dataIndexA >= _data.size()) throw std::runtime_error("Polarization not available"); if (dataIndexB >= _data.size()) throw std::runtime_error("Polarization not available"); return GetSum(_data[dataIndexA]._images[0], _data[dataIndexB]._images[0]); } Image2DCPtr getSecondSum(size_t dataIndexA, size_t dataIndexB) const { if (dataIndexA >= _data.size()) throw std::runtime_error("Polarization not available"); if (dataIndexB >= _data.size()) throw std::runtime_error("Polarization not available"); return GetSum(_data[dataIndexA]._images[1], _data[dataIndexB]._images[1]); } Image2DCPtr getFirstDiff(size_t dataIndexA, size_t dataIndexB) const { if (dataIndexA >= _data.size()) throw std::runtime_error("Polarization not available"); if (dataIndexB >= _data.size()) throw std::runtime_error("Polarization not available"); return GetDifference(_data[dataIndexA]._images[0], _data[dataIndexB]._images[0]); } Image2DCPtr getSecondDiff(size_t dataIndexA, size_t dataIndexB) const { if (dataIndexA >= _data.size()) throw std::runtime_error("Polarization not available"); if (dataIndexB >= _data.size()) throw std::runtime_error("Polarization not available"); return GetDifference(_data[dataIndexA]._images[1], _data[dataIndexB]._images[1]); } Image2DCPtr getNegRealPlusImag(size_t xyIndex, size_t yxIndex) const { if (xyIndex >= _data.size()) throw std::runtime_error("Polarization not available"); if (yxIndex >= _data.size()) throw std::runtime_error("Polarization not available"); return GetNegatedSum(_data[xyIndex]._images[1], _data[yxIndex]._images[0]); } Image2DCPtr getRealMinusImag(size_t xyIndex, size_t yxIndex) const { if (xyIndex >= _data.size()) throw std::runtime_error("Polarization not available"); if (yxIndex >= _data.size()) throw std::runtime_error("Polarization not available"); return GetDifference(_data[xyIndex]._images[0], _data[yxIndex]._images[1]); } Image2DCPtr GetSum(const Image2DCPtr& left, const Image2DCPtr& right) const; Image2DCPtr GetNegatedSum(const Image2DCPtr& left, const Image2DCPtr& right) const; Image2DCPtr GetDifference(const Image2DCPtr& left, const Image2DCPtr& right) const; Image2DCPtr getSinglePhaseFromTwoPolPhase(size_t polA, size_t polB) const; // Image2DCPtr GetZeroImage() const; template Mask2DCPtr GetSetMask() const { if (ImageWidth() == 0 || ImageHeight() == 0) throw std::runtime_error("Can't make a mask without an image"); return Mask2D::CreateSetMaskPtr(ImageWidth(), ImageHeight()); } Mask2DCPtr GetCombinedMask() const; struct PolarizedTimeFrequencyData { PolarizedTimeFrequencyData() : _images{nullptr, nullptr}, _flagging(nullptr), _polarization(aocommon::Polarization::StokesI) {} PolarizedTimeFrequencyData(aocommon::PolarizationEnum polarization, const Image2DCPtr& image) : _images{image, nullptr}, _flagging(nullptr), _polarization(polarization) {} PolarizedTimeFrequencyData(aocommon::PolarizationEnum polarization, const Image2DCPtr& imageA, const Image2DCPtr& imageB) : _images{imageA, imageB}, _flagging(nullptr), _polarization(polarization) {} // Second image is only filled when complex representation = complex parts Image2DCPtr _images[2]; Mask2DCPtr _flagging; aocommon::PolarizationEnum _polarization; }; TimeFrequencyData(enum ComplexRepresentation complexRepresentation, const PolarizedTimeFrequencyData& source) : _complexRepresentation(complexRepresentation), _data(1, source) {} enum ComplexRepresentation _complexRepresentation; std::vector _data; }; /** * Concatenates the data inside the time-frequency data into a single vector. * The returned vector will be ordered in polarization (major), frequency and * then time. */ std::vector> ToComplexVector( const TimeFrequencyData& tf_data); TimeFrequencyData ElementWiseDivide(const TimeFrequencyData& lhs, const TimeFrequencyData& rhs); TimeFrequencyData ElementWiseNorm(const TimeFrequencyData& data); TimeFrequencyData ElementWiseSqrt(const TimeFrequencyData& data); #endif aoflagger-v3.4.0/structures/mask2d.cpp0000644000175000017500000001633114507760372016450 0ustar olesoles#include "mask2d.h" #include "image2d.h" #include #include Mask2D::Mask2D() : _width(0), _height(0), _stride(0), _values(nullptr), _valuesConsecutive(nullptr) {} Mask2D::Mask2D(const Mask2D& source) : Mask2D(source.Width(), source.Height()) { memcpy(_valuesConsecutive, source._valuesConsecutive, _stride * _height * sizeof(bool)); } Mask2D::Mask2D(Mask2D&& source) noexcept : _width(source._width), _height(source._height), _stride(source._stride), _values(source._values), _valuesConsecutive(source._valuesConsecutive) { source._width = 0; source._stride = 0; source._height = 0; source._values = nullptr; source._valuesConsecutive = nullptr; } Mask2D::Mask2D(size_t width, size_t height) : _width(width), _height(height), _stride((((width - 1) / 4) + 1) * 4) { if (_width == 0) _stride = 0; allocate(); } void Mask2D::allocate() { unsigned allocHeight = ((((_height - 1) / 4) + 1) * 4); if (_height == 0) allocHeight = 0; _valuesConsecutive = new bool[_stride * allocHeight * sizeof(bool)]; _values = new bool*[allocHeight]; for (size_t y = 0; y < _height; ++y) { _values[y] = &_valuesConsecutive[_stride * y]; // Even though the values after the requested width are never relevant, we // will initialize them to true to prevent valgrind to report unset values // when they are used in SSE instructions. for (size_t x = _width; x < _stride; ++x) { _values[y][x] = true; } } for (size_t y = _height; y < allocHeight; ++y) { _values[y] = &_valuesConsecutive[_stride * y]; // (see remark above about initializing to true) for (size_t x = 0; x < _stride; ++x) { _values[y][x] = true; } } } Mask2D::~Mask2D() noexcept { delete[] _values; delete[] _valuesConsecutive; } Mask2D& Mask2D::operator=(const Mask2D& rhs) { if (_width != rhs._width || _height != rhs._height || _stride != rhs._stride) { delete[] _values; delete[] _valuesConsecutive; _width = rhs._width; _height = rhs._height; _stride = rhs._stride; allocate(); } std::copy(rhs._valuesConsecutive, rhs._valuesConsecutive + _stride * _height, _valuesConsecutive); return *this; } Mask2D& Mask2D::operator=(Mask2D&& rhs) noexcept { std::swap(rhs._width, _width); std::swap(rhs._stride, _stride); std::swap(rhs._height, _height); std::swap(rhs._values, _values); std::swap(rhs._valuesConsecutive, _valuesConsecutive); return *this; } Mask2D* Mask2D::CreateUnsetMask(const Image2D& templateImage) { return new Mask2D(templateImage.Width(), templateImage.Height()); } template Mask2D* Mask2D::CreateSetMask(const class Image2D& templateImage) { size_t width = templateImage.Width(), height = templateImage.Height(); Mask2D* newMask = new Mask2D(width, height); memset(newMask->_valuesConsecutive, InitValue, newMask->_stride * height * sizeof(bool)); return newMask; } template Mask2D* Mask2D::CreateSetMask( const class Image2D& templateImage); template Mask2D* Mask2D::CreateSetMask( const class Image2D& templateImage); Mask2DPtr Mask2D::CreatePtrFromRows(const Mask2D& source, size_t offset, size_t count) { assert(offset <= source._height && offset + count <= source._height && "The selected rows exceed the height of the source."); Mask2DPtr result = Mask2D::CreateUnsetMaskPtr(source._width, count); assert(result->_valuesConsecutive && source._valuesConsecutive && "The construction of a mask should always allocate memory."); std::copy_n(source._valuesConsecutive + result->_stride * offset, result->_stride * count, result->_valuesConsecutive); return result; } Mask2D Mask2D::ShrinkHorizontally(int factor) const { const size_t newWidth = (_width + factor - 1) / factor; Mask2D newMask(newWidth, _height); for (size_t x = 0; x < newWidth; ++x) { size_t binSize = factor; if (binSize + x * factor > _width) binSize = _width - x * factor; for (size_t y = 0; y < _height; ++y) { bool value = false; for (size_t binX = 0; binX < binSize; ++binX) { const size_t curX = x * factor + binX; value = value | Value(curX, y); } newMask.SetValue(x, y, value); } } return newMask; } Mask2D Mask2D::ShrinkHorizontallyForAveraging(int factor) const { const size_t newWidth = (_width + factor - 1) / factor; Mask2D newMask(newWidth, _height); for (size_t x = 0; x < newWidth; ++x) { size_t binSize = factor; if (binSize + x * factor > _width) binSize = _width - x * factor; for (size_t y = 0; y < _height; ++y) { bool value = true; for (size_t binX = 0; binX < binSize; ++binX) { const size_t curX = x * factor + binX; value = value & Value(curX, y); } newMask.SetValue(x, y, value); } } return newMask; } Mask2D Mask2D::ShrinkVertically(int factor) const { const size_t newHeight = (_height + factor - 1) / factor; Mask2D newMask(_width, newHeight); for (size_t y = 0; y < newHeight; ++y) { size_t binSize = factor; if (binSize + y * factor > _height) binSize = _height - y * factor; for (size_t x = 0; x < _width; ++x) { bool value = false; for (size_t binY = 0; binY < binSize; ++binY) { const size_t curY = y * factor + binY; value = value | Value(x, curY); } newMask.SetValue(x, y, value); } } return newMask; } Mask2D Mask2D::ShrinkVerticallyForAveraging(int factor) const { const size_t newHeight = (_height + factor - 1) / factor; Mask2D newMask(_width, newHeight); for (size_t y = 0; y != newHeight; ++y) { size_t binSize = factor; if (binSize + y * factor > _height) binSize = _height - y * factor; for (size_t x = 0; x != _width; ++x) { bool value = true; for (size_t binY = 0; binY != binSize; ++binY) { const size_t curY = y * factor + binY; value = value & Value(x, curY); } newMask.SetValue(x, y, value); } } return newMask; } void Mask2D::EnlargeHorizontallyAndSet(const Mask2D& smallMask, int factor) { for (size_t x = 0; x < smallMask.Width(); ++x) { size_t binSize = factor; if (binSize + x * factor > _width) binSize = _width - x * factor; for (size_t y = 0; y < _height; ++y) { for (size_t binX = 0; binX < binSize; ++binX) { const size_t curX = x * factor + binX; SetValue(curX, y, smallMask.Value(x, y)); } } } } void Mask2D::EnlargeVerticallyAndSet(const Mask2D& smallMask, int factor) { for (size_t y = 0; y < smallMask.Height(); ++y) { size_t binSize = factor; if (binSize + y * factor > _height) binSize = _height - y * factor; for (size_t x = 0; x < _width; ++x) { for (size_t binY = 0; binY < binSize; ++binY) { const size_t curY = y * factor + binY; SetValue(x, curY, smallMask.Value(x, y)); } } } } std::string Mask2D::ToString() const { std::string str(_height * (_width + 1), ' '); for (size_t y = 0; y != _height; ++y) { const bool* row = ValuePtr(0, y); for (size_t x = 0; x != _width; ++x) { if (row[x]) str[y * (_width + 1) + x] = 'X'; } str[y * (_width + 1) + _width] = '\n'; } return str; } aoflagger-v3.4.0/structures/date.h0000644000175000017500000001076714507760372015660 0ustar olesoles#ifndef MSIODATE_H #define MSIODATE_H #include #include #include class Date { public: static double JDToYears(double jd) noexcept { return jd / 365.25L - 4712.0L; } static double JDToMonth(double jd) noexcept { return ((int)floor((jd / (365.25L) - 4712.0L) / 12.0L)) % 12; } static int JDToDayOfYear(double jd) noexcept { // return floor(jd - floor(jd / (365.25L))*365.25L); double x2 = (jd - 1721119.5); // number of days since year 0 int c2 = (int)((8.0 * x2 + 7.0) / 292194.0); double x1 = x2 - floor(146097.0 * c2 / 4.0); // number of days since beginning of century int c1 = (int)((200 * x1 + 199) / 73050); double x0 = x1 - floor(36525.0 * c1 / 100.0); return (int)x0; } static void JDToDate(double jd, int& dayOfMonth, int& month, int& year) noexcept { double x2 = (jd - 1721119.5); // number of days since year 0 int c2 = (int)((8.0 * x2 + 7.0) / 292194.0); double x1 = x2 - floor(146097.0 * c2 / 4.0); // number of days since beginning of century int c1 = (int)((200 * x1 + 199) / 73050); double x0 = x1 - floor(36525.0 * c1 / 100.0); year = 100 * c2 + c1; month = (int)((10.0 * x0 + 923.0) / 306.0); dayOfMonth = (int)x0 - ((153 * month - 457) / 5) + 1; if (month > 12) { month -= 12; ++year; } } static double JDToHourOfDay(double jd) noexcept { return fmodl(jd + 0.5, 1.0) * 24.0; } static double MJDToJD(double mjd) noexcept { return mjd + 2400000.5; } static double JDToMJD(double jd) noexcept { return jd - 2400000.5; } static double JDToAipsMJD(double jd) noexcept { return JDToMJD(jd) * (60.0 * 60.0 * 24.0); } static double MJDToAipsMJD(double jd) noexcept { return jd * (60.0 * 60.0 * 24.0); } static double AipsMJDToJD(double aipsMjd) noexcept { return MJDToJD(aipsMjd / (60.0 * 60.0 * 24.0)); } static double AipsMJDToYears(double aipsMjd) noexcept { return JDToYears(AipsMJDToJD(aipsMjd)); } static std::string ToString(double time, int dayOfMonth, int month, int year) { std::stringstream s; int mins = int(time * 60) % 60; int secs = int(time * 3600) % 60; int msec = int(time * 3600000) % 1000; s << floor(time) << ":" << (mins / 10) << (mins % 10) << ":" << (secs / 10) << (secs % 10) << "." << msec / 100 << (msec / 10) % 10 << (msec) % 10 << ", " << year << "-"; if (month < 10) s << "0"; s << month << "-"; if (dayOfMonth < 10) s << "0"; s << dayOfMonth; return s.str(); } static std::string ToString(double time) { std::stringstream s; int msec = int(round(time * 3600000)) % 1000; time -= msec / 3600000.0; int secs = int(round(time * 3600)) % 60; time -= secs / 3600.0; int mins = int(round(time * 60)) % 60; time -= mins / 60.0; int hours = int(round(time)); s << hours << ":" << (mins / 10) << (mins % 10); if (msec != 0 || secs != 0) { s << ":" << (secs / 10) << (secs % 10); if (msec != 0) { s << "." << msec / 100; if (msec % 100 != 0) { s << (msec / 10) % 10; if (msec % 10 != 0) s << (msec) % 10; } } } return s.str(); } static std::string ToString(int dayOfMonth, int month, int year) { std::stringstream s; s << year << "-"; if (month < 10) s << "0"; s << month << "-"; if (dayOfMonth < 10) s << "0"; s << dayOfMonth; return s.str(); } static std::string AipsMJDToString(double aipsMjd) { double jd = AipsMJDToJD(aipsMjd); double time = JDToHourOfDay(jd); int year, month, day; JDToDate(jd, day, month, year); return ToString(time, day, month, year); } static std::string AipsMJDToDateString(double aipsMjd) { double jd = AipsMJDToJD(aipsMjd); int year, month, day; JDToDate(jd, day, month, year); return ToString(day, month, year); } static std::string AipsMJDToTimeString(double aipsMjd) { double jd = AipsMJDToJD(aipsMjd); double time = JDToHourOfDay(jd); return ToString(time); } static std::string AipsMJDToRoundTimeString(double aipsMjd) { double jd = AipsMJDToJD(aipsMjd); double time = round(JDToHourOfDay(jd) * 60.0 * 60.0) / (60.0 * 60.0); return ToString(time); } static std::string JDToString(double jd) { double time = JDToHourOfDay(jd); int year, month, day; JDToDate(jd, day, month, year); return ToString(time, day, month, year); } }; #endif // MSIODATE_H aoflagger-v3.4.0/structures/msrowdata.h0000644000175000017500000000440714507760372016736 0ustar olesoles#ifndef MS_ROW_DATA_H #define MS_ROW_DATA_H #include #include #include "types.h" #include "../util/serializable.h" /** * Encapsulates the information that is contained in the Data column in one row * of a measurement set. * If some of the meta data needs to be stored as well, use the MSRowDataExt * class. * @see MSRowDataExt */ class MSRowData : public Serializable { public: MSRowData() = default; MSRowData(unsigned polarizationCount, unsigned channelCount) : _polarizationCount(polarizationCount), _channelCount(channelCount), _realData(polarizationCount * channelCount), _imagData(polarizationCount * channelCount) {} virtual void Serialize(std::ostream& stream) const final override { SerializeToUInt32(stream, _polarizationCount); SerializeToUInt32(stream, _channelCount); for (num_t val : _realData) SerializeToFloat(stream, val); for (num_t val : _imagData) SerializeToFloat(stream, val); } virtual void Unserialize(std::istream& stream) final override { _polarizationCount = UnserializeUInt32(stream); _channelCount = UnserializeUInt32(stream); const size_t size = _polarizationCount * _channelCount; _realData.resize(size); _imagData.resize(size); for (size_t i = 0; i < size; ++i) _realData[i] = UnserializeFloat(stream); for (size_t i = 0; i < size; ++i) _imagData[i] = UnserializeFloat(stream); } unsigned PolarizationCount() const { return _polarizationCount; } unsigned ChannelCount() const { return _channelCount; } const num_t* RealPtr() const { return _realData.data(); } const num_t* ImagPtr() const { return _imagData.data(); } num_t* RealPtr() { return _realData.data(); } num_t* ImagPtr() { return _imagData.data(); } const num_t* RealPtr(size_t channel) const { return &_realData[_polarizationCount * channel]; } const num_t* ImagPtr(size_t channel) const { return &_imagData[_polarizationCount * channel]; } num_t* RealPtr(size_t channel) { return &_realData[_polarizationCount * channel]; } num_t* ImagPtr(size_t channel) { return &_imagData[_polarizationCount * channel]; } private: unsigned _polarizationCount, _channelCount; std::vector _realData, _imagData; }; #endif aoflagger-v3.4.0/structures/timefrequencymetadata.h0000644000175000017500000001216014507760372021311 0ustar olesoles#ifndef MSIO_TIME_FREQUENCY_META_DATA_H #define MSIO_TIME_FREQUENCY_META_DATA_H #include #include #include #include "antennainfo.h" typedef std::shared_ptr TimeFrequencyMetaDataPtr; typedef std::shared_ptr TimeFrequencyMetaDataCPtr; class TimeFrequencyMetaData { public: TimeFrequencyMetaData() : _sequenceId(0), _valueDescription("Visibility"), _valueUnits("Jy") {} TimeFrequencyMetaData(const AntennaInfo& antenna1, const AntennaInfo& antenna2, const BandInfo& band, const FieldInfo& field, const std::vector& observationTimes) : _antenna1(new AntennaInfo(antenna1)), _antenna2(new AntennaInfo(antenna2)), _band(new BandInfo(band)), _sequenceId(0), _field(new FieldInfo(field)), _observationTimes(new std::vector(observationTimes)), _valueDescription("Visibility"), _valueUnits("Jy") {} TimeFrequencyMetaData(const TimeFrequencyMetaData& source) : _sequenceId(source._sequenceId), _valueDescription(source._valueDescription), _valueUnits(source._valueUnits) { if (source._antenna1) _antenna1.reset(new AntennaInfo(*source._antenna1)); if (source._antenna2) _antenna2.reset(new AntennaInfo(*source._antenna2)); if (source._band) _band.reset(new BandInfo(*source._band)); if (source._field) _field.reset(new FieldInfo(*source._field)); if (source._observationTimes) _observationTimes.reset( new std::vector(*source._observationTimes)); if (source._uvw) _uvw.reset(new std::vector(*source._uvw)); } TimeFrequencyMetaData& operator=(const TimeFrequencyMetaData& rhs) { _sequenceId = rhs._sequenceId; _valueDescription = rhs._valueDescription; _valueUnits = rhs._valueUnits; if (rhs._antenna1) _antenna1.reset(new AntennaInfo(*rhs._antenna1)); if (rhs._antenna2) _antenna2.reset(new AntennaInfo(*rhs._antenna2)); if (rhs._band) _band.reset(new BandInfo(*rhs._band)); if (rhs._field) _field.reset(new FieldInfo(*rhs._field)); if (rhs._observationTimes) _observationTimes.reset(new std::vector(*rhs._observationTimes)); if (rhs._uvw) _uvw.reset(new std::vector(*rhs._uvw)); return *this; } const AntennaInfo& Antenna1() const { return *_antenna1; } void ClearAntenna1() { _antenna1.reset(); } void SetAntenna1(const AntennaInfo& antenna1) { _antenna1.reset(new AntennaInfo(antenna1)); } bool HasAntenna1() const { return static_cast(_antenna1); } const AntennaInfo& Antenna2() const { return *_antenna2; } void ClearAntenna2() { _antenna2.reset(); } void SetAntenna2(const AntennaInfo& antenna2) { _antenna2.reset(new AntennaInfo(antenna2)); } bool HasAntenna2() const { return static_cast(_antenna2); } const BandInfo& Band() const { return *_band; } void ClearBand() { _band.reset(); } void SetBand(const BandInfo& band) { _band.reset(new BandInfo(band)); } bool HasBand() const { return static_cast(_band); } const FieldInfo& Field() const { return *_field; } void ClearField() { _field.reset(); } void SetField(const FieldInfo& field) { _field.reset(new FieldInfo(field)); } bool HasField() const { return static_cast(_field); } const std::vector& ObservationTimes() const { return *_observationTimes; } void ClearObservationTimes() { _observationTimes.reset(); } void SetObservationTimes(const std::vector& times) { _observationTimes.reset(new std::vector(times)); } void SetObservationTimes(std::vector&& times) { _observationTimes.reset(new std::vector(std::move(times))); } bool HasObservationTimes() const { return static_cast(_observationTimes) && !_observationTimes->empty(); } unsigned SequenceId() const { return _sequenceId; } void SetSequenceId(unsigned sequenceId) { _sequenceId = sequenceId; } const std::vector& UVW() const { return *_uvw; } void ClearUVW() { _uvw.reset(); } void SetUVW(const std::vector& uvw) { _uvw.reset(new std::vector(uvw)); } bool HasUVW() const { return static_cast(_uvw); } bool HasBaseline() const { return HasAntenna1() && HasAntenna2(); } class Baseline Baseline() const { return ::Baseline(*_antenna1, *_antenna2); } const std::string& ValueDescription() const { return _valueDescription; } void SetValueDescription(const std::string& valueDescription) { _valueDescription = valueDescription; } const std::string& ValueUnits() const { return _valueUnits; } void SetValueUnits(const std::string& valueUnits) { _valueUnits = valueUnits; } private: std::unique_ptr _antenna1; std::unique_ptr _antenna2; std::unique_ptr _band; unsigned _sequenceId; std::unique_ptr _field; std::unique_ptr> _observationTimes; std::unique_ptr> _uvw; std::string _valueDescription, _valueUnits; }; #endif // MSIO_TIME_FREQUENCY_META_DATA_H aoflagger-v3.4.0/structures/samplerow.h0000644000175000017500000002004714507760372016744 0ustar olesoles#ifndef SAMPLEROW_H #define SAMPLEROW_H #include #include #include #include #include #include "image2d.h" #include "mask2d.h" #include "../algorithms/convolutions.h" class SampleRow { public: explicit SampleRow(size_t size) : _values(size) {} static SampleRow MakeEmpty(size_t size) { return SampleRow(size); } static SampleRow MakeZero(size_t size) { SampleRow row(size); std::fill(row._values.begin(), row._values.end(), 0.0); return row; } static SampleRow MakeFromRow(const Image2D* image, size_t y) { SampleRow row(image->Width()); std::copy(image->ValuePtr(0, y), image->ValuePtr(0, y) + image->Width(), row._values.data()); return row; } static SampleRow MakeFromRow(const Image2D* image, size_t xStart, size_t length, size_t y) { SampleRow row(length); std::copy(image->ValuePtr(xStart, y), image->ValuePtr(xStart, y) + length, row._values.data()); return row; } static SampleRow MakeFromRowWithMissings(const Image2D* image, const Mask2D* mask, size_t y) { SampleRow row(image->Width()); for (size_t x = 0; x < image->Width(); ++x) { if (mask->Value(x, y)) row._values[x] = std::numeric_limits::quiet_NaN(); else row._values[x] = image->Value(x, y); } return row; } static SampleRow MakeAmplitudeFromRow(const Image2D* real, const Image2D* imaginary, size_t y) { SampleRow row(real->Width()); for (size_t x = 0; x < real->Width(); ++x) { row._values[x] = sqrtn(real->Value(x, y) * real->Value(x, y) + imaginary->Value(x, y) * imaginary->Value(x, y)); } return row; } static SampleRow MakeFromColumn(const Image2D* image, size_t x) { SampleRow row(image->Height()); for (size_t y = 0; y < image->Height(); ++y) row._values[y] = image->Value(x, y); return row; } static SampleRow MakeFromColumnWithMissings(const Image2D* image, const Mask2D* mask, size_t x) { SampleRow row(image->Height()); for (size_t y = 0; y < image->Height(); ++y) { if (mask->Value(x, y)) row._values[y] = std::numeric_limits::quiet_NaN(); else row._values[y] = image->Value(x, y); } return row; } static SampleRow MakeFromRowSum(const Image2D* image, size_t yStart, size_t yEnd) { if (yEnd > yStart) { SampleRow row = MakeFromRow(image, yStart); for (size_t y = yStart + 1; y < yEnd; ++y) { for (size_t x = 0; x < image->Width(); ++x) row._values[x] += image->Value(x, y); } return row; } else { return MakeZero(image->Width()); } } static SampleRow MakeFromColumnSum(const Image2D* image, size_t xStart, size_t xEnd) { if (xEnd > xStart) { SampleRow row = MakeFromColumn(image, xStart); for (size_t x = xStart + 1; x < xEnd; ++x) { for (size_t y = 0; y < image->Width(); ++y) row._values[y] += image->Value(x, y); } return row; } else { return MakeZero(image->Width()); } } void SetHorizontalImageValues(Image2D* image, unsigned y) const noexcept { for (size_t i = 0; i < _values.size(); ++i) { image->SetValue(i, y, _values[i]); } } void SetHorizontalImageValues(Image2D* image, unsigned xStart, unsigned y) const noexcept { for (size_t i = 0; i < _values.size(); ++i) { image->SetValue(i + xStart, y, _values[i]); } } void SetVerticalImageValues(Image2D* image, unsigned x) const noexcept { for (size_t i = 0; i < _values.size(); ++i) { image->SetValue(x, i, _values[i]); } } void SetVerticalImageValues(Image2D* image, unsigned x, unsigned yStart) const noexcept { for (size_t i = 0; i < _values.size(); ++i) { image->SetValue(x, i + yStart, _values[i]); } } num_t Value(size_t i) const noexcept { return _values[i]; } void SetValue(size_t i, num_t newValue) noexcept { _values[i] = newValue; } size_t Size() const noexcept { return _values.size(); } size_t IndexOfMax() const noexcept { size_t maxIndex = 0; num_t maxValue = _values[0]; for (size_t i = 1; i < _values.size(); ++i) { if (_values[i] > maxValue) { maxIndex = i; maxValue = _values[i]; } } return maxIndex; } numl_t RMS() const noexcept { if (_values.empty()) return std::numeric_limits::quiet_NaN(); numl_t sum = 0.0; for (num_t v : _values) sum += v * v; return sqrtnl(sum / _values.size()); } num_t Median() const noexcept { if (_values.empty()) return std::numeric_limits::quiet_NaN(); std::vector copy(_values); if (_values.size() % 2 == 0) { size_t m = _values.size() / 2 - 1; std::nth_element(copy.begin(), copy.begin() + m, copy.end()); num_t leftMid = *(copy.begin() + m); std::nth_element(copy.begin(), copy.begin() + m + 1, copy.end()); num_t rightMid = *(copy.begin() + m + 1); return (leftMid + rightMid) / 2; } else { size_t m = _values.size() / 2; std::nth_element(copy.begin(), copy.begin() + m, copy.end()); num_t mid = *(copy.begin() + m); return mid; } } numl_t Mean() const noexcept { numl_t mean = 0.0; for (num_t v : _values) mean += v; return mean / _values.size(); } numl_t MeanWithMissings() const noexcept { numl_t mean = 0.0; size_t count = 0; for (num_t v : _values) { if (std::isfinite(v)) { mean += v; ++count; } } return mean / count; } numl_t StdDev(double mean) const noexcept { numl_t stddev = 0.0; for (num_t v : _values) stddev += (v - mean) * (v - mean); return sqrtnl(stddev / _values.size()); } num_t RMSWithMissings() const { return MakeWithoutMissings().RMS(); } num_t MedianWithMissings() const { return MakeWithoutMissings().Median(); } num_t StdDevWithMissings(double mean) const { return MakeWithoutMissings().StdDev(mean); } SampleRow MakeWithoutMissings() const; bool ValueIsMissing(size_t i) const { return !std::isfinite(Value(i)); } void SetValueMissing(size_t i) { SetValue(i, std::numeric_limits::quiet_NaN()); } void ConvolveWithGaussian(num_t sigma) { algorithms::Convolutions::OneDimensionalGausConvolution( _values.data(), _values.size(), sigma); } void ConvolveWithSinc(num_t frequency) { algorithms::Convolutions::OneDimensionalSincConvolution( _values.data(), _values.size(), frequency); } SampleRow* operator-=(const SampleRow& source) noexcept { for (unsigned i = 0; i < _values.size(); ++i) _values[i] -= source._values[i]; return this; } num_t WinsorizedMean() const { std::vector data(_values); std::sort(data.begin(), data.end(), numLessThanOperator); size_t lowIndex = (size_t)floor(0.1 * data.size()); size_t highIndex = (size_t)ceil(0.9 * data.size()) - 1; num_t lowValue = data[lowIndex]; num_t highValue = data[highIndex]; // Calculate mean num_t mean = 0.0; for (size_t x = 0; x < data.size(); ++x) { const num_t value = data[x]; if (value < lowValue) mean += lowValue; else if (value > highValue) mean += highValue; else mean += value; } return mean / (num_t)data.size(); } num_t WinsorizedMeanWithMissings() const { return MakeWithoutMissings().WinsorizedMean(); } private: std::vector _values; // We need this less than operator, because the normal operator // does not enforce a strictly ordered set, because a #include #include #include #include #include class MSMetaData { public: class Sequence; explicit MSMetaData(const std::string& path) : _path(path), _isMainTableDataInitialized(false) { initializeOtherData(); } ~MSMetaData(); void SetIntervalStart(size_t index) { _intervalStart = index; } void SetIntervalEnd(size_t index) { _intervalEnd = index; } size_t FrequencyCount(size_t bandIndex) { return _bands[bandIndex].channels.size(); } size_t TimestepCount() { InitializeMainTableData(); return _observationTimes.size(); } size_t TimestepCount(size_t sequenceId) { InitializeMainTableData(); return _observationTimesPerSequence[sequenceId].size(); } size_t PolarizationCount() const { return PolarizationCount(Path()); } static size_t PolarizationCount(const std::string& filename); size_t AntennaCount() const { return _antennas.size(); } size_t BandCount() const { return _bands.size(); } size_t FieldCount() const { return _fields.size(); } static size_t BandCount(const std::string& filename); /** * Get number of sequences. A sequence is a contiguous number of scans * on the same field. Thus, the next sequence starts as soon as the * fieldId changes (possibly to a previous field) */ size_t SequenceCount() { InitializeMainTableData(); return _observationTimesPerSequence.size(); } const AntennaInfo& GetAntennaInfo(unsigned antennaId) const { return _antennas[antennaId]; } const BandInfo& GetBandInfo(unsigned bandIndex) const { return _bands[bandIndex]; } const FieldInfo& GetFieldInfo(unsigned fieldIndex) const { return _fields[fieldIndex]; } void GetDataDescToBandVector(std::vector& dataDescToBand); std::string Path() const { return _path; } /** * Does additional initialization of the metadata. * * Some 'const' versions of the direct getters for the internal vectors * require a call to this function. Otherwise they will return empty * containers. */ void InitializeMainTableData(); void GetBaselines(std::vector>& baselines) { InitializeMainTableData(); baselines = _baselines; } /// @pre InitializeMainTableData is called. const std::vector>& GetBaselines() const { return _baselines; } const std::vector& GetSequences() { InitializeMainTableData(); return _sequences; } /// @pre InitializeMainTableData is called. const std::vector& GetSequences() const { return _sequences; } const std::set& GetObservationTimes() { InitializeMainTableData(); return _observationTimes; } /// @pre InitializeMainTableData is called. const std::set& GetObservationTimes() const { return _observationTimes; } const std::set& GetObservationTimesSet(size_t sequenceId) { InitializeMainTableData(); return _observationTimesPerSequence[sequenceId]; } /// @pre InitializeMainTableData is called. const std::vector>& GetObservationTimesPerSequence() const { return _observationTimesPerSequence; } const std::vector& GetAntennas() const { return _antennas; } const std::vector& GetBands() const { return _bands; } const std::vector& GetFields() const { return _fields; } bool HasAOFlaggerHistory(); void GetAOFlaggerHistory(std::ostream& stream); void AddAOFlaggerHistory(const std::string& strategy, const std::string& commandline); std::string GetStationName() const; bool IsChannelZeroRubish(); class Sequence { public: Sequence(unsigned _antenna1, unsigned _antenna2, unsigned _spw, unsigned _sequenceId, unsigned _fieldId) : antenna1(_antenna1), antenna2(_antenna2), spw(_spw), sequenceId(_sequenceId), fieldId(_fieldId) {} unsigned antenna1, antenna2; unsigned spw; unsigned sequenceId; unsigned fieldId; bool operator<(const Sequence& rhs) const { if (antenna1 < rhs.antenna1) { return true; } else if (antenna1 == rhs.antenna1) { if (antenna2 < rhs.antenna2) { return true; } else if (antenna2 == rhs.antenna2) { if (spw < rhs.spw) { return true; } else if (spw == rhs.spw) { return sequenceId < rhs.sequenceId; } } } return false; } bool operator==(const Sequence& rhs) const { return antenna1 == rhs.antenna1 && antenna2 == rhs.antenna2 && spw == rhs.spw && sequenceId == rhs.sequenceId; } }; static std::string GetTelescopeName(casacore::MeasurementSet& ms); private: void initializeOtherData(); void initializeAntennas(casacore::MeasurementSet& ms); void initializeBands(casacore::MeasurementSet& ms); void initializeFields(casacore::MeasurementSet& ms); const std::string _path; bool _isMainTableDataInitialized; std::vector> _baselines; std::set _observationTimes; std::vector> _observationTimesPerSequence; std::vector _antennas; std::vector _bands; std::vector _fields; std::vector _sequences; std::optional _intervalStart, _intervalEnd; }; #endif aoflagger-v3.4.0/structures/msiterator.cpp0000644000175000017500000000124714507760372017460 0ustar olesoles#include "msiterator.h" MSIterator::MSIterator(const casacore::MeasurementSet& ms, bool hasCorrectedData) : _row(0), _ms(ms), _antenna1Col(_ms, "ANTENNA1"), _antenna2Col(_ms, "ANTENNA2"), _dataCol(_ms, "DATA"), _flagCol(_ms, "FLAG"), _correctedDataCol(hasCorrectedData ? new casacore::ArrayColumn( _ms, "CORRECTED_DATA") : nullptr), _timeCol(_ms, "TIME"), _fieldCol(_ms, "FIELD_ID"), _scanNumberCol(_ms, "SCAN_NUMBER"), _uvwCol(_ms, "UVW"), _windowCol(_ms, "DATA_DESC_ID") {} aoflagger-v3.4.0/structures/spatialmatrixmetadata.h0000644000175000017500000000522214507760372021314 0ustar olesoles#ifndef SPATIALMATRIXMETADATA_H #define SPATIALMATRIXMETADATA_H #include "antennainfo.h" class SpatialMatrixMetaData { public: explicit SpatialMatrixMetaData(size_t antennaCount) : _antennaCount(antennaCount), _antennae(new AntennaInfo[antennaCount]), _uvw(new class UVW*[antennaCount]), _frequency(0.0), _channelIndex(0), _timeIndex(0) { for (size_t i = 0; i < _antennaCount; ++i) _uvw[i] = new class UVW[_antennaCount]; } SpatialMatrixMetaData(const SpatialMatrixMetaData& source) : _antennaCount(source._antennaCount), _antennae(new AntennaInfo[_antennaCount]), _uvw(new class UVW*[_antennaCount]), _frequency(source._frequency), _channelIndex(source._channelIndex), _timeIndex(source._timeIndex) { for (size_t i = 0; i < _antennaCount; ++i) { _uvw[i] = new class UVW[_antennaCount]; _antennae[i] = source._antennae[i]; for (size_t j = 0; j < _antennaCount; ++j) _uvw[i][j] = source._uvw[i][j]; } } ~SpatialMatrixMetaData() { for (size_t i = 0; i < _antennaCount; ++i) delete[] _uvw[i]; delete[] _uvw; delete[] _antennae; } SpatialMatrixMetaData& operator=(const SpatialMatrixMetaData& source) { _antennaCount = source._antennaCount; _antennae = new AntennaInfo[_antennaCount]; _uvw = new class UVW*[_antennaCount]; _frequency = source._frequency; _channelIndex = source._channelIndex; _timeIndex = source._timeIndex; for (size_t i = 0; i < _antennaCount; ++i) { _uvw[i] = new class UVW[_antennaCount]; _antennae[i] = source._antennae[i]; for (size_t j = 0; j < _antennaCount; ++j) _uvw[i][j] = source._uvw[i][j]; } return *this; } void SetAntenna(unsigned index, const AntennaInfo& antenna) { _antennae[index] = antenna; } const AntennaInfo& Antenna(unsigned index) const { return _antennae[index]; } void SetUVW(unsigned a1, unsigned a2, const class UVW& uvw) { _uvw[a2][a1] = uvw; } const class UVW& UVW(unsigned a1, unsigned a2) const { return _uvw[a2][a1]; } size_t AntennaCount() const { return _antennaCount; } void SetFrequency(num_t frequency) { _frequency = frequency; } num_t Frequency() const { return _frequency; } void SetChannelIndex(size_t channelIndex) { _channelIndex = channelIndex; } size_t ChannelIndex() const { return _channelIndex; } void SetTimeIndex(size_t timeIndex) { _timeIndex = timeIndex; } size_t TimeIndex() const { return _timeIndex; } private: size_t _antennaCount; AntennaInfo* _antennae; class UVW** _uvw; num_t _frequency; size_t _channelIndex; size_t _timeIndex; }; #endif // SPATIALMATRIXMETADATA_H aoflagger-v3.4.0/structures/stokesimager.h0000644000175000017500000000163414507760372017431 0ustar olesoles#ifndef STOKESIMAGER_H #define STOKESIMAGER_H #include "image2d.h" class StokesImager { public: static Image2DPtr CreateSum(Image2DCPtr left, Image2DCPtr right); static Image2DPtr CreateDifference(Image2DCPtr left, Image2DCPtr right); static Image2DPtr CreateNegatedSum(Image2DCPtr left, Image2DCPtr right); static Image2DPtr CreateStokesIAmplitude(Image2DCPtr realXX, Image2DCPtr imaginaryXX, Image2DCPtr realYY, Image2DCPtr imaginaryYY); static Image2DPtr CreateStokesI(Image2DCPtr xx, Image2DCPtr yy) { return CreateSum(xx, yy); } static Image2DPtr CreateStokesQ(Image2DCPtr xx, Image2DCPtr yy) { return CreateDifference(xx, yy); } static Image2DPtr CreateAvgPhase(Image2DCPtr xx, Image2DCPtr yy); private: StokesImager() {} ~StokesImager() {} }; #endif aoflagger-v3.4.0/structures/mask2d.h0000644000175000017500000002331314507760372016113 0ustar olesoles#ifndef MASK2D_H #define MASK2D_H #include #include #include #include #include "image2d.h" typedef boost::intrusive_ptr Mask2DPtr; typedef boost::intrusive_ptr Mask2DCPtr; void swap(Mask2D&, Mask2D&); void swap(Mask2D&, Mask2D&&); void swap(Mask2D&&, Mask2D&); class Mask2D : public boost::intrusive_ref_counter { public: Mask2D(); Mask2D(const Mask2D& source); Mask2D(Mask2D&& source) noexcept; ~Mask2D() noexcept; Mask2D& operator=(const Mask2D& rhs); Mask2D& operator=(Mask2D&& rhs) noexcept; bool operator==(const Mask2D& rhs) const { if (_width != rhs._width || _height != rhs._height) return false; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) if (_values[y][x] != rhs._values[y][x]) return false; } return true; } bool operator!=(const Mask2D& rhs) const { return !(*this == rhs); } template static Mask2DPtr MakePtr(Args&&... args) { // This function is to have a generic 'make_' function, that e.g. calls // the more efficient make_shared() when Mask2DPtr is a shared_ptr, but // also works when Mask2DPtr is a boost::intrusive_ptr. return Mask2DPtr(new Mask2D(std::forward(args)...)); } /// Creates mask with uninitialized values. static Mask2D MakeUnsetMask(size_t width, size_t height) { return Mask2D(width, height); } template static Mask2D MakeSetMask(size_t width, size_t height) { Mask2D newMask(width, height); memset(newMask._valuesConsecutive, InitValue, newMask._stride * height * sizeof(bool)); return newMask; } static Mask2D* CreateUnsetMask(size_t width, size_t height) { return new Mask2D(width, height); } static Mask2DPtr CreateUnsetMaskPtr(size_t width, size_t height) { return Mask2DPtr(new Mask2D(width, height)); } static Mask2D* CreateUnsetMask(const class Image2D& templateImage); static Mask2DPtr CreateUnsetMask(Image2DCPtr templateImage) { return Mask2DPtr(CreateUnsetMask(*templateImage)); } template static Mask2D* CreateSetMask(const class Image2D& templateImage); template static Mask2DPtr CreateSetMask(Image2DCPtr templateImage) { return Mask2DPtr(CreateSetMask(*templateImage)); } template static Mask2D* CreateSetMask(size_t width, size_t height) { Mask2D* newMask = new Mask2D(width, height); memset(newMask->_valuesConsecutive, InitValue, newMask->_stride * height * sizeof(bool)); return newMask; } template static Mask2DPtr CreateSetMaskPtr(size_t width, size_t height) { return Mask2DPtr(CreateSetMask(width, height)); } /** * Creates a new mask containing a subset of an existing mask. * * @pre The rows selected to be copied exist in @a source. * * @param source The source mask to copy from. * @param offset The offset of the first row to be copied. * @param count The number of rows to copy. * * @returns The new mask. */ static Mask2DPtr CreatePtrFromRows(const Mask2D& source, size_t offset, size_t count); bool Value(size_t x, size_t y) const { return _values[y][x]; } void SetValue(size_t x, size_t y, bool newValue) { _values[y][x] = newValue; } void SetHorizontalValues(size_t x, size_t y, bool newValue, size_t count) { memset(&_values[y][x], newValue, count * sizeof(bool)); } void SetVerticalValues(size_t x, size_t y, bool newValue, size_t count) { for (size_t i = 0; i != count; ++i) _values[y + i][x] = newValue; } size_t Width() const { return _width; } size_t Height() const { return _height; } bool AllFalse() const { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { if (_values[y][x]) return false; } } return true; } /** * Returns a pointer to one row of data. This can be used to step * quickly over the data in x direction. Note that the next row * is not exactly at "one times width", because the number of * samples in a row is made divisable by four. This makes it * possible to execute SSE instruction easily. * * If you want to skip over a whole row, use the Stride() method * to determine the intrinsicly used width of one row. * * @see Stride() */ bool* ValuePtr(size_t x, size_t y) { return &_values[y][x]; } /** * Returns a constant pointer to one row of data. This can be used to * step quickly over the data in x direction. Note that the next row * is not exactly at "one times width", because the number of * samples in a row is made divisable by four. This makes it * possible to execute SSE instruction easily. * * If you want to skip over a whole row, use the Stride() method * to determine the intrinsicly used width of one row. * * @see Stride() */ const bool* ValuePtr(size_t x, size_t y) const { return &_values[y][x]; } bool* Data() { return _valuesConsecutive; } const bool* Data() const { return _valuesConsecutive; } /** * This value specifies the intrinsic width of one row. It is * normally the first number that is >= Width() and divisable by * four. When using the ValuePtr(unsigned, unsigned) method, * this value can be used to step over one row. * * @see ValuePtr(unsigned, unsigned) */ size_t Stride() const { return _stride; } template void SetAll() { memset(_valuesConsecutive, NewValue, _stride * _height * sizeof(bool)); } template void SetAllVertically(size_t x) { for (size_t y = 0; y < _height; ++y) _values[y][x] = NewValue; } template void SetAllVertically(size_t startX, size_t endX) { for (size_t x = startX; x < endX; ++x) { for (size_t y = 0; y < _height; ++y) _values[y][x] = NewValue; } } template void SetAllHorizontally(size_t y) { memset(_values[y], NewValue, _width * sizeof(bool)); } template void SetAllHorizontally(size_t startY, size_t endY) { memset(_values[startY], BoolValue, _width * sizeof(bool) * (endY - startY)); } void Invert() { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) _values[y][x] = !_values[y][x]; } } /** * Flips the image round the diagonal, i.e., x becomes y and y becomes x. */ Mask2D MakeXYFlipped() const { Mask2D mask(_height, _width); for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) mask._values[x][y] = _values[y][x]; } return mask; } template size_t GetCount() const { size_t count = 0; for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) if (BoolValue == _values[y][x]) ++count; } return count; } Mask2D ShrinkHorizontally(int factor) const; Mask2D ShrinkHorizontallyForAveraging(int factor) const; Mask2D ShrinkVertically(int factor) const; Mask2D ShrinkVerticallyForAveraging(int factor) const; void EnlargeHorizontallyAndSet(const Mask2D& smallMask, int factor); void EnlargeVerticallyAndSet(const Mask2D& smallMask, int factor); void Join(const Mask2D& other) { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) SetValue(x, y, other.Value(x, y) || Value(x, y)); } } void Intersect(const Mask2D& other) { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) SetValue(x, y, other.Value(x, y) && Value(x, y)); } } Mask2D Trim(size_t startX, size_t startY, size_t endX, size_t endY) const { size_t width = endX - startX, height = endY - startY; Mask2D mask(width, height); for (size_t y = startY; y < endY; ++y) { for (size_t x = startX; x < endX; ++x) mask.SetValue(x - startX, y - startY, Value(x, y)); } return mask; } void CopyFrom(const Mask2D& source, size_t destX, size_t destY) { size_t x2 = source._width + destX, y2 = source._height + destY; if (x2 > _width) x2 = _width; if (y2 > _height) y2 = _height; for (size_t y = destY; y < y2; ++y) { for (size_t x = destX; x < x2; ++x) SetValue(x, y, source.Value(x - destX, y - destY)); } } void SwapXY() { Mask2D tempMask(_height, _width); for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) { tempMask.SetValue(y, x, Value(x, y)); } } *this = std::move(tempMask); } std::string ToString() const; private: friend void swap(Mask2D&, Mask2D&); friend void swap(Mask2D&, Mask2D&&); friend void swap(Mask2D&&, Mask2D&); Mask2D(size_t width, size_t height); void allocate(); size_t _width, _height; size_t _stride; bool** _values; bool* _valuesConsecutive; }; inline void swap(Mask2D& left, Mask2D& right) { std::swap(left._width, right._width); std::swap(left._stride, right._stride); std::swap(left._height, right._height); std::swap(left._values, right._values); std::swap(left._valuesConsecutive, right._valuesConsecutive); } inline void swap(Mask2D& left, Mask2D&& right) { std::swap(left._width, right._width); std::swap(left._stride, right._stride); std::swap(left._height, right._height); std::swap(left._values, right._values); std::swap(left._valuesConsecutive, right._valuesConsecutive); } inline void swap(Mask2D&& left, Mask2D& right) { std::swap(left._width, right._width); std::swap(left._stride, right._stride); std::swap(left._height, right._height); std::swap(left._values, right._values); std::swap(left._valuesConsecutive, right._valuesConsecutive); } #endif aoflagger-v3.4.0/structures/segmentedimage.h0000644000175000017500000000605414507760372017713 0ustar olesoles#ifndef SEGMENTEDIMAGE_H #define SEGMENTEDIMAGE_H #include #include typedef std::shared_ptr SegmentedImagePtr; typedef std::shared_ptr SegmentedImageCPtr; class SegmentedImage { public: ~SegmentedImage() { for (size_t y = 0; y < _height; ++y) delete[] _data[y]; delete[] _data; } static SegmentedImage* Create(size_t width, size_t height, size_t initialValue = 0) { SegmentedImage* image = new SegmentedImage(width, height); for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) image->_data[y][x] = initialValue; } return image; } static SegmentedImagePtr CreatePtr(size_t width, size_t height, size_t initialValue = 0) { return SegmentedImagePtr(Create(width, height, initialValue)); } static SegmentedImage* CreateUnset(size_t width, size_t height) { return new SegmentedImage(width, height); } static SegmentedImagePtr CreateUnsetPtr(size_t width, size_t height) { return SegmentedImagePtr(CreateUnset(width, height)); } static SegmentedImagePtr CreateCopy(SegmentedImagePtr segmentedImage) { SegmentedImage* copy = CreateUnset(segmentedImage->_width, segmentedImage->_height); for (size_t y = 0; y < segmentedImage->_height; ++y) { for (size_t x = 0; x < segmentedImage->_width; ++x) { copy->SetValue(x, y, segmentedImage->Value(x, y)); } } copy->_segmentCount = segmentedImage->_segmentCount; return SegmentedImagePtr(copy); } size_t Value(size_t x, size_t y) const { return _data[y][x]; } void SetValue(size_t x, size_t y, size_t newValue) { _data[y][x] = newValue; } size_t Width() const { return _width; } size_t Height() const { return _height; } size_t NewSegmentValue() { ++_segmentCount; return _segmentCount; } size_t SegmentCount() const { return _segmentCount; } void MergeSegments(size_t destinationSegment, size_t otherSegment) { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) if (_data[y][x] == otherSegment) _data[y][x] = destinationSegment; } } void RemoveSegment(size_t segment) { for (size_t y = 0; y < _height; ++y) { for (size_t x = 0; x < _width; ++x) if (_data[y][x] == segment) _data[y][x] = 0; } } void RemoveSegment(size_t segment, size_t xLeft, size_t xRight, size_t yTop, size_t yBottom) { for (size_t y = yTop; y < yBottom; ++y) { for (size_t x = xLeft; x < xRight; ++x) if (_data[y][x] == segment) _data[y][x] = 0; } } private: SegmentedImage(size_t width, size_t height) : _width(width), _height(height), _data(new size_t*[height]), _segmentCount(0) { for (size_t y = 0; y < height; ++y) _data[y] = new size_t[width]; } SegmentedImage(const SegmentedImage&) = delete; SegmentedImage& operator=(const SegmentedImage&) = delete; size_t _width, _height; size_t** _data; size_t _segmentCount; }; #endif aoflagger-v3.4.0/structures/stokesimager.cpp0000644000175000017500000000526014507760372017763 0ustar olesoles#include "stokesimager.h" Image2DPtr StokesImager::CreateStokesIAmplitude(Image2DCPtr realXX, Image2DCPtr imaginaryXX, Image2DCPtr realYY, Image2DCPtr imaginaryYY) { Image2D* stokesI = Image2D::CreateUnsetImage(realXX->Width(), realXX->Height()); for (unsigned long y = 0; y < realXX->Height(); ++y) { for (unsigned long x = 0; x < realXX->Width(); ++x) { const double xx_a = sqrt(realXX->Value(x, y) * realXX->Value(x, y) + imaginaryXX->Value(x, y) * imaginaryXX->Value(x, y)); const double yy_a = sqrt(realYY->Value(x, y) * realYY->Value(x, y) + imaginaryYY->Value(x, y) * imaginaryYY->Value(x, y)); stokesI->SetValue(x, y, xx_a + yy_a); } } return Image2DPtr(stokesI); } Image2DPtr StokesImager::CreateSum(Image2DCPtr left, Image2DCPtr right) { Image2D* sum = Image2D::CreateUnsetImage(left->Width(), right->Height()); for (unsigned long y = 0; y < left->Height(); ++y) { for (unsigned long x = 0; x < right->Width(); ++x) { const num_t left_a = left->Value(x, y); const num_t right_a = right->Value(x, y); sum->SetValue(x, y, left_a + right_a); } } return Image2DPtr(sum); } Image2DPtr StokesImager::CreateNegatedSum(Image2DCPtr left, Image2DCPtr right) { Image2D* sum = Image2D::CreateUnsetImage(left->Width(), right->Height()); for (unsigned long y = 0; y < left->Height(); ++y) { for (unsigned long x = 0; x < right->Width(); ++x) { const num_t left_a = left->Value(x, y); const num_t right_a = right->Value(x, y); sum->SetValue(x, y, -(left_a + right_a)); } } return Image2DPtr(sum); } Image2DPtr StokesImager::CreateDifference(Image2DCPtr left, Image2DCPtr right) { Image2D* difference = Image2D::CreateUnsetImage(left->Width(), right->Height()); for (unsigned long y = 0; y < left->Height(); ++y) { for (unsigned long x = 0; x < right->Width(); ++x) { const num_t left_a = left->Value(x, y); const num_t right_a = right->Value(x, y); difference->SetValue(x, y, left_a - right_a); } } return Image2DPtr(difference); } Image2DPtr StokesImager::CreateAvgPhase(Image2DCPtr xx, Image2DCPtr yy) { Image2D* avgPhase = Image2D::CreateUnsetImage(xx->Width(), xx->Height()); for (unsigned long y = 0; y < xx->Height(); ++y) { for (unsigned long x = 0; x < xx->Width(); ++x) { const double xx_a = xx->Value(x, y); const double yy_a = yy->Value(x, y); avgPhase->SetValue(x, y, fmodn(xx_a + yy_a, 2.0L * M_PIn)); } } return Image2DPtr(avgPhase); } aoflagger-v3.4.0/structures/msrowdataext.h0000644000175000017500000000406514507760372017457 0ustar olesoles#ifndef MS_ROW_DATAEXT_H #define MS_ROW_DATAEXT_H #include "msrowdata.h" #include "../util/serializable.h" class MSRowDataExt : public Serializable { public: MSRowDataExt() = default; MSRowDataExt(unsigned polarizationCount, unsigned channelCount) : _data(polarizationCount, channelCount), _antenna1(), _antenna2(), _timeOffsetIndex(), _u(), _v(), _w(), _time() {} const MSRowData& Data() const { return _data; } MSRowData& Data() { return _data; } unsigned Antenna1() const { return _antenna1; } unsigned Antenna2() const { return _antenna2; } double U() const { return _u; } double V() const { return _v; } double W() const { return _w; } double Time() const { return _time; } size_t TimeOffsetIndex() const { return _timeOffsetIndex; } void SetU(double u) { _u = u; } void SetV(double v) { _v = v; } void SetW(double w) { _w = w; } void SetAntenna1(double antenna1) { _antenna1 = antenna1; } void SetAntenna2(double antenna2) { _antenna2 = antenna2; } void SetTime(double time) { _time = time; } void SetTimeOffsetIndex(size_t timeOffsetIndex) { _timeOffsetIndex = timeOffsetIndex; } virtual void Serialize(std::ostream& stream) const final override { _data.Serialize(stream); SerializeToUInt32(stream, _antenna1); SerializeToUInt32(stream, _antenna2); SerializeToUInt64(stream, _timeOffsetIndex); SerializeToDouble(stream, _u); SerializeToDouble(stream, _v); SerializeToDouble(stream, _w); SerializeToDouble(stream, _time); } virtual void Unserialize(std::istream& stream) final override { _data.Unserialize(stream); _antenna1 = UnserializeUInt32(stream); _antenna2 = UnserializeUInt32(stream); _timeOffsetIndex = UnserializeUInt64(stream); _u = UnserializeDouble(stream); _v = UnserializeDouble(stream); _w = UnserializeDouble(stream); _time = UnserializeDouble(stream); } private: MSRowData _data; unsigned _antenna1, _antenna2; size_t _timeOffsetIndex; double _u, _v, _w; double _time; }; #endif aoflagger-v3.4.0/.gitlab-ci.yml0000644000175000017500000000712114507760372014771 0ustar olesolesstages: - build - test - package - release .dependencies: before_script: - apt-get update -qq - export DEBIAN_FRONTEND=noninteractive && apt-get install -y -qq casacore-data casacore-tools casacore-dev cmake g++ git libblas-dev liblapack-dev libboost-date-time-dev libboost-system-dev libboost-test-dev libcfitsio-dev libfftw3-dev libgsl-dev libgtkmm-3.0-dev libhdf5-serial-dev liblua5.3-dev libpng-dev libpython3-dev libxml2-dev pkg-config python3 python3-dev python3-numpy python3-pip - pip3 install pytest ubuntu20-build: stage: build image: ubuntu:20.04 extends: .dependencies script: - mkdir build - cd build - cmake ../ - make -j`nproc` - make -j`nproc` install - cd python - echo "import aoflagger"|python3 format-ubuntu22: stage: test image: ubuntu:22.04 needs: [] variables: GIT_SUBMODULE_STRATEGY: recursive before_script: - apt-get update -qq - export DEBIAN_FRONTEND=noninteractive && apt-get install -y -qq clang-format-14 python3-pip wget unzip - pip3 install black cmake-format - wget https://github.com/JohnnyMorganz/StyLua/releases/download/v0.15.2/stylua-linux-x86_64.zip - unzip -d /usr/local/bin stylua-linux-x86_64.zip script: - ./scripts/run-format.sh ubuntu20-tests: stage: test image: ubuntu:20.04 extends: .dependencies script: - mkdir build - cd build - cmake -DENABLE_TESTS=ON -DCMAKE_CXX_FLAGS="-coverage" -DCMAKE_EXE_LINKER_FLAGS="-coverage" ../ # Do not install AOFlagger in this job. The tests should still run. - make -j`nproc` all runtests - ctest --output-on-failure artifacts: paths: - build/*.xml reports: junit: build/*.xml # Test whether aoflagger can be build successfully using the latest Ubuntu # release. This version should be updated every 6 months to the then current # release. Even when the latest release is an LTS release the update is useful # since it tests whether the software builds with ninja. ubuntu22-tests: stage: test image: ubuntu:22.04 before_script: - !reference [.dependencies, before_script] - export DEBIAN_FRONTEND=noninteractive && apt-get install -y -qq ninja-build script: - mkdir build - cd build - cmake -DENABLE_TESTS=ON -GNinja ../ - ninja all runtests install - ninja check - ctest --output-on-failure - cd python - echo "import aoflagger"|python3 artifacts: paths: - build/*.xml reports: junit: build/*.xml .packaging: rules: - if: $CI_COMMIT_TAG variables: PACKAGE_FILE: "aoflagger-${CI_COMMIT_TAG}.tbz2" PACKAGE_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/sources/${CI_COMMIT_TAG}/aoflagger-${CI_COMMIT_TAG}.tbz2" package: stage: package extends: .packaging image: ubuntu:20.04 before_script: - apt-get update -qq - export DEBIAN_FRONTEND=noninteractive && apt-get install -y -qq curl git python3-pip - pip3 install git-archive-all script: - | git-archive-all --force-submodules ${PACKAGE_FILE} curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file ${PACKAGE_FILE} ${PACKAGE_URL} release: stage: release extends: .packaging needs: ["package"] image: registry.gitlab.com/gitlab-org/release-cli:latest script: - | release-cli create --name "Release $CI_COMMIT_TAG" --description RELEASE.md \ --assets-link "{\"name\":\"${PACKAGE_FILE}\",\"url\":\"${PACKAGE_URL}\",\"link_type\":\"package\"}" aoflagger-v3.4.0/RELEASE.md0000644000175000017500000000043714507760372013742 0ustar olesoles## About this release (no information yet) ## Downloading releases #### Do not use Source code assets! Please ignore the (automatically generated) "Source code" assets, since they do not include git submodules. Instead, use the file below "Packages", which does include all submodules. aoflagger-v3.4.0/external/0000755000175000017500000000000014516225226014150 5ustar olesolesaoflagger-v3.4.0/external/npy.hpp0000644000175000017500000004312214507760372015477 0ustar olesoles/* Copyright 2017 Leon Merten Lohse Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef NPY_HPP_ #define NPY_HPP_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace npy { /* Compile-time test for byte order. If your compiler does not define these per default, you may want to define one of these constants manually. Defaults to little endian order. */ #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ defined(__BIG_ENDIAN__) || \ defined(__ARMEB__) || \ defined(__THUMBEB__) || \ defined(__AARCH64EB__) || \ defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) const bool big_endian = true; #else const bool big_endian = false; #endif const char magic_string[] = "\x93NUMPY"; const size_t magic_string_length = 6; const char little_endian_char = '<'; const char big_endian_char = '>'; const char no_endian_char = '|'; constexpr std::array endian_chars = {little_endian_char, big_endian_char, no_endian_char}; constexpr std::array numtype_chars = {'f', 'i', 'u', 'c'}; constexpr char host_endian_char = (big_endian ? big_endian_char : little_endian_char); /* npy array length */ typedef unsigned long int ndarray_len_t; typedef std::pair version_t; struct dtype_t { const char byteorder; const char kind; const unsigned int itemsize; // TODO(llohse): implement as constexpr inline std::string str() const { const size_t max_buflen = 16; char buf[max_buflen]; std::snprintf(buf, max_buflen, "%c%c%u", byteorder, kind, itemsize); return std::string(buf); } inline std::tuple tie() const { return std::tie(byteorder, kind, itemsize); } }; struct header_t { const dtype_t dtype; const bool fortran_order; const std::vector shape; }; inline void write_magic(std::ostream &ostream, version_t version) { ostream.write(magic_string, magic_string_length); ostream.put(version.first); ostream.put(version.second); } inline version_t read_magic(std::istream &istream) { char buf[magic_string_length + 2]; istream.read(buf, magic_string_length + 2); if (!istream) { throw std::runtime_error("io error: failed reading file"); } if (0 != std::memcmp(buf, magic_string, magic_string_length)) throw std::runtime_error("this file does not have a valid npy format."); version_t version; version.first = buf[magic_string_length]; version.second = buf[magic_string_length + 1]; return version; } const std::unordered_map dtype_map = { {std::type_index(typeid(float)), {host_endian_char, 'f', sizeof(float)}}, {std::type_index(typeid(double)), {host_endian_char, 'f', sizeof(double)}}, {std::type_index(typeid(long double)), {host_endian_char, 'f', sizeof(long double)}}, {std::type_index(typeid(char)), {no_endian_char, 'i', sizeof(char)}}, {std::type_index(typeid(signed char)), {no_endian_char, 'i', sizeof(signed char)}}, {std::type_index(typeid(short)), {host_endian_char, 'i', sizeof(short)}}, {std::type_index(typeid(int)), {host_endian_char, 'i', sizeof(int)}}, {std::type_index(typeid(long)), {host_endian_char, 'i', sizeof(long)}}, {std::type_index(typeid(long long)), {host_endian_char, 'i', sizeof(long long)}}, {std::type_index(typeid(unsigned char)), {no_endian_char, 'u', sizeof(unsigned char)}}, {std::type_index(typeid(unsigned short)), {host_endian_char, 'u', sizeof(unsigned short)}}, {std::type_index(typeid(unsigned int)), {host_endian_char, 'u', sizeof(unsigned int)}}, {std::type_index(typeid(unsigned long)), {host_endian_char, 'u', sizeof(unsigned long)}}, {std::type_index(typeid(unsigned long long)), {host_endian_char, 'u', sizeof(unsigned long long)}}, {std::type_index(typeid(std::complex)), {host_endian_char, 'c', sizeof(std::complex)}}, {std::type_index(typeid(std::complex)), {host_endian_char, 'c', sizeof(std::complex)}}, {std::type_index(typeid(std::complex)), {host_endian_char, 'c', sizeof(std::complex)}} }; // helpers inline bool is_digits(const std::string &str) { return std::all_of(str.begin(), str.end(), ::isdigit); } template inline bool in_array(T val, const std::array &arr) { return std::find(std::begin(arr), std::end(arr), val) != std::end(arr); } inline dtype_t parse_descr(std::string typestring) { if (typestring.length() < 3) { throw std::runtime_error("invalid typestring (length)"); } char byteorder_c = typestring.at(0); char kind_c = typestring.at(1); std::string itemsize_s = typestring.substr(2); if (!in_array(byteorder_c, endian_chars)) { throw std::runtime_error("invalid typestring (byteorder)"); } if (!in_array(kind_c, numtype_chars)) { throw std::runtime_error("invalid typestring (kind)"); } if (!is_digits(itemsize_s)) { throw std::runtime_error("invalid typestring (itemsize)"); } unsigned int itemsize = std::stoul(itemsize_s); return {byteorder_c, kind_c, itemsize}; } namespace pyparse { /** Removes leading and trailing whitespaces */ inline std::string trim(const std::string &str) { const std::string whitespace = " \t"; auto begin = str.find_first_not_of(whitespace); if (begin == std::string::npos) return ""; auto end = str.find_last_not_of(whitespace); return str.substr(begin, end - begin + 1); } inline std::string get_value_from_map(const std::string &mapstr) { size_t sep_pos = mapstr.find_first_of(":"); if (sep_pos == std::string::npos) return ""; std::string tmp = mapstr.substr(sep_pos + 1); return trim(tmp); } /** Parses the string representation of a Python dict The keys need to be known and may not appear anywhere else in the data. */ inline std::unordered_map parse_dict(std::string in, const std::vector &keys) { std::unordered_map map; if (keys.size() == 0) return map; in = trim(in); // unwrap dictionary if ((in.front() == '{') && (in.back() == '}')) in = in.substr(1, in.length() - 2); else throw std::runtime_error("Not a Python dictionary."); std::vector > positions; for (auto const &value : keys) { size_t pos = in.find("'" + value + "'"); if (pos == std::string::npos) throw std::runtime_error("Missing '" + value + "' key."); std::pair position_pair{pos, value}; positions.push_back(position_pair); } // sort by position in dict std::sort(positions.begin(), positions.end()); for (size_t i = 0; i < positions.size(); ++i) { std::string raw_value; size_t begin{positions[i].first}; size_t end{std::string::npos}; std::string key = positions[i].second; if (i + 1 < positions.size()) end = positions[i + 1].first; raw_value = in.substr(begin, end - begin); raw_value = trim(raw_value); if (raw_value.back() == ',') raw_value.pop_back(); map[key] = get_value_from_map(raw_value); } return map; } /** Parses the string representation of a Python boolean */ inline bool parse_bool(const std::string &in) { if (in == "True") return true; if (in == "False") return false; throw std::runtime_error("Invalid python boolan."); } /** Parses the string representation of a Python str */ inline std::string parse_str(const std::string &in) { if ((in.front() == '\'') && (in.back() == '\'')) return in.substr(1, in.length() - 2); throw std::runtime_error("Invalid python string."); } /** Parses the string represenatation of a Python tuple into a vector of its items */ inline std::vector parse_tuple(std::string in) { std::vector v; const char seperator = ','; in = trim(in); if ((in.front() == '(') && (in.back() == ')')) in = in.substr(1, in.length() - 2); else throw std::runtime_error("Invalid Python tuple."); std::istringstream iss(in); for (std::string token; std::getline(iss, token, seperator);) { v.push_back(token); } return v; } template inline std::string write_tuple(const std::vector &v) { if (v.size() == 0) return "()"; std::ostringstream ss; if (v.size() == 1) { ss << "(" << v.front() << ",)"; } else { const std::string delimiter = ", "; // v.size() > 1 ss << "("; std::copy(v.begin(), v.end() - 1, std::ostream_iterator(ss, delimiter.c_str())); ss << v.back(); ss << ")"; } return ss.str(); } inline std::string write_boolean(bool b) { if (b) return "True"; else return "False"; } } // namespace pyparse inline header_t parse_header(std::string header) { /* The first 6 bytes are a magic string: exactly "x93NUMPY". The next 1 byte is an unsigned byte: the major version number of the file format, e.g. x01. The next 1 byte is an unsigned byte: the minor version number of the file format, e.g. x00. Note: the version of the file format is not tied to the version of the numpy package. The next 2 bytes form a little-endian unsigned short int: the length of the header data HEADER_LEN. The next HEADER_LEN bytes form the header data describing the array's format. It is an ASCII string which contains a Python literal expression of a dictionary. It is terminated by a newline ('n') and padded with spaces ('x20') to make the total length of the magic string + 4 + HEADER_LEN be evenly divisible by 16 for alignment purposes. The dictionary contains three keys: "descr" : dtype.descr An object that can be passed as an argument to the numpy.dtype() constructor to create the array's dtype. "fortran_order" : bool Whether the array data is Fortran-contiguous or not. Since Fortran-contiguous arrays are a common form of non-C-contiguity, we allow them to be written directly to disk for efficiency. "shape" : tuple of int The shape of the array. For repeatability and readability, this dictionary is formatted using pprint.pformat() so the keys are in alphabetic order. */ // remove trailing newline if (header.back() != '\n') throw std::runtime_error("invalid header"); header.pop_back(); // parse the dictionary std::vector keys{"descr", "fortran_order", "shape"}; auto dict_map = npy::pyparse::parse_dict(header, keys); if (dict_map.size() == 0) throw std::runtime_error("invalid dictionary in header"); std::string descr_s = dict_map["descr"]; std::string fortran_s = dict_map["fortran_order"]; std::string shape_s = dict_map["shape"]; std::string descr = npy::pyparse::parse_str(descr_s); dtype_t dtype = parse_descr(descr); // convert literal Python bool to C++ bool bool fortran_order = npy::pyparse::parse_bool(fortran_s); // parse the shape tuple auto shape_v = npy::pyparse::parse_tuple(shape_s); std::vector shape; for (auto item : shape_v) { ndarray_len_t dim = static_cast(std::stoul(item)); shape.push_back(dim); } return {dtype, fortran_order, shape}; } inline std::string write_header_dict(const std::string &descr, bool fortran_order, const std::vector &shape) { std::string s_fortran_order = npy::pyparse::write_boolean(fortran_order); std::string shape_s = npy::pyparse::write_tuple(shape); return "{'descr': '" + descr + "', 'fortran_order': " + s_fortran_order + ", 'shape': " + shape_s + ", }"; } inline void write_header(std::ostream &out, const header_t &header) { std::string header_dict = write_header_dict(header.dtype.str(), header.fortran_order, header.shape); size_t length = magic_string_length + 2 + 2 + header_dict.length() + 1; version_t version{1, 0}; if (length >= 255 * 255) { length = magic_string_length + 2 + 4 + header_dict.length() + 1; version = {2, 0}; } size_t padding_len = 16 - length % 16; std::string padding(padding_len, ' '); // write magic write_magic(out, version); // write header length if (version == version_t{1, 0}) { uint8_t header_len_le16[2]; uint16_t header_len = static_cast(header_dict.length() + padding.length() + 1); header_len_le16[0] = (header_len >> 0) & 0xff; header_len_le16[1] = (header_len >> 8) & 0xff; out.write(reinterpret_cast(header_len_le16), 2); } else { uint8_t header_len_le32[4]; uint32_t header_len = static_cast(header_dict.length() + padding.length() + 1); header_len_le32[0] = (header_len >> 0) & 0xff; header_len_le32[1] = (header_len >> 8) & 0xff; header_len_le32[2] = (header_len >> 16) & 0xff; header_len_le32[3] = (header_len >> 24) & 0xff; out.write(reinterpret_cast(header_len_le32), 4); } out << header_dict << padding << '\n'; } inline std::string read_header(std::istream &istream) { // check magic bytes an version number version_t version = read_magic(istream); uint32_t header_length; if (version == version_t{1, 0}) { uint8_t header_len_le16[2]; istream.read(reinterpret_cast(header_len_le16), 2); header_length = (header_len_le16[0] << 0) | (header_len_le16[1] << 8); if ((magic_string_length + 2 + 2 + header_length) % 16 != 0) { // TODO(llohse): display warning } } else if (version == version_t{2, 0}) { uint8_t header_len_le32[4]; istream.read(reinterpret_cast(header_len_le32), 4); header_length = (header_len_le32[0] << 0) | (header_len_le32[1] << 8) | (header_len_le32[2] << 16) | (header_len_le32[3] << 24); if ((magic_string_length + 2 + 4 + header_length) % 16 != 0) { // TODO(llohse): display warning } } else { throw std::runtime_error("unsupported file format version"); } auto buf_v = std::vector(); buf_v.reserve(header_length); istream.read(buf_v.data(), header_length); std::string header(buf_v.data(), header_length); return header; } inline ndarray_len_t comp_size(const std::vector &shape) { ndarray_len_t size = 1; for (ndarray_len_t i : shape) size *= i; return size; } template inline void SaveArrayAsNumpy(const std::string &filename, bool fortran_order, unsigned int n_dims, const unsigned long shape[], const Scalar* data) { // static_assert(has_typestring::value, "scalar type not understood"); const dtype_t dtype = dtype_map.at(std::type_index(typeid(Scalar))); std::ofstream stream(filename, std::ofstream::binary); if (!stream) { throw std::runtime_error("io error: failed to open a file."); } std::vector shape_v(shape, shape + n_dims); header_t header{dtype, fortran_order, shape_v}; write_header(stream, header); auto size = static_cast(comp_size(shape_v)); stream.write(reinterpret_cast(data), sizeof(Scalar) * size); } template inline void SaveArrayAsNumpy(const std::string &filename, bool fortran_order, unsigned int n_dims, const unsigned long shape[], const std::vector &data) { SaveArrayAsNumpy(filename, fortran_order, n_dims, shape, data.data()); } template inline void LoadArrayFromNumpy(const std::string &filename, std::vector &shape, std::vector &data) { bool fortran_order; LoadArrayFromNumpy(filename, shape, fortran_order, data); } template inline void LoadArrayFromNumpy(const std::string &filename, std::vector &shape, bool &fortran_order, std::vector &data) { std::ifstream stream(filename, std::ifstream::binary); if (!stream) { throw std::runtime_error("io error: failed to open a file."); } std::string header_s = read_header(stream); // parse header header_t header = parse_header(header_s); // check if the typestring matches the given one // static_assert(has_typestring::value, "scalar type not understood"); const dtype_t dtype = dtype_map.at(std::type_index(typeid(Scalar))); if (header.dtype.tie() != dtype.tie()) { throw std::runtime_error("formatting error: typestrings not matching"); } shape = header.shape; fortran_order = header.fortran_order; // compute the data size based on the shape auto size = static_cast(comp_size(shape)); data.resize(size); // read the data stream.read(reinterpret_cast(data.data()), sizeof(Scalar) * size); } } // namespace npy #endif // NPY_HPP_ aoflagger-v3.4.0/external/pybind11/0000755000175000017500000000000014516225226015577 5ustar olesolesaoflagger-v3.4.0/external/pybind11/.github/0000755000175000017500000000000014516225226017137 5ustar olesolesaoflagger-v3.4.0/external/pybind11/.github/ISSUE_TEMPLATE/0000755000175000017500000000000014516225226021322 5ustar olesolesaoflagger-v3.4.0/external/pybind11/.github/ISSUE_TEMPLATE/bug-report.yml0000644000175000017500000000500114507760431024131 0ustar olesolesname: Bug Report description: File an issue about a bug title: "[BUG]: " labels: [triage] body: - type: markdown attributes: value: | Please do your best to make the issue as easy to act on as possible, and only submit here if there is clearly a problem with pybind11 (ask first if unsure). **Note that a reproducer in a PR is much more likely to get immediate attention.** - type: checkboxes id: steps attributes: label: Required prerequisites description: Make sure you've completed the following steps before submitting your issue -- thank you! options: - label: Make sure you've read the [documentation](https://pybind11.readthedocs.io). Your issue may be addressed there. required: true - label: Search the [issue tracker](https://github.com/pybind/pybind11/issues) and [Discussions](https:/pybind/pybind11/discussions) to verify that this hasn't already been reported. +1 or comment there if it has. required: true - label: Consider asking first in the [Gitter chat room](https://gitter.im/pybind/Lobby) or in a [Discussion](https:/pybind/pybind11/discussions/new). required: false - type: input id: version attributes: label: What version (or hash if on master) of pybind11 are you using? validations: required: true - type: textarea id: description attributes: label: Problem description placeholder: >- Provide a short description, state the expected behavior and what actually happens. Include relevant information like what version of pybind11 you are using, what system you are on, and any useful commands / output. validations: required: true - type: textarea id: code attributes: label: Reproducible example code placeholder: >- The code should be minimal, have no external dependencies, isolate the function(s) that cause breakage. Submit matched and complete C++ and Python snippets that can be easily compiled and run to diagnose the issue. — Note that a reproducer in a PR is much more likely to get immediate attention: failing tests in the pybind11 CI are the best starting point for working out fixes. render: text - type: input id: regression attributes: label: Is this a regression? Put the last known working version here if it is. description: Put the last known working version here if this is a regression. value: Not a regression aoflagger-v3.4.0/external/pybind11/.github/ISSUE_TEMPLATE/config.yml0000644000175000017500000000051014507760431023310 0ustar olesolesblank_issues_enabled: false contact_links: - name: Ask a question url: https://github.com/pybind/pybind11/discussions/new about: Please ask and answer questions here, or propose new ideas. - name: Gitter room url: https://gitter.im/pybind/Lobby about: A room for discussing pybind11 with an active community aoflagger-v3.4.0/external/pybind11/.github/matchers/0000755000175000017500000000000014516225226020745 5ustar olesolesaoflagger-v3.4.0/external/pybind11/.github/matchers/pylint.json0000644000175000017500000000123414507760431023161 0ustar olesoles{ "problemMatcher": [ { "severity": "warning", "pattern": [ { "regexp": "^([^:]+):(\\d+):(\\d+): ([A-DF-Z]\\d+): \\033\\[[\\d;]+m([^\\033]+).*$", "file": 1, "line": 2, "column": 3, "code": 4, "message": 5 } ], "owner": "pylint-warning" }, { "severity": "error", "pattern": [ { "regexp": "^([^:]+):(\\d+):(\\d+): (E\\d+): \\033\\[[\\d;]+m([^\\033]+).*$", "file": 1, "line": 2, "column": 3, "code": 4, "message": 5 } ], "owner": "pylint-error" } ] } aoflagger-v3.4.0/external/pybind11/.github/dependabot.yml0000644000175000017500000000024214507760431021767 0ustar olesolesversion: 2 updates: # Maintain dependencies for GitHub Actions - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" aoflagger-v3.4.0/external/pybind11/.github/labeler.yml0000644000175000017500000000016414507760431021273 0ustar olesolesdocs: - any: - 'docs/**/*.rst' - '!docs/changelog.rst' - '!docs/upgrade.rst' ci: - '.github/workflows/*.yml' aoflagger-v3.4.0/external/pybind11/.github/labeler_merged.yml0000644000175000017500000000006214507760431022613 0ustar olesolesneeds changelog: - all: - '!docs/changelog.rst' aoflagger-v3.4.0/external/pybind11/.github/pull_request_template.md0000644000175000017500000000120514507760431024100 0ustar olesoles ## Description ## Suggested changelog entry: ```rst ``` aoflagger-v3.4.0/external/pybind11/.github/CONTRIBUTING.md0000644000175000017500000003566414507760431021410 0ustar olesolesThank you for your interest in this project! Please refer to the following sections on how to contribute code and bug reports. ### Reporting bugs Before submitting a question or bug report, please take a moment of your time and ensure that your issue isn't already discussed in the project documentation provided at [pybind11.readthedocs.org][] or in the [issue tracker][]. You can also check [gitter][] to see if it came up before. Assuming that you have identified a previously unknown problem or an important question, it's essential that you submit a self-contained and minimal piece of code that reproduces the problem. In other words: no external dependencies, isolate the function(s) that cause breakage, submit matched and complete C++ and Python snippets that can be easily compiled and run in isolation; or ideally make a small PR with a failing test case that can be used as a starting point. ## Pull requests Contributions are submitted, reviewed, and accepted using GitHub pull requests. Please refer to [this article][using pull requests] for details and adhere to the following rules to make the process as smooth as possible: * Make a new branch for every feature you're working on. * Make small and clean pull requests that are easy to review but make sure they do add value by themselves. * Add tests for any new functionality and run the test suite (`cmake --build build --target pytest`) to ensure that no existing features break. * Please run [`pre-commit`][pre-commit] to check your code matches the project style. (Note that `gawk` is required.) Use `pre-commit run --all-files` before committing (or use installed-mode, check pre-commit docs) to verify your code passes before pushing to save time. * This project has a strong focus on providing general solutions using a minimal amount of code, thus small pull requests are greatly preferred. ### Licensing of contributions pybind11 is provided under a BSD-style license that can be found in the ``LICENSE`` file. By using, distributing, or contributing to this project, you agree to the terms and conditions of this license. You are under no obligation whatsoever to provide any bug fixes, patches, or upgrades to the features, functionality or performance of the source code ("Enhancements") to anyone; however, if you choose to make your Enhancements available either publicly, or directly to the author of this software, without imposing a separate written license agreement for such Enhancements, then you hereby grant the following license: a non-exclusive, royalty-free perpetual license to install, use, modify, prepare derivative works, incorporate into other computer software, distribute, and sublicense such enhancements or derivative works thereof, in binary and source code form. ## Development of pybind11 ### Quick setup To setup a quick development environment, use [`nox`](https://nox.thea.codes). This will allow you to do some common tasks with minimal setup effort, but will take more time to run and be less flexible than a full development environment. If you use [`pipx run nox`](https://pipx.pypa.io), you don't even need to install `nox`. Examples: ```bash # List all available sessions nox -l # Run linters nox -s lint # Run tests on Python 3.9 nox -s tests-3.9 # Build and preview docs nox -s docs -- serve # Build SDists and wheels nox -s build ``` ### Full setup To setup an ideal development environment, run the following commands on a system with CMake 3.14+: ```bash python3 -m venv venv source venv/bin/activate pip install -r tests/requirements.txt cmake -S . -B build -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON cmake --build build -j4 ``` Tips: * You can use `virtualenv` (faster, from PyPI) instead of `venv`. * You can select any name for your environment folder; if it contains "env" it will be ignored by git. * If you don't have CMake 3.14+, just add "cmake" to the pip install command. * You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+ * In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`. FindPython uses `-DPython_ROOT_DIR=/path/to` or `-DPython_EXECUTABLE=/path/to/python`. ### Configuration options In CMake, configuration options are given with "-D". Options are stored in the build directory, in the `CMakeCache.txt` file, so they are remembered for each build directory. Two selections are special - the generator, given with `-G`, and the compiler, which is selected based on environment variables `CXX` and similar, or `-DCMAKE_CXX_COMPILER=`. Unlike the others, these cannot be changed after the initial run. The valid options are: * `-DCMAKE_BUILD_TYPE`: Release, Debug, MinSizeRel, RelWithDebInfo * `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+'s FindPython instead of the classic, deprecated, custom FindPythonLibs * `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests) * `-DBUILD_TESTING=ON`: Enable the tests * `-DDOWNLOAD_CATCH=ON`: Download catch to build the C++ tests * `-DDOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests * `-DPYBIND11_INSTALL=ON/OFF`: Enable the install target (on by default for the master project) * `-DUSE_PYTHON_INSTALL_DIR=ON`: Try to install into the python dir
A few standard CMake tricks: (click to expand)

* Use `cmake --build build -v` to see the commands used to build the files. * Use `cmake build -LH` to list the CMake options with help. * Use `ccmake` if available to see a curses (terminal) gui, or `cmake-gui` for a completely graphical interface (not present in the PyPI package). * Use `cmake --build build -j12` to build with 12 cores (for example). * Use `-G` and the name of a generator to use something different. `cmake --help` lists the generators available. - On Unix, setting `CMAKE_GENERATER=Ninja` in your environment will give you automatic mulithreading on all your CMake projects! * Open the `CMakeLists.txt` with QtCreator to generate for that IDE. * You can use `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` to generate the `.json` file that some tools expect.

To run the tests, you can "build" the check target: ```bash cmake --build build --target check ``` `--target` can be spelled `-t` in CMake 3.15+. You can also run individual tests with these targets: * `pytest`: Python tests only, using the [pytest](https://docs.pytest.org/en/stable/) framework * `cpptest`: C++ tests only * `test_cmake_build`: Install / subdirectory tests If you want to build just a subset of tests, use `-DPYBIND11_TEST_OVERRIDE="test_callbacks;test_pickling"`. If this is empty, all tests will be built. Tests are specified without an extension if they need both a .py and .cpp file. You may also pass flags to the `pytest` target by editing `tests/pytest.ini` or by using the `PYTEST_ADDOPTS` environment variable (see [`pytest` docs](https://docs.pytest.org/en/2.7.3/customize.html#adding-default-options)). As an example: ```bash env PYTEST_ADDOPTS="--capture=no --exitfirst" \ cmake --build build --target pytest # Or using abbreviated flags env PYTEST_ADDOPTS="-s -x" cmake --build build --target pytest ``` ### Formatting All formatting is handled by pre-commit. Install with brew (macOS) or pip (any OS): ```bash # Any OS python3 -m pip install pre-commit # OR macOS with homebrew: brew install pre-commit ``` Then, you can run it on the items you've added to your staging area, or all files: ```bash pre-commit run # OR pre-commit run --all-files ``` And, if you want to always use it, you can install it as a git hook (hence the name, pre-commit): ```bash pre-commit install ``` ### Clang-Format As of v2.6.2, pybind11 ships with a [`clang-format`][clang-format] configuration file at the top level of the repo (the filename is `.clang-format`). Currently, formatting is NOT applied automatically, but manually using `clang-format` for newly developed files is highly encouraged. To check if a file needs formatting: ```bash clang-format -style=file --dry-run some.cpp ``` The output will show things to be fixed, if any. To actually format the file: ```bash clang-format -style=file -i some.cpp ``` Note that the `-style-file` option searches the parent directories for the `.clang-format` file, i.e. the commands above can be run in any subdirectory of the pybind11 repo. ### Clang-Tidy [`clang-tidy`][clang-tidy] performs deeper static code analyses and is more complex to run, compared to `clang-format`, but support for `clang-tidy` is built into the pybind11 CMake configuration. To run `clang-tidy`, the following recipe should work. Run the `docker` command from the top-level directory inside your pybind11 git clone. Files will be modified in place, so you can use git to monitor the changes. ```bash docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:15-bullseye apt-get update && apt-get install -y git python3-dev python3-pytest cmake -S /mounted_pybind11/ -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--use-color" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17 cmake --build build -j 2 ``` You can add `--fix` to the options list if you want. ### Include what you use To run include what you use, install (`brew install include-what-you-use` on macOS), then run: ```bash cmake -S . -B build-iwyu -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=$(which include-what-you-use) cmake --build build ``` The report is sent to stderr; you can pipe it into a file if you wish. ### Build recipes This builds with the Intel compiler (assuming it is in your path, along with a recent CMake and Python): ```bash python3 -m venv venv . venv/bin/activate pip install pytest cmake -S . -B build-intel -DCMAKE_CXX_COMPILER=$(which icpc) -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DPYBIND11_WERROR=ON ``` This will test the PGI compilers: ```bash docker run --rm -it -v $PWD:/pybind11 nvcr.io/hpc/pgi-compilers:ce apt-get update && apt-get install -y python3-dev python3-pip python3-pytest wget -qO- "https://cmake.org/files/v3.18/cmake-3.18.2-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /usr/local cmake -S pybind11/ -B build cmake --build build ``` ### Explanation of the SDist/wheel building design > These details below are _only_ for packaging the Python sources from git. The > SDists and wheels created do not have any extra requirements at all and are > completely normal. The main objective of the packaging system is to create SDists (Python's source distribution packages) and wheels (Python's binary distribution packages) that include everything that is needed to work with pybind11, and which can be installed without any additional dependencies. This is more complex than it appears: in order to support CMake as a first class language even when using the PyPI package, they must include the _generated_ CMake files (so as not to require CMake when installing the `pybind11` package itself). They should also provide the option to install to the "standard" location (`/include/pybind11` and `/share/cmake/pybind11`) so they are easy to find with CMake, but this can cause problems if you are not an environment or using ``pyproject.toml`` requirements. This was solved by having two packages; the "nice" pybind11 package that stores the includes and CMake files inside the package, that you get access to via functions in the package, and a `pybind11-global` package that can be included via `pybind11[global]` if you want the more invasive but discoverable file locations. If you want to install or package the GitHub source, it is best to have Pip 10 or newer on Windows, macOS, or Linux (manylinux1 compatible, includes most distributions). You can then build the SDists, or run any procedure that makes SDists internally, like making wheels or installing. ```bash # Editable development install example python3 -m pip install -e . ``` Since Pip itself does not have an `sdist` command (it does have `wheel` and `install`), you may want to use the upcoming `build` package: ```bash python3 -m pip install build # Normal package python3 -m build -s . # Global extra PYBIND11_GLOBAL_SDIST=1 python3 -m build -s . ``` If you want to use the classic "direct" usage of `python setup.py`, you will need CMake 3.15+ and either `make` or `ninja` preinstalled (possibly via `pip install cmake ninja`), since directly running Python on `setup.py` cannot pick up and install `pyproject.toml` requirements. As long as you have those two things, though, everything works the way you would expect: ```bash # Normal package python3 setup.py sdist # Global extra PYBIND11_GLOBAL_SDIST=1 python3 setup.py sdist ``` A detailed explanation of the build procedure design for developers wanting to work on or maintain the packaging system is as follows: #### 1. Building from the source directory When you invoke any `setup.py` command from the source directory, including `pip wheel .` and `pip install .`, you will activate a full source build. This is made of the following steps: 1. If the tool is PEP 518 compliant, like Pip 10+, it will create a temporary virtual environment and install the build requirements (mostly CMake) into it. (if you are not on Windows, macOS, or a manylinux compliant system, you can disable this with `--no-build-isolation` as long as you have CMake 3.15+ installed) 2. The environment variable `PYBIND11_GLOBAL_SDIST` is checked - if it is set and truthy, this will be make the accessory `pybind11-global` package, instead of the normal `pybind11` package. This package is used for installing the files directly to your environment root directory, using `pybind11[global]`. 2. `setup.py` reads the version from `pybind11/_version.py` and verifies it matches `includes/pybind11/detail/common.h`. 3. CMake is run with `-DCMAKE_INSTALL_PREIFX=pybind11`. Since the CMake install procedure uses only relative paths and is identical on all platforms, these files are valid as long as they stay in the correct relative position to the includes. `pybind11/share/cmake/pybind11` has the CMake files, and `pybind11/include` has the includes. The build directory is discarded. 4. Simpler files are placed in the SDist: `tools/setup_*.py.in`, `tools/pyproject.toml` (`main` or `global`) 5. The package is created by running the setup function in the `tools/setup_*.py`. `setup_main.py` fills in Python packages, and `setup_global.py` fills in only the data/header slots. 6. A context manager cleans up the temporary CMake install directory (even if an error is thrown). ### 2. Building from SDist Since the SDist has the rendered template files in `tools` along with the includes and CMake files in the correct locations, the builds are completely trivial and simple. No extra requirements are required. You can even use Pip 9 if you really want to. [pre-commit]: https://pre-commit.com [clang-format]: https://clang.llvm.org/docs/ClangFormat.html [clang-tidy]: https://clang.llvm.org/extra/clang-tidy/ [pybind11.readthedocs.org]: http://pybind11.readthedocs.org/en/latest [issue tracker]: https://github.com/pybind/pybind11/issues [gitter]: https://gitter.im/pybind/Lobby [using pull requests]: https://help.github.com/articles/using-pull-requests aoflagger-v3.4.0/external/pybind11/.github/workflows/0000755000175000017500000000000014516225226021174 5ustar olesolesaoflagger-v3.4.0/external/pybind11/.github/workflows/configure.yml0000644000175000017500000000411714507760431023705 0ustar olesolesname: Config on: workflow_dispatch: pull_request: push: branches: - master - stable - v* env: # For cmake: VERBOSE: 1 jobs: # This tests various versions of CMake in various combinations, to make sure # the configure step passes. cmake: strategy: fail-fast: false matrix: runs-on: [ubuntu-20.04, macos-latest, windows-latest] arch: [x64] cmake: ["3.23"] include: - runs-on: ubuntu-20.04 arch: x64 cmake: 3.4 - runs-on: macos-latest arch: x64 cmake: 3.7 - runs-on: windows-2019 arch: x64 # x86 compilers seem to be missing on 2019 image cmake: 3.18 name: ðŸ 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v3 - name: Setup Python 3.7 uses: actions/setup-python@v4 with: python-version: 3.7 architecture: ${{ matrix.arch }} - name: Prepare env run: python -m pip install -r tests/requirements.txt # An action for adding a specific version of CMake: # https://github.com/jwlawson/actions-setup-cmake - name: Setup CMake ${{ matrix.cmake }} uses: jwlawson/actions-setup-cmake@v1.13 with: cmake-version: ${{ matrix.cmake }} # These steps use a directory with a space in it intentionally - name: Make build directories run: mkdir "build dir" - name: Configure working-directory: build dir shell: bash run: > cmake .. -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") # Only build and test if this was manually triggered in the GitHub UI - name: Build working-directory: build dir if: github.event_name == 'workflow_dispatch' run: cmake --build . --config Release - name: Test working-directory: build dir if: github.event_name == 'workflow_dispatch' run: cmake --build . --config Release --target check aoflagger-v3.4.0/external/pybind11/.github/workflows/labeler.yml0000644000175000017500000000105714507760431023332 0ustar olesolesname: Labeler on: pull_request_target: types: [closed] jobs: label: name: Labeler runs-on: ubuntu-latest steps: - uses: actions/labeler@main if: > github.event.pull_request.merged == true && !startsWith(github.event.pull_request.title, 'chore(deps):') && !startsWith(github.event.pull_request.title, 'ci(fix):') && !startsWith(github.event.pull_request.title, 'docs(changelog):') with: repo-token: ${{ secrets.GITHUB_TOKEN }} configuration-path: .github/labeler_merged.yml aoflagger-v3.4.0/external/pybind11/.github/workflows/ci.yml0000644000175000017500000007642714507760431022334 0ustar olesolesname: CI on: workflow_dispatch: pull_request: push: branches: - master - stable - v* concurrency: group: test-${{ github.ref }} cancel-in-progress: true env: PIP_ONLY_BINARY: numpy FORCE_COLOR: 3 PYTEST_TIMEOUT: 300 # For cmake: VERBOSE: 1 jobs: # This is the "main" test suite, which tests a large number of different # versions of default compilers and Python versions in GitHub Actions. standard: strategy: fail-fast: false matrix: runs-on: [ubuntu-20.04, windows-2022, macos-latest] python: - '3.6' - '3.9' - '3.10' - '3.11' - 'pypy-3.7' - 'pypy-3.8' - 'pypy-3.9' # Items in here will either be added to the build matrix (if not # present), or add new keys to an existing matrix element if all the # existing keys match. # # We support an optional key: args, for cmake args include: # Just add a key - runs-on: ubuntu-20.04 python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON -DCMAKE_CXX_FLAGS="-D_=1" - runs-on: ubuntu-20.04 python: 'pypy-3.8' args: > -DPYBIND11_FINDPYTHON=ON - runs-on: windows-2019 python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON # Inject a couple Windows 2019 runs - runs-on: windows-2019 python: '3.9' name: "ðŸ ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}" runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Setup Boost (Linux) # Can't use boost + define _ if: runner.os == 'Linux' && matrix.python != '3.6' run: sudo apt-get install libboost-dev - name: Setup Boost (macOS) if: runner.os == 'macOS' run: brew install boost - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Cache wheels if: runner.os == 'macOS' uses: actions/cache@v3 with: # This path is specific to macOS - we really only need it for PyPy NumPy wheels # See https://github.com/actions/cache/blob/master/examples.md#python---pip # for ways to do this more generally path: ~/Library/Caches/pip # Look to see if there is a cache hit for the corresponding requirements file key: ${{ runner.os }}-pip-${{ matrix.python }}-x64-${{ hashFiles('tests/requirements.txt') }} - name: Prepare env run: | python -m pip install -r tests/requirements.txt - name: Setup annotations on Linux if: runner.os == 'Linux' run: python -m pip install pytest-github-actions-annotate-failures # First build - C++11 mode and inplace # More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here. - name: Configure C++11 ${{ matrix.args }} run: > cmake -S . -B . -DPYBIND11_WERROR=ON -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 ${{ matrix.args }} - name: Build C++11 run: cmake --build . -j 2 - name: Python tests C++11 run: cmake --build . --target pytest -j 2 - name: C++11 tests # TODO: Figure out how to load the DLL on Python 3.8+ if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11' || matrix.python == 'pypy-3.8'))" run: cmake --build . --target cpptest -j 2 - name: Interface test C++11 run: cmake --build . --target test_cmake_build - name: Clean directory run: git clean -fdx # Second build - C++17 mode and in a build directory # More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF here. - name: Configure C++17 run: > cmake -S . -B build2 -DPYBIND11_WERROR=ON -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 ${{ matrix.args }} - name: Build run: cmake --build build2 -j 2 - name: Python tests run: cmake --build build2 --target pytest - name: C++ tests # TODO: Figure out how to load the DLL on Python 3.8+ if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11' || matrix.python == 'pypy-3.8'))" run: cmake --build build2 --target cpptest # Third build - C++17 mode with unstable ABI - name: Configure (unstable ABI) run: > cmake -S . -B build3 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 -DPYBIND11_INTERNALS_VERSION=10000000 "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" ${{ matrix.args }} - name: Build (unstable ABI) run: cmake --build build3 -j 2 - name: Python tests (unstable ABI) run: cmake --build build3 --target pytest - name: Interface test run: cmake --build build2 --target test_cmake_build # This makes sure the setup_helpers module can build packages using # setuptools - name: Setuptools helpers test run: pytest tests/extra_setuptools if: "!(matrix.runs-on == 'windows-2022')" deadsnakes: strategy: fail-fast: false matrix: include: # TODO: Fails on 3.10, investigate - python-version: "3.9" python-debug: true valgrind: true - python-version: "3.11" python-debug: false name: "ðŸ ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64" runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python-version }} (deadsnakes) uses: deadsnakes/action@v3.0.0 with: python-version: ${{ matrix.python-version }} debug: ${{ matrix.python-debug }} - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Valgrind cache if: matrix.valgrind uses: actions/cache@v3 id: cache-valgrind with: path: valgrind key: 3.16.1 # Valgrind version - name: Compile Valgrind if: matrix.valgrind && steps.cache-valgrind.outputs.cache-hit != 'true' run: | VALGRIND_VERSION=3.16.1 curl https://sourceware.org/pub/valgrind/valgrind-$VALGRIND_VERSION.tar.bz2 -o - | tar xj mv valgrind-$VALGRIND_VERSION valgrind cd valgrind ./configure make -j 2 > /dev/null - name: Install Valgrind if: matrix.valgrind working-directory: valgrind run: | sudo make install sudo apt-get update sudo apt-get install libc6-dbg # Needed by Valgrind - name: Prepare env run: | python -m pip install -r tests/requirements.txt - name: Configure env: SETUPTOOLS_USE_DISTUTILS: stdlib run: > cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 - name: Build run: cmake --build build -j 2 - name: Python tests run: cmake --build build --target pytest - name: C++ tests run: cmake --build build --target cpptest - name: Run Valgrind on Python tests if: matrix.valgrind run: cmake --build build --target memcheck # Testing on clang using the excellent silkeh clang docker images clang: runs-on: ubuntu-latest strategy: fail-fast: false matrix: clang: - 3.6 - 3.7 - 3.9 - 7 - 9 - dev std: - 11 container_suffix: - "" include: - clang: 5 std: 14 - clang: 10 std: 17 - clang: 11 std: 20 - clang: 12 std: 20 - clang: 13 std: 20 - clang: 14 std: 20 - clang: 15 std: 20 container_suffix: "-bullseye" name: "ðŸ 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64" container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}" steps: - uses: actions/checkout@v3 - name: Add wget and python3 run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev - name: Configure shell: bash run: > cmake -S . -B build -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build run: cmake --build build -j 2 - name: Python tests run: cmake --build build --target pytest - name: C++ tests run: cmake --build build --target cpptest - name: Interface test run: cmake --build build --target test_cmake_build # Testing NVCC; forces sources to behave like .cu files cuda: runs-on: ubuntu-latest name: "ðŸ 3.10 • CUDA 11.7 • Ubuntu 22.04" container: nvidia/cuda:11.7.0-devel-ubuntu22.04 steps: - uses: actions/checkout@v3 # tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND - name: Install ðŸ 3 run: apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y cmake git python3-dev python3-pytest python3-numpy - name: Configure run: cmake -S . -B build -DPYBIND11_CUDA_TESTS=ON -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON - name: Build run: cmake --build build -j2 --verbose - name: Python tests run: cmake --build build --target pytest # TODO: Internal compiler error - report to NVidia # # Testing CentOS 8 + PGI compilers # centos-nvhpc8: # runs-on: ubuntu-latest # name: "ðŸ 3 • CentOS8 / PGI 20.11 • x64" # container: centos:8 # # steps: # - uses: actions/checkout@v3 # # - name: Add Python 3 and a few requirements # run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules # # - name: Install CMake with pip # run: | # python3 -m pip install --upgrade pip # python3 -m pip install cmake --prefer-binary # # - name: Install NVidia HPC SDK # run: > # yum -y install # https://developer.download.nvidia.com/hpc-sdk/20.11/nvhpc-20-11-20.11-1.x86_64.rpm # https://developer.download.nvidia.com/hpc-sdk/20.11/nvhpc-2020-20.11-1.x86_64.rpm # # - name: Configure # shell: bash # run: | # source /etc/profile.d/modules.sh # module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/20.11 # cmake -S . -B build -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=14 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") # # - name: Build # run: cmake --build build -j 2 --verbose # # - name: Python tests # run: cmake --build build --target pytest # # - name: C++ tests # run: cmake --build build --target cpptest # # - name: Interface test # run: cmake --build build --target test_cmake_build # Testing on CentOS 7 + PGI compilers, which seems to require more workarounds centos-nvhpc7: runs-on: ubuntu-latest name: "ðŸ 3 • CentOS7 / PGI 22.9 • x64" container: centos:7 steps: - uses: actions/checkout@v3 - name: Add Python 3 and a few requirements run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3 yum-utils - name: Install NVidia HPC SDK run: yum-config-manager --add-repo https://developer.download.nvidia.com/hpc-sdk/rhel/nvhpc.repo && yum -y install nvhpc-22.9 # On CentOS 7, we have to filter a few tests (compiler internal error) # and allow deeper template recursion (not needed on CentOS 8 with a newer # standard library). On some systems, you many need further workarounds: # https://github.com/pybind/pybind11/pull/2475 - name: Configure shell: bash run: | source /etc/profile.d/modules.sh module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/22.9 cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \ -DCMAKE_CXX_STANDARD=11 \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \ -DCMAKE_CXX_FLAGS="-Wc,--pending_instantiations=0" \ -DPYBIND11_TEST_FILTER="test_smart_ptr.cpp" # Building before installing Pip should produce a warning but not an error - name: Build run: cmake3 --build build -j 2 --verbose - name: Install CMake with pip run: | python3 -m pip install --upgrade pip python3 -m pip install pytest - name: Python tests run: cmake3 --build build --target pytest - name: C++ tests run: cmake3 --build build --target cpptest - name: Interface test run: cmake3 --build build --target test_cmake_build # Testing on GCC using the GCC docker images (only recent images supported) gcc: runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - { gcc: 7, std: 11 } - { gcc: 7, std: 17 } - { gcc: 8, std: 14 } - { gcc: 8, std: 17 } - { gcc: 10, std: 17 } - { gcc: 11, std: 20 } - { gcc: 12, std: 20 } name: "ðŸ 3 • GCC ${{ matrix.gcc }} • C++${{ matrix.std }}• x64" container: "gcc:${{ matrix.gcc }}" steps: - uses: actions/checkout@v3 - name: Add Python 3 run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev - name: Update pip run: python3 -m pip install --upgrade pip - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Configure shell: bash run: > cmake -S . -B build -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build run: cmake --build build -j 2 - name: Python tests run: cmake --build build --target pytest - name: C++ tests run: cmake --build build --target cpptest - name: Interface test run: cmake --build build --target test_cmake_build # Testing on ICC using the oneAPI apt repo icc: runs-on: ubuntu-20.04 strategy: fail-fast: false name: "ðŸ 3 • ICC latest • x64" steps: - uses: actions/checkout@v3 - name: Add apt repo run: | sudo apt-get update sudo apt-get install -y wget build-essential pkg-config cmake ca-certificates gnupg wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list - name: Add ICC & Python 3 run: sudo apt-get update; sudo apt-get install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic cmake python3-dev python3-numpy python3-pytest python3-pip - name: Update pip run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e python3 -m pip install --upgrade pip - name: Install dependencies run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e python3 -m pip install -r tests/requirements.txt - name: Configure C++11 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake -S . -B build-11 \ -DPYBIND11_WERROR=ON \ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=11 \ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build C++11 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-11 -j 2 -v - name: Python tests C++11 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e sudo service apport stop cmake --build build-11 --target check - name: C++ tests C++11 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-11 --target cpptest - name: Interface test C++11 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-11 --target test_cmake_build - name: Configure C++17 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake -S . -B build-17 \ -DPYBIND11_WERROR=ON \ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build C++17 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-17 -j 2 -v - name: Python tests C++17 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e sudo service apport stop cmake --build build-17 --target check - name: C++ tests C++17 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-17 --target cpptest - name: Interface test C++17 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-17 --target test_cmake_build # Testing on CentOS (manylinux uses a centos base, and this is an easy way # to get GCC 4.8, which is the manylinux1 compiler). centos: runs-on: ubuntu-latest strategy: fail-fast: false matrix: container: - "centos:7" # GCC 4.8 - "almalinux:8" - "almalinux:9" name: "ðŸ 3 • ${{ matrix.container }} • x64" container: "${{ matrix.container }}" steps: - uses: actions/checkout@v3 - name: Add Python 3 (RHEL 7) if: matrix.container == 'centos:7' run: yum update -y && yum install -y python3-devel gcc-c++ make git - name: Add Python 3 (RHEL 8+) if: matrix.container != 'centos:7' run: dnf update -y && dnf install -y python3-devel gcc-c++ make git - name: Update pip run: python3 -m pip install --upgrade pip - name: Install dependencies run: | python3 -m pip install cmake -r tests/requirements.txt - name: Configure shell: bash run: > cmake -S . -B build -DCMAKE_BUILD_TYPE=MinSizeRel -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build run: cmake --build build -j 2 - name: Python tests run: cmake --build build --target pytest - name: C++ tests run: cmake --build build --target cpptest - name: Interface test run: cmake --build build --target test_cmake_build # This tests an "install" with the CMake tools install-classic: name: "ðŸ 3.7 • Debian • x86 • Install" runs-on: ubuntu-latest container: i386/debian:buster steps: - uses: actions/checkout@v1 # Required to run inside docker - name: Install requirements run: | apt-get update apt-get install -y git make cmake g++ libeigen3-dev python3-dev python3-pip pip3 install "pytest==6.*" - name: Configure for install run: > cmake . -DPYBIND11_INSTALL=1 -DPYBIND11_TEST=0 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Make and install run: make install - name: Copy tests to new directory run: cp -a tests /pybind11-tests - name: Make a new test directory run: mkdir /build-tests - name: Configure tests run: > cmake ../pybind11-tests -DDOWNLOAD_CATCH=ON -DPYBIND11_WERROR=ON -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") working-directory: /build-tests - name: Python tests run: make pytest -j 2 working-directory: /build-tests # This verifies that the documentation is not horribly broken, and does a # basic validation check on the SDist. doxygen: name: "Documentation build test" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.x" - name: Install Doxygen run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04 - name: Build docs run: pipx run nox -s docs - name: Make SDist run: pipx run nox -s build -- --sdist - run: git status --ignored - name: Check local include dir run: > ls pybind11; python3 -c "import pybind11, pathlib; assert (a := pybind11.get_include()) == (b := str(pathlib.Path('include').resolve())), f'{a} != {b}'" - name: Compare Dists (headers only) working-directory: include run: | python3 -m pip install --user -U ../dist/*.tar.gz installed=$(python3 -c "import pybind11; print(pybind11.get_include() + '/pybind11')") diff -rq $installed ./pybind11 win32: strategy: fail-fast: false matrix: python: - 3.6 - 3.7 - 3.8 - 3.9 include: - python: 3.9 args: -DCMAKE_CXX_STANDARD=20 - python: 3.8 args: -DCMAKE_CXX_STANDARD=17 - python: 3.7 args: -DCMAKE_CXX_STANDARD=14 name: "ðŸ ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}" runs-on: windows-2019 steps: - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} architecture: x86 - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare MSVC uses: ilammy/msvc-dev-cmd@v1.12.1 with: arch: x86 - name: Prepare env run: | python -m pip install -r tests/requirements.txt # First build - C++11 mode and inplace - name: Configure ${{ matrix.args }} run: > cmake -S . -B build -G "Visual Studio 16 2019" -A Win32 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON ${{ matrix.args }} - name: Build C++11 run: cmake --build build -j 2 - name: Python tests run: cmake --build build -t pytest win32-debug: strategy: fail-fast: false matrix: python: - 3.8 - 3.9 include: - python: 3.9 args: -DCMAKE_CXX_STANDARD=20 - python: 3.8 args: -DCMAKE_CXX_STANDARD=17 name: "ðŸ ${{ matrix.python }} • MSVC 2019 (Debug) • x86 ${{ matrix.args }}" runs-on: windows-2019 steps: - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} architecture: x86 - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare MSVC uses: ilammy/msvc-dev-cmd@v1.12.1 with: arch: x86 - name: Prepare env run: | python -m pip install -r tests/requirements.txt # First build - C++11 mode and inplace - name: Configure ${{ matrix.args }} run: > cmake -S . -B build -G "Visual Studio 16 2019" -A Win32 -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON ${{ matrix.args }} - name: Build C++11 run: cmake --build build --config Debug -j 2 - name: Python tests run: cmake --build build --config Debug -t pytest windows-2022: strategy: fail-fast: false matrix: python: - 3.9 name: "ðŸ ${{ matrix.python }} • MSVC 2022 C++20 • x64" runs-on: windows-2022 steps: - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Prepare env run: | python3 -m pip install -r tests/requirements.txt - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Configure C++20 run: > cmake -S . -B build -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=20 - name: Build C++20 run: cmake --build build -j 2 - name: Python tests run: cmake --build build --target pytest - name: C++20 tests run: cmake --build build --target cpptest -j 2 - name: Interface test C++20 run: cmake --build build --target test_cmake_build mingw: name: "ðŸ 3 • windows-latest • ${{ matrix.sys }}" runs-on: windows-latest defaults: run: shell: msys2 {0} strategy: fail-fast: false matrix: include: - { sys: mingw64, env: x86_64 } - { sys: mingw32, env: i686 } steps: - uses: msys2/setup-msys2@v2 with: msystem: ${{matrix.sys}} install: >- git mingw-w64-${{matrix.env}}-gcc mingw-w64-${{matrix.env}}-python-pip mingw-w64-${{matrix.env}}-python-numpy mingw-w64-${{matrix.env}}-python-scipy mingw-w64-${{matrix.env}}-cmake mingw-w64-${{matrix.env}}-make mingw-w64-${{matrix.env}}-python-pytest mingw-w64-${{matrix.env}}-eigen3 mingw-w64-${{matrix.env}}-boost mingw-w64-${{matrix.env}}-catch - uses: actions/checkout@v3 - name: Configure C++11 # LTO leads to many undefined reference like # `pybind11::detail::function_call::function_call(pybind11::detail::function_call&&) run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build - name: Build C++11 run: cmake --build build -j 2 - name: Python tests C++11 run: cmake --build build --target pytest -j 2 - name: C++11 tests run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target cpptest -j 2 - name: Interface test C++11 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_cmake_build - name: Clean directory run: git clean -fdx - name: Configure C++14 run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build2 - name: Build C++14 run: cmake --build build2 -j 2 - name: Python tests C++14 run: cmake --build build2 --target pytest -j 2 - name: C++14 tests run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target cpptest -j 2 - name: Interface test C++14 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_cmake_build - name: Clean directory run: git clean -fdx - name: Configure C++17 run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build3 - name: Build C++17 run: cmake --build build3 -j 2 - name: Python tests C++17 run: cmake --build build3 --target pytest -j 2 - name: C++17 tests run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target cpptest -j 2 - name: Interface test C++17 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cmake_build windows_clang: strategy: matrix: os: [windows-latest] python: ['3.10'] runs-on: "${{ matrix.os }}" name: "ðŸ ${{ matrix.python }} • ${{ matrix.os }} • clang-latest" steps: - name: Show env run: env - name: Checkout uses: actions/checkout@v3 - name: Set up Clang uses: egor-tensin/setup-clang@v1 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Install ninja-build tool uses: seanmiddleditch/gha-setup-ninja@v3 - name: Run pip installs run: | python -m pip install --upgrade pip python -m pip install -r tests/requirements.txt - name: Show Clang++ version run: clang++ --version - name: Show CMake version run: cmake --version # TODO: WERROR=ON - name: Configure Clang run: > cmake -G Ninja -S . -B . -DPYBIND11_WERROR=OFF -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 - name: Build run: cmake --build . -j 2 - name: Python tests run: cmake --build . --target pytest -j 2 - name: C++ tests run: cmake --build . --target cpptest -j 2 - name: Interface test run: cmake --build . --target test_cmake_build -j 2 - name: Clean directory run: git clean -fdx macos_brew_install_llvm: name: "macos-latest • brew install llvm" runs-on: macos-latest env: # https://apple.stackexchange.com/questions/227026/how-to-install-recent-clang-with-homebrew LDFLAGS: '-L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib' steps: - name: Update PATH run: echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH - name: Show env run: env - name: Checkout uses: actions/checkout@v3 - name: Show Clang++ version before brew install llvm run: clang++ --version - name: brew install llvm run: brew install llvm - name: Show Clang++ version after brew install llvm run: clang++ --version - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Run pip installs run: | python3 -m pip install --upgrade pip python3 -m pip install -r tests/requirements.txt python3 -m pip install numpy python3 -m pip install scipy - name: Show CMake version run: cmake --version - name: CMake Configure run: > cmake -S . -B . -DPYBIND11_WERROR=ON -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build run: cmake --build . -j 2 - name: Python tests run: cmake --build . --target pytest -j 2 - name: C++ tests run: cmake --build . --target cpptest -j 2 - name: Interface test run: cmake --build . --target test_cmake_build -j 2 - name: Clean directory run: git clean -fdx aoflagger-v3.4.0/external/pybind11/.github/workflows/upstream.yml0000644000175000017500000000546114507760431023567 0ustar olesoles name: Upstream on: workflow_dispatch: pull_request: concurrency: group: upstream-${{ github.ref }} cancel-in-progress: true env: PIP_ONLY_BINARY: numpy # For cmake: VERBOSE: 1 jobs: standard: name: "ðŸ 3.11 latest internals • ubuntu-latest • x64" runs-on: ubuntu-latest if: "contains(github.event.pull_request.labels.*.name, 'python dev')" steps: - uses: actions/checkout@v3 - name: Setup Python 3.11 uses: actions/setup-python@v4 with: python-version: "3.11-dev" - name: Setup Boost (Linux) if: runner.os == 'Linux' run: sudo apt-get install libboost-dev - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare env run: | python -m pip install -r tests/requirements.txt - name: Setup annotations on Linux if: runner.os == 'Linux' run: python -m pip install pytest-github-actions-annotate-failures # First build - C++11 mode and inplace - name: Configure C++11 run: > cmake -S . -B . -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 - name: Build C++11 run: cmake --build . -j 2 - name: Python tests C++11 run: cmake --build . --target pytest -j 2 - name: C++11 tests run: cmake --build . --target cpptest -j 2 - name: Interface test C++11 run: cmake --build . --target test_cmake_build - name: Clean directory run: git clean -fdx # Second build - C++17 mode and in a build directory - name: Configure C++17 run: > cmake -S . -B build2 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 ${{ matrix.args }} ${{ matrix.args2 }} - name: Build run: cmake --build build2 -j 2 - name: Python tests run: cmake --build build2 --target pytest - name: C++ tests run: cmake --build build2 --target cpptest # Third build - C++17 mode with unstable ABI - name: Configure (unstable ABI) run: > cmake -S . -B build3 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 -DPYBIND11_INTERNALS_VERSION=10000000 "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" ${{ matrix.args }} - name: Build (unstable ABI) run: cmake --build build3 -j 2 - name: Python tests (unstable ABI) run: cmake --build build3 --target pytest - name: Interface test run: cmake --build build3 --target test_cmake_build # This makes sure the setup_helpers module can build packages using # setuptools - name: Setuptools helpers test run: pytest tests/extra_setuptools aoflagger-v3.4.0/external/pybind11/.github/workflows/format.yml0000644000175000017500000000266414507760431023221 0ustar olesoles# This is a format job. Pre-commit has a first-party GitHub action, so we use # that: https://github.com/pre-commit/action name: Format on: workflow_dispatch: pull_request: push: branches: - master - stable - "v*" env: FORCE_COLOR: 3 # For cmake: VERBOSE: 1 jobs: pre-commit: name: Format runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.x" - name: Add matchers run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json" - uses: pre-commit/action@v3.0.0 with: # Slow hooks are marked with manual - slow is okay here, run them too extra_args: --hook-stage manual --all-files clang-tidy: # When making changes here, please also review the "Clang-Tidy" section # in .github/CONTRIBUTING.md and update as needed. name: Clang-Tidy runs-on: ubuntu-latest container: silkeh/clang:15-bullseye steps: - uses: actions/checkout@v3 - name: Install requirements run: apt-get update && apt-get install -y git python3-dev python3-pytest - name: Configure run: > cmake -S . -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--use-color;--warnings-as-errors=*" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17 - name: Build run: cmake --build build -j 2 -- --keep-going aoflagger-v3.4.0/external/pybind11/.github/workflows/pip.yml0000644000175000017500000000477614507760431022527 0ustar olesolesname: Pip on: workflow_dispatch: pull_request: push: branches: - master - stable - v* release: types: - published env: PIP_ONLY_BINARY: numpy jobs: # This builds the sdists and wheels and makes sure the files are exactly as # expected. Using Windows and Python 3.6, since that is often the most # challenging matrix element. test-packaging: name: ðŸ 3.6 • 📦 tests • windows-latest runs-on: windows-latest steps: - uses: actions/checkout@v3 - name: Setup ðŸ 3.6 uses: actions/setup-python@v4 with: python-version: 3.6 - name: Prepare env run: | python -m pip install -r tests/requirements.txt - name: Python Packaging tests run: pytest tests/extra_python_package/ # This runs the packaging tests and also builds and saves the packages as # artifacts. packaging: name: ðŸ 3.8 • 📦 & 📦 tests • ubuntu-latest runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup ðŸ 3.8 uses: actions/setup-python@v4 with: python-version: 3.8 - name: Prepare env run: | python -m pip install -r tests/requirements.txt build twine - name: Python Packaging tests run: pytest tests/extra_python_package/ - name: Build SDist and wheels run: | python -m build PYBIND11_GLOBAL_SDIST=1 python -m build - name: Check metadata run: twine check dist/* - name: Save standard package uses: actions/upload-artifact@v3 with: name: standard path: dist/pybind11-* - name: Save global package uses: actions/upload-artifact@v3 with: name: global path: dist/pybind11_global-* # When a GitHub release is made, upload the artifacts to PyPI upload: name: Upload to PyPI runs-on: ubuntu-latest if: github.event_name == 'release' && github.event.action == 'published' needs: [packaging] steps: - uses: actions/setup-python@v4 with: python-version: "3.x" # Downloads all to directories matching the artifact names - uses: actions/download-artifact@v3 - name: Publish standard package uses: pypa/gh-action-pypi-publish@v1.6.4 with: password: ${{ secrets.pypi_password }} packages_dir: standard/ - name: Publish global package uses: pypa/gh-action-pypi-publish@v1.6.4 with: password: ${{ secrets.pypi_password_global }} packages_dir: global/ aoflagger-v3.4.0/external/pybind11/.github/CODEOWNERS0000644000175000017500000000026614507760431020540 0ustar olesoles*.cmake @henryiii CMakeLists.txt @henryiii *.yml @henryiii *.yaml @henryiii /tools/ @henryiii /pybind11/ @henryiii noxfile.py @henryiii .clang-format @henryiii .clang-tidy @henryiii aoflagger-v3.4.0/external/pybind11/README.rst0000644000175000017500000001700614507760431017274 0ustar olesoles.. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png :alt: pybind11 logo **pybind11 — Seamless operability between C++11 and Python** |Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions| |CI| |Build status| |Repology| |PyPI package| |Conda-forge| |Python Versions| `Setuptools example `_ • `Scikit-build example `_ • `CMake example `_ .. start **pybind11** is a lightweight header-only library that exposes C++ types in Python and vice versa, mainly to create Python bindings of existing C++ code. Its goals and syntax are similar to the excellent `Boost.Python `_ library by David Abrahams: to minimize boilerplate code in traditional extension modules by inferring type information using compile-time introspection. The main issue with Boost.Python—and the reason for creating such a similar project—is Boost. Boost is an enormously large and complex suite of utility libraries that works with almost every C++ compiler in existence. This compatibility has its cost: arcane template tricks and workarounds are necessary to support the oldest and buggiest of compiler specimens. Now that C++11-compatible compilers are widely available, this heavy machinery has become an excessively large and unnecessary dependency. Think of this library as a tiny self-contained version of Boost.Python with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K lines of code and depend on Python (3.6+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to some of the new C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has grown beyond Boost.Python in many ways, leading to dramatically simpler binding code in many common situations. Tutorial and reference documentation is provided at `pybind11.readthedocs.io `_. A PDF version of the manual is available `here `_. And the source code is always available at `github.com/pybind/pybind11 `_. Core features ------------- pybind11 can map the following core C++ features to Python: - Functions accepting and returning custom data structures per value, reference, or pointer - Instance methods and static methods - Overloaded functions - Instance attributes and static attributes - Arbitrary exception types - Enumerations - Callbacks - Iterators and ranges - Custom operators - Single and multiple inheritance - STL data structures - Smart pointers with reference counting like ``std::shared_ptr`` - Internal references with correct reference counting - C++ classes with virtual (and pure virtual) methods can be extended in Python Goodies ------- In addition to the core functionality, pybind11 provides some extra goodies: - Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic interface (pybind11 2.9 was the last version to support Python 2 and 3.5). - It is possible to bind C++11 lambda functions with captured variables. The lambda capture data is stored inside the resulting Python function object. - pybind11 uses C++11 move constructors and move assignment operators whenever possible to efficiently transfer custom data types. - It's easy to expose the internal storage of custom data types through Pythons' buffer protocols. This is handy e.g. for fast conversion between C++ matrix classes like Eigen and NumPy without expensive copy operations. - pybind11 can automatically vectorize functions so that they are transparently applied to all entries of one or more NumPy array arguments. - Python's slice-based access and assignment operations can be supported with just a few lines of code. - Everything is contained in just a few header files; there is no need to link against any additional libraries. - Binaries are generally smaller by a factor of at least 2 compared to equivalent bindings generated by Boost.Python. A recent pybind11 conversion of PyRosetta, an enormous Boost.Python binding project, `reported `_ a binary size reduction of **5.4x** and compile time reduction by **5.8x**. - Function signatures are precomputed at compile time (using ``constexpr``), leading to smaller binaries. - With little extra effort, C++ types can be pickled and unpickled similar to regular Python objects. Supported compilers ------------------- 1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer) 2. GCC 4.8 or newer 3. Microsoft Visual Studio 2017 or newer 4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI) 5. Cygwin/GCC (previously tested on 2.5.1) 6. NVCC (CUDA 11.0 tested in CI) 7. NVIDIA PGI (20.9 tested in CI) About ----- This project was created by `Wenzel Jakob `_. Significant features and/or improvements to the code were contributed by Jonas Adler, Lori A. Burns, Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov Johan Mabille, Tomasz MiÄ…sko, Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart. We thank Google for a generous financial contribution to the continuous integration infrastructure used by this project. Contributing ~~~~~~~~~~~~ See the `contributing guide `_ for information on building and contributing to pybind11. License ~~~~~~~ pybind11 is provided under a BSD-style license that can be found in the `LICENSE `_ file. By using, distributing, or contributing to this project, you agree to the terms and conditions of this license. .. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest :target: http://pybind11.readthedocs.org/en/latest .. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue.svg :target: http://pybind11.readthedocs.org/en/stable .. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg :target: https://gitter.im/pybind/Lobby .. |CI| image:: https://github.com/pybind/pybind11/workflows/CI/badge.svg :target: https://github.com/pybind/pybind11/actions .. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true :target: https://ci.appveyor.com/project/wjakob/pybind11 .. |PyPI package| image:: https://img.shields.io/pypi/v/pybind11.svg :target: https://pypi.org/project/pybind11/ .. |Conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pybind11.svg :target: https://github.com/conda-forge/pybind11-feedstock .. |Repology| image:: https://repology.org/badge/latest-versions/python:pybind11.svg :target: https://repology.org/project/python:pybind11/versions .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pybind11.svg :target: https://pypi.org/project/pybind11/ .. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github :target: https://github.com/pybind/pybind11/discussions aoflagger-v3.4.0/external/pybind11/docs/0000755000175000017500000000000014516225226016527 5ustar olesolesaoflagger-v3.4.0/external/pybind11/docs/installing.rst0000644000175000017500000000631514507760431021434 0ustar olesoles.. _installing: Installing the library ###################### There are several ways to get the pybind11 source, which lives at `pybind/pybind11 on GitHub `_. The pybind11 developers recommend one of the first three ways listed here, submodule, PyPI, or conda-forge, for obtaining pybind11. .. _include_as_a_submodule: Include as a submodule ====================== When you are working on a project in Git, you can use the pybind11 repository as a submodule. From your git repository, use: .. code-block:: bash git submodule add -b stable ../../pybind/pybind11 extern/pybind11 git submodule update --init This assumes you are placing your dependencies in ``extern/``, and that you are using GitHub; if you are not using GitHub, use the full https or ssh URL instead of the relative URL ``../../pybind/pybind11`` above. Some other servers also require the ``.git`` extension (GitHub does not). From here, you can now include ``extern/pybind11/include``, or you can use the various integration tools (see :ref:`compiling`) pybind11 provides directly from the local folder. Include with PyPI ================= You can download the sources and CMake files as a Python package from PyPI using Pip. Just use: .. code-block:: bash pip install pybind11 This will provide pybind11 in a standard Python package format. If you want pybind11 available directly in your environment root, you can use: .. code-block:: bash pip install "pybind11[global]" This is not recommended if you are installing with your system Python, as it will add files to ``/usr/local/include/pybind11`` and ``/usr/local/share/cmake/pybind11``, so unless that is what you want, it is recommended only for use in virtual environments or your ``pyproject.toml`` file (see :ref:`compiling`). Include with conda-forge ======================== You can use pybind11 with conda packaging via `conda-forge `_: .. code-block:: bash conda install -c conda-forge pybind11 Include with vcpkg ================== You can download and install pybind11 using the Microsoft `vcpkg `_ dependency manager: .. code-block:: bash git clone https://github.com/Microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.sh ./vcpkg integrate install vcpkg install pybind11 The pybind11 port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please `create an issue or pull request `_ on the vcpkg repository. Global install with brew ======================== The brew package manager (Homebrew on macOS, or Linuxbrew on Linux) has a `pybind11 package `_. To install: .. code-block:: bash brew install pybind11 .. We should list Conan, and possibly a few other C++ package managers (hunter, .. perhaps). Conan has a very clean CMake integration that would be good to show. Other options ============= Other locations you can find pybind11 are `listed here `_; these are maintained by various packagers and the community. aoflagger-v3.4.0/external/pybind11/docs/conf.py0000644000175000017500000002646614507760431020046 0ustar olesoles#!/usr/bin/env python3 # # pybind11 documentation build configuration file, created by # sphinx-quickstart on Sun Oct 11 19:23:48 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os import re import subprocess import sys from pathlib import Path DIR = Path(__file__).parent.resolve() # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "breathe", "sphinx_copybutton", "sphinxcontrib.rsvgconverter", "sphinxcontrib.moderncmakedomain", ] breathe_projects = {"pybind11": ".build/doxygenxml/"} breathe_default_project = "pybind11" breathe_domain_by_extension = {"h": "cpp"} # Add any paths that contain templates here, relative to this directory. templates_path = [".templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = "index" # General information about the project. project = "pybind11" copyright = "2017, Wenzel Jakob" author = "Wenzel Jakob" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # Read the listed version with open("../pybind11/_version.py") as f: code = compile(f.read(), "../pybind11/_version.py", "exec") loc = {} exec(code, loc) # The full version, including alpha/beta/rc tags. version = loc["__version__"] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [".build", "release.rst"] # The reST default role (used for this markup: `text`) to use for all # documents. default_role = "any" # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. # pygments_style = 'monokai' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = "furo" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] html_css_files = [ "css/custom.css", ] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' # html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value # html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = "pybind11doc" # -- Options for LaTeX output --------------------------------------------- latex_engine = "pdflatex" latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # # Additional stuff for the LaTeX preamble. # remove blank pages (between the title page and the TOC, etc.) "classoptions": ",openany,oneside", "preamble": r""" \usepackage{fontawesome} \usepackage{textgreek} \DeclareUnicodeCharacter{00A0}{} \DeclareUnicodeCharacter{2194}{\faArrowsH} \DeclareUnicodeCharacter{1F382}{\faBirthdayCake} \DeclareUnicodeCharacter{1F355}{\faAdjust} \DeclareUnicodeCharacter{0301}{'} \DeclareUnicodeCharacter{03C0}{\textpi} """, # Latex figure (float) alignment # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, "pybind11.tex", "pybind11 Documentation", "Wenzel Jakob", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = 'pybind11-logo.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [(master_doc, "pybind11", "pybind11 Documentation", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( master_doc, "pybind11", "pybind11 Documentation", author, "pybind11", "One line description of project.", "Miscellaneous", ), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False primary_domain = "cpp" highlight_language = "cpp" def generate_doxygen_xml(app): build_dir = os.path.join(app.confdir, ".build") if not os.path.exists(build_dir): os.mkdir(build_dir) try: subprocess.call(["doxygen", "--version"]) retcode = subprocess.call(["doxygen"], cwd=app.confdir) if retcode < 0: sys.stderr.write(f"doxygen error code: {-retcode}\n") except OSError as e: sys.stderr.write(f"doxygen execution failed: {e}\n") def prepare(app): with open(DIR.parent / "README.rst") as f: contents = f.read() if app.builder.name == "latex": # Remove badges and stuff from start contents = contents[contents.find(r".. start") :] # Filter out section titles for index.rst for LaTeX contents = re.sub(r"^(.*)\n[-~]{3,}$", r"**\1**", contents, flags=re.MULTILINE) with open(DIR / "readme.rst", "w") as f: f.write(contents) def clean_up(app, exception): # noqa: ARG001 (DIR / "readme.rst").unlink() def setup(app): # Add hook for building doxygen xml when needed app.connect("builder-inited", generate_doxygen_xml) # Copy the readme in app.connect("builder-inited", prepare) # Clean up the generated readme app.connect("build-finished", clean_up) aoflagger-v3.4.0/external/pybind11/docs/faq.rst0000644000175000017500000003157114507760431020041 0ustar olesolesFrequently asked questions ########################## "ImportError: dynamic module does not define init function" =========================================================== 1. Make sure that the name specified in PYBIND11_MODULE is identical to the filename of the extension library (without suffixes such as ``.so``). 2. If the above did not fix the issue, you are likely using an incompatible version of Python that does not match what you compiled with. "Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``" ======================================================================== See the first answer. "SystemError: dynamic module not initialized properly" ====================================================== See the first answer. The Python interpreter immediately crashes when importing my module =================================================================== See the first answer. .. _faq_reference_arguments: Limitations involving reference arguments ========================================= In C++, it's fairly common to pass arguments using mutable references or mutable pointers, which allows both read and write access to the value supplied by the caller. This is sometimes done for efficiency reasons, or to realize functions that have multiple return values. Here are two very basic examples: .. code-block:: cpp void increment(int &i) { i++; } void increment_ptr(int *i) { (*i)++; } In Python, all arguments are passed by reference, so there is no general issue in binding such code from Python. However, certain basic Python types (like ``str``, ``int``, ``bool``, ``float``, etc.) are **immutable**. This means that the following attempt to port the function to Python doesn't have the same effect on the value provided by the caller -- in fact, it does nothing at all. .. code-block:: python def increment(i): i += 1 # nope.. pybind11 is also affected by such language-level conventions, which means that binding ``increment`` or ``increment_ptr`` will also create Python functions that don't modify their arguments. Although inconvenient, one workaround is to encapsulate the immutable types in a custom type that does allow modifications. An other alternative involves binding a small wrapper lambda function that returns a tuple with all output arguments (see the remainder of the documentation for examples on binding lambda functions). An example: .. code-block:: cpp int foo(int &i) { i++; return 123; } and the binding code .. code-block:: cpp m.def("foo", [](int i) { int rv = foo(i); return std::make_tuple(rv, i); }); How can I reduce the build time? ================================ It's good practice to split binding code over multiple files, as in the following example: :file:`example.cpp`: .. code-block:: cpp void init_ex1(py::module_ &); void init_ex2(py::module_ &); /* ... */ PYBIND11_MODULE(example, m) { init_ex1(m); init_ex2(m); /* ... */ } :file:`ex1.cpp`: .. code-block:: cpp void init_ex1(py::module_ &m) { m.def("add", [](int a, int b) { return a + b; }); } :file:`ex2.cpp`: .. code-block:: cpp void init_ex2(py::module_ &m) { m.def("sub", [](int a, int b) { return a - b; }); } :command:`python`: .. code-block:: pycon >>> import example >>> example.add(1, 2) 3 >>> example.sub(1, 1) 0 As shown above, the various ``init_ex`` functions should be contained in separate files that can be compiled independently from one another, and then linked together into the same final shared object. Following this approach will: 1. reduce memory requirements per compilation unit. 2. enable parallel builds (if desired). 3. allow for faster incremental builds. For instance, when a single class definition is changed, only a subset of the binding code will generally need to be recompiled. "recursive template instantiation exceeded maximum depth of 256" ================================================================ If you receive an error about excessive recursive template evaluation, try specifying a larger value, e.g. ``-ftemplate-depth=1024`` on GCC/Clang. The culprit is generally the generation of function signatures at compile time using C++14 template metaprogramming. .. _`faq:hidden_visibility`: "'SomeClass' declared with greater visibility than the type of its field 'SomeClass::member' [-Wattributes]" ============================================================================================================ This error typically indicates that you are compiling without the required ``-fvisibility`` flag. pybind11 code internally forces hidden visibility on all internal code, but if non-hidden (and thus *exported*) code attempts to include a pybind type (for example, ``py::object`` or ``py::list``) you can run into this warning. To avoid it, make sure you are specifying ``-fvisibility=hidden`` when compiling pybind code. As to why ``-fvisibility=hidden`` is necessary, because pybind modules could have been compiled under different versions of pybind itself, it is also important that the symbols defined in one module do not clash with the potentially-incompatible symbols defined in another. While Python extension modules are usually loaded with localized symbols (under POSIX systems typically using ``dlopen`` with the ``RTLD_LOCAL`` flag), this Python default can be changed, but even if it isn't it is not always enough to guarantee complete independence of the symbols involved when not using ``-fvisibility=hidden``. Additionally, ``-fvisibility=hidden`` can deliver considerably binary size savings. (See the following section for more details.) .. _`faq:symhidden`: How can I create smaller binaries? ================================== To do its job, pybind11 extensively relies on a programming technique known as *template metaprogramming*, which is a way of performing computation at compile time using type information. Template metaprogramming usually instantiates code involving significant numbers of deeply nested types that are either completely removed or reduced to just a few instructions during the compiler's optimization phase. However, due to the nested nature of these types, the resulting symbol names in the compiled extension library can be extremely long. For instance, the included test suite contains the following symbol: .. only:: html .. code-block:: none _​_​Z​N​8​p​y​b​i​n​d​1​1​1​2​c​p​p​_​f​u​n​c​t​i​o​n​C​1​I​v​8​E​x​a​m​p​l​e​2​J​R​N​S​t​3​_​_​1​6​v​e​c​t​o​r​I​N​S​3​_​1​2​b​a​s​i​c​_​s​t​r​i​n​g​I​w​N​S​3​_​1​1​c​h​a​r​_​t​r​a​i​t​s​I​w​E​E​N​S​3​_​9​a​l​l​o​c​a​t​o​r​I​w​E​E​E​E​N​S​8​_​I​S​A​_​E​E​E​E​E​J​N​S​_​4​n​a​m​e​E​N​S​_​7​s​i​b​l​i​n​g​E​N​S​_​9​i​s​_​m​e​t​h​o​d​E​A​2​8​_​c​E​E​E​M​T​0​_​F​T​_​D​p​T​1​_​E​D​p​R​K​T​2​_ .. only:: not html .. code-block:: cpp __ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_ which is the mangled form of the following function type: .. code-block:: cpp pybind11::cpp_function::cpp_function, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&, pybind11::name, pybind11::sibling, pybind11::is_method, char [28]>(void (Example2::*)(std::__1::vector, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&), pybind11::name const&, pybind11::sibling const&, pybind11::is_method const&, char const (&) [28]) The memory needed to store just the mangled name of this function (196 bytes) is larger than the actual piece of code (111 bytes) it represents! On the other hand, it's silly to even give this function a name -- after all, it's just a tiny cog in a bigger piece of machinery that is not exposed to the outside world. So we'll generally only want to export symbols for those functions which are actually called from the outside. This can be achieved by specifying the parameter ``-fvisibility=hidden`` to GCC and Clang, which sets the default symbol visibility to *hidden*, which has a tremendous impact on the final binary size of the resulting extension library. (On Visual Studio, symbols are already hidden by default, so nothing needs to be done there.) In addition to decreasing binary size, ``-fvisibility=hidden`` also avoids potential serious issues when loading multiple modules and is required for proper pybind operation. See the previous FAQ entry for more details. How can I properly handle Ctrl-C in long-running functions? =========================================================== Ctrl-C is received by the Python interpreter, and holds it until the GIL is released, so a long-running function won't be interrupted. To interrupt from inside your function, you can use the ``PyErr_CheckSignals()`` function, that will tell if a signal has been raised on the Python side. This function merely checks a flag, so its impact is negligible. When a signal has been received, you must either explicitly interrupt execution by throwing ``py::error_already_set`` (which will propagate the existing ``KeyboardInterrupt``), or clear the error (which you usually will not want): .. code-block:: cpp PYBIND11_MODULE(example, m) { m.def("long running_func", []() { for (;;) { if (PyErr_CheckSignals() != 0) throw py::error_already_set(); // Long running iteration } }); } CMake doesn't detect the right Python version ============================================= The CMake-based build system will try to automatically detect the installed version of Python and link against that. When this fails, or when there are multiple versions of Python and it finds the wrong one, delete ``CMakeCache.txt`` and then add ``-DPYTHON_EXECUTABLE=$(which python)`` to your CMake configure line. (Replace ``$(which python)`` with a path to python if your prefer.) You can alternatively try ``-DPYBIND11_FINDPYTHON=ON``, which will activate the new CMake FindPython support instead of pybind11's custom search. Requires CMake 3.12+, and 3.15+ or 3.18.2+ are even better. You can set this in your ``CMakeLists.txt`` before adding or finding pybind11, as well. Inconsistent detection of Python version in CMake and pybind11 ============================================================== The functions ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` provided by CMake for Python version detection are modified by pybind11 due to unreliability and limitations that make them unsuitable for pybind11's needs. Instead pybind11 provides its own, more reliable Python detection CMake code. Conflicts can arise, however, when using pybind11 in a project that *also* uses the CMake Python detection in a system with several Python versions installed. This difference may cause inconsistencies and errors if *both* mechanisms are used in the same project. There are three possible solutions: 1. Avoid using ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` from CMake and rely on pybind11 in detecting Python version. If this is not possible, the CMake machinery should be called *before* including pybind11. 2. Set ``PYBIND11_FINDPYTHON`` to ``True`` or use ``find_package(Python COMPONENTS Interpreter Development)`` on modern CMake (3.12+, 3.15+ better, 3.18.2+ best). Pybind11 in these cases uses the new CMake FindPython instead of the old, deprecated search tools, and these modules are much better at finding the correct Python. 3. Set ``PYBIND11_NOPYTHON`` to ``TRUE``. Pybind11 will not search for Python. However, you will have to use the target-based system, and do more setup yourself, because it does not know about or include things that depend on Python, like ``pybind11_add_module``. This might be ideal for integrating into an existing system, like scikit-build's Python helpers. How to cite this project? ========================= We suggest the following BibTeX template to cite pybind11 in scientific discourse: .. code-block:: bash @misc{pybind11, author = {Wenzel Jakob and Jason Rhinelander and Dean Moldovan}, year = {2017}, note = {https://github.com/pybind/pybind11}, title = {pybind11 -- Seamless operability between C++11 and Python} } aoflagger-v3.4.0/external/pybind11/docs/basics.rst0000644000175000017500000002203014507760431020524 0ustar olesoles.. _basics: First steps ########### This sections demonstrates the basic features of pybind11. Before getting started, make sure that development environment is set up to compile the included set of test cases. Compiling the test cases ======================== Linux/macOS ----------- On Linux you'll need to install the **python-dev** or **python3-dev** packages as well as **cmake**. On macOS, the included python version works out of the box, but **cmake** must still be installed. After installing the prerequisites, run .. code-block:: bash mkdir build cd build cmake .. make check -j 4 The last line will both compile and run the tests. Windows ------- On Windows, only **Visual Studio 2017** and newer are supported. .. Note:: To use the C++17 in Visual Studio 2017 (MSVC 14.1), pybind11 requires the flag ``/permissive-`` to be passed to the compiler `to enforce standard conformance`_. When building with Visual Studio 2019, this is not strictly necessary, but still advised. .. _`to enforce standard conformance`: https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=vs-2017 To compile and run the tests: .. code-block:: batch mkdir build cd build cmake .. cmake --build . --config Release --target check This will create a Visual Studio project, compile and run the target, all from the command line. .. Note:: If all tests fail, make sure that the Python binary and the testcases are compiled for the same processor type and bitness (i.e. either **i386** or **x86_64**). You can specify **x86_64** as the target architecture for the generated Visual Studio project using ``cmake -A x64 ..``. .. seealso:: Advanced users who are already familiar with Boost.Python may want to skip the tutorial and look at the test cases in the :file:`tests` directory, which exercise all features of pybind11. Header and namespace conventions ================================ For brevity, all code examples assume that the following two lines are present: .. code-block:: cpp #include namespace py = pybind11; Some features may require additional headers, but those will be specified as needed. .. _simple_example: Creating bindings for a simple function ======================================= Let's start by creating Python bindings for an extremely simple function, which adds two numbers and returns their result: .. code-block:: cpp int add(int i, int j) { return i + j; } For simplicity [#f1]_, we'll put both this function and the binding code into a file named :file:`example.cpp` with the following contents: .. code-block:: cpp #include int add(int i, int j) { return i + j; } PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring m.def("add", &add, "A function that adds two numbers"); } .. [#f1] In practice, implementation and binding code will generally be located in separate files. The :func:`PYBIND11_MODULE` macro creates a function that will be called when an ``import`` statement is issued from within Python. The module name (``example``) is given as the first macro argument (it should not be in quotes). The second argument (``m``) defines a variable of type :class:`py::module_ ` which is the main interface for creating bindings. The method :func:`module_::def` generates binding code that exposes the ``add()`` function to Python. .. note:: Notice how little code was needed to expose our function to Python: all details regarding the function's parameters and return value were automatically inferred using template metaprogramming. This overall approach and the used syntax are borrowed from Boost.Python, though the underlying implementation is very different. pybind11 is a header-only library, hence it is not necessary to link against any special libraries and there are no intermediate (magic) translation steps. On Linux, the above example can be compiled using the following command: .. code-block:: bash $ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix) .. note:: If you used :ref:`include_as_a_submodule` to get the pybind11 source, then use ``$(python3-config --includes) -Iextern/pybind11/include`` instead of ``$(python3 -m pybind11 --includes)`` in the above compilation, as explained in :ref:`building_manually`. For more details on the required compiler flags on Linux and macOS, see :ref:`building_manually`. For complete cross-platform compilation instructions, refer to the :ref:`compiling` page. The `python_example`_ and `cmake_example`_ repositories are also a good place to start. They are both complete project examples with cross-platform build systems. The only difference between the two is that `python_example`_ uses Python's ``setuptools`` to build the module, while `cmake_example`_ uses CMake (which may be preferable for existing C++ projects). .. _python_example: https://github.com/pybind/python_example .. _cmake_example: https://github.com/pybind/cmake_example Building the above C++ code will produce a binary module file that can be imported to Python. Assuming that the compiled module is located in the current directory, the following interactive Python session shows how to load and execute the example: .. code-block:: pycon $ python Python 3.9.10 (main, Jan 15 2022, 11:48:04) [Clang 13.0.0 (clang-1300.0.29.3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import example >>> example.add(1, 2) 3 >>> .. _keyword_args: Keyword arguments ================= With a simple code modification, it is possible to inform Python about the names of the arguments ("i" and "j" in this case). .. code-block:: cpp m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j")); :class:`arg` is one of several special tag classes which can be used to pass metadata into :func:`module_::def`. With this modified binding code, we can now call the function using keyword arguments, which is a more readable alternative particularly for functions taking many parameters: .. code-block:: pycon >>> import example >>> example.add(i=1, j=2) 3L The keyword names also appear in the function signatures within the documentation. .. code-block:: pycon >>> help(example) .... FUNCTIONS add(...) Signature : (i: int, j: int) -> int A function which adds two numbers A shorter notation for named arguments is also available: .. code-block:: cpp // regular notation m.def("add1", &add, py::arg("i"), py::arg("j")); // shorthand using namespace pybind11::literals; m.def("add2", &add, "i"_a, "j"_a); The :var:`_a` suffix forms a C++11 literal which is equivalent to :class:`arg`. Note that the literal operator must first be made visible with the directive ``using namespace pybind11::literals``. This does not bring in anything else from the ``pybind11`` namespace except for literals. .. _default_args: Default arguments ================= Suppose now that the function to be bound has default arguments, e.g.: .. code-block:: cpp int add(int i = 1, int j = 2) { return i + j; } Unfortunately, pybind11 cannot automatically extract these parameters, since they are not part of the function's type information. However, they are simple to specify using an extension of :class:`arg`: .. code-block:: cpp m.def("add", &add, "A function which adds two numbers", py::arg("i") = 1, py::arg("j") = 2); The default values also appear within the documentation. .. code-block:: pycon >>> help(example) .... FUNCTIONS add(...) Signature : (i: int = 1, j: int = 2) -> int A function which adds two numbers The shorthand notation is also available for default arguments: .. code-block:: cpp // regular notation m.def("add1", &add, py::arg("i") = 1, py::arg("j") = 2); // shorthand m.def("add2", &add, "i"_a=1, "j"_a=2); Exporting variables =================== To expose a value from C++, use the ``attr`` function to register it in a module as shown below. Built-in types and general objects (more on that later) are automatically converted when assigned as attributes, and can be explicitly converted using the function ``py::cast``. .. code-block:: cpp PYBIND11_MODULE(example, m) { m.attr("the_answer") = 42; py::object world = py::cast("World"); m.attr("what") = world; } These are then accessible from Python: .. code-block:: pycon >>> import example >>> example.the_answer 42 >>> example.what 'World' .. _supported_types: Supported data types ==================== A large number of data types are supported out of the box and can be used seamlessly as functions arguments, return values or with ``py::cast`` in general. For a full overview, see the :doc:`advanced/cast/index` section. aoflagger-v3.4.0/external/pybind11/docs/pybind11_vs_boost_python1.png0000644000175000017500000012715514507760431024301 0ustar olesoles‰PNG  IHDRÏ ÜMÈbKGDÿÿÿ ½§“ IDATxœìÝ{|\e?ðÏ÷™KJ¡-m)i¸µ€ÜTTt+rs—ÀªPÒtæÌ´4»ººþ¼pu­«ÛE4ÉœIÛÈEWg•‹àÝE©÷ ¥ÜÚ†”k'‘¦i’9Ï÷÷ÇÌ”i.MÒ&9“Îçýzñj2ç9çùÌdNÈwžç< """"""""""""""""""""""""""""""""""""""""""""š®$èDT~šššª{zzŽ …B*"Ï477ï :Q¹‰ÅbG†ÃáùƘ›››Ÿ Ag"""¢ÉÃ♈«V­::—Ë­° Àñ%›|øªçyßÄAX 8Žs=€ø©çyËJï@þ÷ä…žçýy‚ú:9w”~ á8ÎÇ4¸Óó¼äDô3щÄÙ©TêáÒÇâñø7Dä<Ÿ÷<ïkE›rÉdr‘µövç‘§R©ÕÆšñx¼ADþ€_yžwÍÏqœÇÌ´ÖþC[[Ûƒžˆˆ(8á Qð‰Dc.—[  ºðЀm°À›¼Éqœìíí}ß­·ÞÚPÔI!"‡©j €yƒ6-kmô@ûp]7ÜÙÙùYÿ”ËåŽP:š8€U=â@û™h×]wÝýýý7«êy(¼%æ¨0kê“GU×â•Âù ä?`ùcp‰&Žˆ`1€§&è5fŠHÕˆˆ(0,ž‰*\"‘ø˜ª~TõnWW×Ï3™ŒäGÙTõªº À»«««¿àŠ#O8kíŸDä6˜¬>¶lÙ2'‰||„Í¿p›ˆüf²úß_¹\îõ"ò>ƒ·‰ÈO<§ª™údÁ¨««‹ªê߀ª^—N§›ƒÎDDDDSƒÅ3Q‹Çã¯WÕϾýÆ¢E‹®u]7WÚ¦µµõ×%‰UõÓþ!‘H¼;•JÝ9å'I:þ€Õ¿çy™ úß_žç}1è SmΜ9‡¡ðÿÎp8|oÀqˆˆˆh ±x&ª`ƘϪª°µªªªapá\jÇŽ7Ι3çÇ«ê‡ [<×××Ïž1cÆI¾ï‡Uuk[[[ÇXó8Žs”ªoŒéÚ±cǦâèw¬\¹ò¤9UUU›¿öµ¯½4Úñ\×5Û·o?ÙZ;[DžòÞØØXÕ××÷ Gz™^ðÕššš+‰ŽãÜàb³ mºX¹:•JÝã8Î>*"ßI¥RW—,‹ÕcV#?U¾ôÚë'UõsétzÝ ×u€Ç<›ËåÞ‰D¾¬ª×˜Qh2 ‰D®íÇq68ùkßm!7Œ1¯nmm}&‘HÜ©ªK‘ÿù~¹÷ cÌýªú°ˆ\[ø¹¾€)¶CD©Têžd2y®µ6à´bŸ"ò ïûïokkrÍm<3€/ŠÈ›ñÊûÄ‘c>ÒÒÒ²i_ÏgÇc"ò¯Ø{‘¼Ý"òß÷?^|Õ××ψF£…çqx¡]wáuù†çy©ÇqVøœªþ—ˆÜ àÌ’&¿ð>ÏóžH$Žª~ùµÀªêm‡zhrpq[WWš;wî‡TõŸ‘¿¶¸¨Àm‘Häÿ ÷3®¯¯Ÿ]UUõEU] x-r7€Ï#ÿþøOäÏ[ZÜ'‘H<¬ª‹UuE:¾c˜çè¸Àžç­(y|'€™ªz~:þEé>±XìœP(ôEU} J~žªzŸª~¤­­í‘á^O""¢ ˜Ñ›ÑÁ( íùƒµðý¨Òéô}žç}cpáì8ÎÛ­µ¸À‹ªz òÂ#Îp§ã8-ÝÇ0GDŽð¿"ò.÷«ê=²Ž3Æü ‘H\ àGŽp/€_"_°¼ÍóÍA«Ìpž1æ䋜¯ˆÈÈño6Æü,‘HüÝ ý"È—cYÔHúúú¾àßà^UmUÕoØZÈù™ÎÎÎÏ—ìó€?í9€ÈŸl°ÖGL#fXk÷ê?‹bŒù€÷Ø à¿´¨êC‹ÈZÇqR¥û˜ü°èóÂáð]ªð´ˆÜQÈðþ\.wFÿõO6¾°À†¾¾¾~(äQ8& ‡ÿ¹ à—…ÂùÿÜü µªúÝx<þkíÏUxÿýùBñcÌÿ ΖH$®‘ûEä\[¿F<  CU/õ}ÿÁd2ù†QžO)qÇùÂù7È@óßúUõÆ˜ßÆb±S`Ö¬YZxþ{+þUõéQúšQxMÞ à~'Þç?Ðàõ~à8ÎÇU5 WU¿üëoDdYOOÏçJèºnxöìÙß)|XTà…üßAþÿ퉇b±Xmé~õõõ³£Ñè/ ï‹€o!®>`5ò«¾¡ª‡˜cŒiñ¼jäßw3Gy-ñxürcÌ/Tõ­¶ŠÈí<ÛDäbc̃±X윱‹ˆˆhªpÚ6Q…2ÆÔª*ôzž7Þ»=êëëgøäÿxþ^ooïÕÅ)¯®ëšgžyæ“"r€/Äb±ÛÚÚþwÐ!ΰÝZûÚ¶¶¶?ÀŠ+Ž …B0KUo𪪪†âtãD"quáñ·Äãñ“ÒéôcƒŽùZ䋾óŠSµëêênœ3gNÀrUmkjj:u¦©Æãñ:è±ÖžW:"]WW3gÎZWˆ#û+õ<ïÓË—/Ÿ‰DžU½j´)äuuu!cÌwÌWÕ‡B¡Ð»[[[Ÿ/nO$ËTu'ÿ:N·:Ä|‡ªêétú;ÅÇù0€5ªúÖx<~v:þíH<Ï{_"‘¸PUà%ÏóÞ9¦)ïd/ZkßP| ³þ `na¶»C¡Ð5Åiºñxürù.€×Æb±“‹#±XìxUmQÕÖ3f|øæ›oî+¼Nѹsç¦TµÞZû­ÆÆÆ“‹Ûö%‘HÔ«j ù‘ÎkÓéôíÅm«V­Z˜Ëåîp¶1&SWWwfá˜ïŒÅbGcžÆösd©ª>”Ëå.]¿~ý …çü.¹À©þÀg³Ùì ÅKǹ ùÝø§âžy晊È{ôŠÈ©Têžâ¶X,v¼1æ^'‰È­Þ^ÜF?ƒü9· ÀÛ‹ÓÿljhÇóÙ/+V¬8VD¾ *"é¾¾¾ë‹ÓÌKsc¾ÕÔÔtrPÓɉˆˆãÈ3Q…*Üš ^ÄÜ»¹ªª*`.€ÎÒÂ\×µétúÆÂ(›1ÆüëpÇ‘O gX»víU½«ðíÎ\.·¼ô:ÝT*u;€¿!ÐWaªZ_ZØŠ‘xÀq===—·ßhDäôÂ1n+-œ }ôXSøvöªU«Æ4 7œ¹sç¾À)ú"‘È¥…3¤R©[Dä«…LŸá0_*-œÀó¼› ùaŒ9eóÑgK_£uëÖuªjqÊo_$¹¶ôúÖÂtàç p4 9?Œüˆæï-ZÔXZg2™þC9d€g×ßßÕX‚©jqåó¯”ÎÐÜÜü¬ïûW ?*|Zág1!T5^,œüläg&@D6xž÷éÒký­µ­…/444Ìò£Î"ò‘Â>7”ÎÐÖÖö”ª^@Eäüd2y.455U#©D¤±ôºyÏó²ÙìuÅ,“És=ò·7û£ª^Wz}¶çyýýýÈ÷Çìܹó}“‡ˆˆh¬X<U(U-.ÚÚgÃÑSüöH‹,¦×ÀÛ‡Lö}È´q)N tݺu/îù¢¦ËMétúWƒô…&}Õw¹¤Ø¥çyƒ·ŠéÚŽúó$""š*œ¶MT¡Dä¹Â—óöÙptK@Uÿ8Rkí +Ïèíí­Pº”vww7õµøGõH«u¸28€ß´¡x}ªª.©ÍX8Ž‘³­µ§‹È«Ÿ¦üjäØ_™ùº(Ã#¾®‹-z¤³³³ù…Ä–`Ш¡ªna×]…í3FØ>!|ßòs‘œªBU÷ùs5ÆŸ–WÞcïwgéû_hsÒh¹TµøÚ,\¸ð¯#µ³ÖþAD.Å+?‹""Cî•]ÌQøwÈk2000ä}^2*¿½t{˜vPÕ×ã•üÅ;FZY_Dž*\Î1)êêêBN,|{•ã8çÐô¸Â¿£þ<‰ˆˆ¦ ‹g¢ ¥ªOˆDW¬XqÂÚµkmŸU«V `Π‘ÐâÊÃG‡÷0ÆìÙ&"ƒGŠûÝ’jpÎ}ÉѳˆÈsª ™=R›ÑVOþWU=ºð=#"ßVÕ+÷÷ØEªzXáØ#>×u­ã8=ÈÏÃÀ¸ïTxùå—w´MDÆôs-ÜW¹èŒ1ìrøh ¬µÅ×¶g_·+y ÷Úî_B#žƒÚ_“}ÞÂÊZûráyRدøž~¤}Tõ™±dØ_3gΜ…Wf½½ºðß¾Œúó$""š*œ¶MT¡"‘ÈÏ_ÁƘ1M¸<—Ëmuçñd2Y¼•ÎN‘§(‡B¡=P$Vl›Ëåöûv€Æ˜ba4âë꺮)n·ÖŽzßë©vÚi§MÄÏvOÁ©ªï …Bs÷õ_UUÕëG;`Ék;³ðŽäðB¿òÚê éªê¨ï‚Ã@D^*ü»£ðxõ>޽Ï•¬µÃ~讪#³TOOOéWŽöóD~ñ?""¢²À‘g¢ ÕÜܼ3‘HüDU/‘ëÇIwýá ‰Â¿»K°zùBrÄ$kmq[ß‚ ö«h9v›O/ü;îÆ]× wvvšú²çyÜÆZ{dñë™­ªxöñºnß¾ýd¼r›¨‘¦AOkžçírg;ò·´ZÜÒÒ2äÃ@þþÖ¹\®¯¥¥eÔÑvc̾ï@¤ð;u[DÎ(Ô»“:»ŠÓóºîºëŽØÇýº‹ïg@UŸ,|ÿªºººhá罈Èq#«¯°}ØâÚsäX>Èd2ýŽãlptáç™®Ýu×]w„1f ¥¥åoÃm'"" Gž‰*˜µöK…/_%"ŸÇ>îûë8Î ÷Ø…ª÷ƒªþ¸ðåU…Õ|‡PÕú—?éZË vÆŠ+Nü`á¶Zï.dºs¼}öÙgD~¡&cî¡Ùß¿…B{^cÌž)¹¾ït¯Ü=D¤øº^ÐÐÐP3B³å…mkk{j„6ª˜{ÔÌ“¥ø‘÷0R,~‡ÿ6ø¾×Ãiiiy…TU¯®M2™\T\ ODî®MPººº°€är¹‘òŸ."¯kí=PUUõ ݪçÌ™sÅ0» €aW‘,¨êÂÁÛêëëg¨êÛÆñ~\8Öû ×@é.—ËÝ××××í8ÎÚq—ˆˆhR±x&ª`étúªÚ ªú‘x<þíd2yzi›+VÌug5€› í~¼hÑ¢[ŠÛs¹\€.µ===ëêëëKG[%‘Hü€Ë¿mÎÍ“ýœ L8¾µP,ÈÿFט à‹-²ôhª««w 0g­½xðvÇq.P:½çZYß÷÷LW5ÆŒv'Ž:ê¨ï!¯êápø[+W®œSº=ÿƒª~¨ðíWÆó<ÆCDйH&“‹&«ŸQ¬SÕ×uvv~ÅuÝÒYS’H$>àLä/võéaüGáߦD"ñÞÒ +V¬˜k­ýoU6õõõ Y >H™L¦_U‹çãŽã¼½t{2™\d­ý‘ÛÚÚ~…[|ýW¡ÙÅb±sJv“x<þ)#M{ù./}455UG£Ñ4€!EõHŒ1k_$íÌÙ³gµpoç=9ǹAU_@GZ ˆˆ(œ¶MTá-ZÔ¸}ûöYªú¹ÂZ{…ã8[¿ÑáNCaj°ˆü/€ºÒE–Ö¯_ÿB<¿FDþÀ?F£Ñsǹ ùë©ÏSÕ×"¹§ëyÞ÷?I^VÕ7D£ÑGÇù®ªæDäÝȯàû¢ˆÔïÏøš5kz‰ÄZU]ࣉDâ¿QÕ¨ˆœ¯ªo‘ß©j-€#Edϵ×ííí»Çy Àñ"òÇqž‘I¥R· ח뺹d2y•µö'ÞâûþcŽãü@Dv ‹bÁt«çy­Ãc"Xk7!?ú²Ö>å8ÎyW*•qð‰–N§ÿà8Nò\×ÙÙy¡ã8÷ªª-¼îÅ#nô<ï7c9¦çy^<?ODÞ§ªßqçç~`ò£¯GxAD®*½q¹‘p.ò·æú‰ã8÷ø €£¬µïAþ>Ê[}ß?JÖ¨ªªú÷þþþw¨ê[1÷;ŽóÛUõ­"ò‘?ç÷b­m‘k,²Ö>â8νlOOÏ;ÌSÕoŠÈ˜îÉÜÚÚú—D"q½ª~MD’.H$÷Zk}9¯, ÷ùÖÖÖán·FDDŽ<U8×us©Têj©ðkäÿÐ>ÀyÎB¾p~@ãŽ;Þîy^÷àc¤Óé»Dä-ªz?€Z+4!¿ØÏêzY:¾qjžàÑÂŠ× `¥ˆ48FDî‘7Há·cÇŽ&_Яª—ªêg|JU_à;vìx³ªÞªú¥ûªêJÏ!?=öHkí™ûꫵµõ÷Þ "w ?bÞ ªA¾p~LUÏó–a]+ò<ïEÿ ù÷‘ª:¤¸šlžç}UU/Aþ6dK\Wø¹¾ù[ŸÕ{žçŽãšN§?àC¶#ÿšþ3€3ÜfŒyÍT~H0…õ .‘OȸÀG\üûË‹D"¯<ÿæ›oîëëë»…Ñ|ïðÏ"r–ˆÜà“Ãõ—N§‹·ízù¼ÀUz¼×ó­ñäO¥R­.‘ «êªÂÏó O«ê Ïó†ÍBDD”ý^ –ˆNõõõ³#‘È©‘ÝÆ˜§Z[[Ÿëþ±XìHc̉ÖZ‰F£Oº­Õ¤J$IUmð[ÏóÞà8NÄóš\.Wà±¶¶¶çF;ÆX]sÍ53«ªª–F—·/Z´è‘}Ýö¨ÈuÝð³Ï>[‹ü=†·eà•ŸK(Š t¬]»ö LbÑxŽQ…㵟DDDDDDD£`ñLDDDDDD4 NÛ¦ŠÐØØXÕÛÛ{ÔÖÖÞV˜"JDebùòåóC¡ÐE"òr:¾#èSDv§R©‡ƒÎCD{K&“ ¬µ'©j6NWü%Ë?Ï|@ß?Ž]ξö³?|ó×&-M:ŽšõB°ì¶Ï\òã©ÊED“‡EU„l6«ªšUÕlÐYˆh¨h4š+œŸÝAg!¢¡TµOU³Æ˜Ag)'·¸ý_("§ø¥³f^„¢-¬zú-Ÿ¾äÅ#"š\Žã5557º®kƒÎDD¯ˆÅbµÆ˜˜ªfÓé4¯}&*3ñxü,¹LU7§ÓéÛƒÎCDŽ<‚#ÏTÖ¬YÓ[WW·<Ïã¨3Q™©­­íܸqãê™3gjÐYˆh¨®®®?ØÀ: QPX~Í5×\P]]ý'ÿâ8ÎW<ÏãèÑB¾]¬cuÎY2Iqˆˆg‚0ªzVáß £µ‘+ ÿ®-}üÖ[oíp €CK§sÑPš÷NŠIˆBDT¦Åȳˆœ©ª‘ Žã,‘SUu'€ßxž·kPó7@.—ûÃ0‡úcáx¯pûä¦&"""š¾üˆ>î—Æó÷¢Ê#“—ˆˆ(XÓ¢x.Œ<ï‘õªú.Õ=‹8f‰ÄGS©ÔÚ’¶µPUUõÒàãˆÈŽB~ÜĦ2ÒÔÔTÝÓÓó1¨©©ájÛDe&‹ÕcbªšM§Ó¼ö™¨ |ã_/Í.»ñ®Aåâ±î£ÐoMf&"¢ •ý´íU«V à3Tu–ˆ4¸RDnB~ v[<¯/Ùe6€¾æææƒe­} TuæD'"""šæÌ'ô¥¥¨ü÷­î%Or "¢À”}ñœËåf©ªàËÙlöm©Tj½çy™T*õa©ùb]]]´°K@ßpÇ2Æù‡&?9•“5kÖôf³ÙÕÙlv5G‰ÊOmmmg6›]=00 : ½â–O_ü{ˆ®F½–ù¡Põ€3™ˆˆ‚RöÓ¶=ÏÛ`åpÛR©Ô÷Çù=€×Ì;÷u~ `€ù®ë†]×Ýk¡ ß÷0Æ@Dþ¶.#ªúÎx<^N§Pº!‹-€\.÷í­Žã\`­]¨ª¿X»ví–âã‰DâLß÷Ï4Ælò<ï7ÅÇëëë†Ãá D¤‹}L]sçÎ=É÷ý3Ç™Öσ}°ƒ±ŽŽŽ fÏž=íŸû`e[¿‡¾…_(‘ªÕÎË"@¯…ö ÌWŒV»ë>ööÝeý<Ê´pP‡hÚ(ûây 6x €…`Ë–-s¼PÚPD怵vÇ>Žpºˆ ™L>[ºÁZ{€¾ïïõKNUkŒ1Ç ^ \Dæc‹È‹¥Ï˜1c†µv±ª>?¸scÌb`ìƒ}°öÁ>Øû(—>Þn½÷¼š'¿3€ð܈ä@Άrý~ø×‡F¾{tì±ÝÓáyÕ‡ˆ,‘þd2ydÉã¯5ƼÓ`&(å•}ñœH$ÎVÕ·ªêoÒéô¯†ir$Xk_UÝ("g„B¡c0´x>®ðïï÷ÑeŸˆÜe­ýEkkëÆÒ ±XÌ€%K–ì5-Ü÷ý_cþ‰D:KïïïÌó²1æ…A¿dŒ¹SDvckíìƒ}°öÁ>Øû`åÒÇ9 ·ý¶EOü/DNŠà•I}aã‡ÃƇ|:}âgŽ‹oþl9?2èãÉ–––lññ†††cÌo1W >•§ñÝø>‰Db¹ª®‘;R©Ô{K·544Ô„ÃáÇ ô÷÷ÕÞÞ¾;‘H,SÕ¯p=Ï»¡´½ã8÷¸PDNO¥R®?Çq7•JýxÒžM¹ÆÆÆªÞÞÞ« ¶¶ö6^÷LT^–/_>? ]$"/§Óé;‚ÎCDyÛÚN›kÑ÷[‹Gm,zý±+ž¸yòS\ÇéÊår§®[·®sôÖD¤²Ÿ&¢ªßð‚ª^Vºªv2™\ …n0SU¿X¼¶$ }À3>‹ÅÞQlÇ?àBUýáH…3¼Âá°1Æ,.N©"¢ò …ª çç1Ag!¢Wøèû$ÆR8€Ê¿?µþ¸…“›ˆˆ(8e_<{ž×m­ýG/‹ÈzÇquçWÖÚ'Eä|iïêêúb±}ssóN¹€1ÆüÈqœÇù£ˆü€­¾ïÇ{2˜ŽŽŽ~Uͨj†£ÎDådzCU3Ƙ{‚ÎBDy§^ ~»Ì”\è“•‡ˆ(heÍ3´µµýlÕªU§û¾¿RUß À"òÍT*5ä­T*õÓ•+W¾ÆZ{½ªžàɨêÍëÖ­ëžò'@Ëd2>€£6$¢@xž· ;z+"¢éiÚŒ<×uÃç€çyЀ#Q‰†††YápøLÙJ¥:Ç9mÚÚvÂ3,ë>ü|23‰#ÏTº»»#–XêºnÙߢ¨Òc°ÔZ{nÐYˆ(O ‘¯Œ}<ß‹ðOb$"¢@±x¦ŠÐÑÑá‹ÈÙàº.G‰ÊL$é‘ Ƙ¿…ˆ^ñ‚Ø¿CS _Vœ¼bÓË“‰ˆ((œ¶M!“Éô¸3èD4¼–––,xŽ•³¶4s™D£·+pÑÍþÅŠcÍwMi8"¢)Æâ™ˆˆˆˆFt쪭YoñN¼¢×@ð³Ø"À}Qƒ¯Õðø Aç$"šl,ž‰ˆˆˆhT…‘eŽ.QÅbñL¡®®.4oÞ¼c ¥¥åÉ óÑÞêëëgTWW×ø¾Ÿó0™yˆˆ¨<ñ“SªMMMÕ===€šš®¶MTfb±X­1&¦ªÙt:ÍkŸij‰^5¾ö¸À×''LyŠÇãg‰Èeªº9Nsµm"ªHy&""¢ŠÕ°úû³=®TNœ4DDTÎ8òLaÍš5½uuu«Àó<Ž:•™ÚÚÚÎ7®ž9s¦…*‹íµ!ȸw«¸¿Ÿºººþ `?è,DDA©¸_þT¹2™LoЈhx…K)xŽÒ”kw/ïZvÃÝ/bì×cùN;ó“‡HïkÃÈÍìÓªî>þrvuöSK®}ô± 3e``àéH$’±Öî : QPX<‰‘ÊN2™\`­=IU³étš—XQEâÈ3U„îî–º®+Aç!¢½c°ÔZ{nÐY¨²è·ômãÙG çORœ²åû~ òÿ=+è,DDA™–ÅsCCì±¶u'âºî´|ž4q:::|Ù "\×å¨3Q™‰D"="²Áó— ³PeÙž=i€ÈxöQ ân×”Ëå^*üôñ ³eÚLÛvçp€°ã8;üPU?™N§‡Ü:"_)"Ÿprgg'ÇyÐóñÖÖÖ¦8:•L&ÓàΠsÑðZZZ²à9JèĬîùè¶߀ŽÉÊS®Ö¯_¿ À¶ siZŒÈ:ŽCþª×ˆÈzUýŒˆÜ NDJ$§j¿RD¾àPù/ù€×XkÇÏ›úg@DDDåèìĆ~;ÎÝøA<Q*û‘çÂíÿ° ÀÙ©TêÑâ6Çq>àfUý2€‹`ùòåó| ÀSƘsZ[[Ÿ€x<þmù©ˆ4»®ûj×uí”?"""*G€7ޱ­˜ôd†!"¢òTö#ÏápøïÌ‘oxž÷hé6Ïó¾ àïŠ×5‡ÃákàËÅÂÒéô¯Tõv§nß¾ý-S÷ ¨ÔÕÕ…V®\¹xåÊ•‹ƒÎBDCÕ××ÏX¹råbÇqŽ : Užc{üëÜ?–¶ ´{ì¡IŽTvfÎÑ£‚ÎBD”éPØû`݇€ˆ¦…iU<;Žójkí}ŽðiÏó>;L³.sg•þ‚€\.7Çìãš:UཡPè¤d2ù?¥Û¬µWØyôÑGÿ€=¿}ß?_DŽÛ½{wÀÆ’]N‘óEä!{~ñΜ9s¾µ¶Îó<€½~ñŠH°öÁ>Øû`ìƒ}°ƒ£KvïÞ½1™L>Y|\U_+"¯SÕiõ÷8Q%›6'k2™|ƒµö‡È_¯¼Êó¼–šn°¸¯¯o>€½ŠgYªºy] ø‹ªþ_kkë^·¢ˆÅb'@(ò·ÓZkUu¯E4T5k­}ÒóRéã»wïÞ‡Ÿ‘®Á[kŸdßGSSSõ®]»®RÕ…"rßt}ìƒ}Ä}t‰È[ãñx$Nï¹öy>öÁ>Ê>¢ÑèiŽã\¬ª›ÓéôíÓõyÜǯÓéô–âã‰D¢ÏZ»ËóƒEDåiZLI&“ç ç0€÷{ž÷½‘Ú:Žó)7ªê²t:}ë m_pª^˜N§ïaÿDÄM¥R?žÈç@ÁjjjªîééùÔÔÔÜ8Ü5ñDœX,VkŒ‰©j¶´x&¢òÇϑˊÅsÐy&Žãtår¹S×­[×t¢ÿÏÞ½ÇÇUÕ{ÿ¬=“¤i)—Rn!´Ð"* Êä¦x|¸)¨)ÞZÚì„báTEÔ#²=ŽçPµÚ83½„rQ‰Ê£Øâõ€ ¨Hõ r-”^"Ò&³÷zþX2¹'m&{’|߯W^3™½ö¬ß$™$¿½Öú-XÑïw{饗îEÑÀċJœÂ0ü5Æ\éûþUµ}ß?˜ <{衇þ¦°QK±Y²dI[KKË---7*q)>•••Í---7vtt¤âŽEDzÛ¶mÛ#---7nÛ¶­)îXDDâRôÓ¶Ã0¼¨Ú­µßñ}¿ÏvíííïhllܶbÅŠ§kkkÿËsðûºººoGQ´7p%0ÅZ;7oOh™@šššÚâŽADú–»¨¥÷¨H‘jjj Ñ{TD&¸¢Ožã€Î=›÷ë¯Q"‘xcýÐCýÒóÏ?¿ÃZûkmʸ"†Ou=¶µTÑ'ÏétzØEr#_ ‚à†Í›7šH$ZÓéôKODDDDDRNô¢ IDATD&€¢Ož÷Dnzösƒ6”qoÑ¢EemmmTVVÞªuÏ"ÅeÁ‚$‰³1¯e2™;ãŽGDºó}vE§$‰­©TJµcDdB×ɳH§d2éyž7+î8D¤o‰D¢Ìó¼YÖÚ–Á[‹Èh³ÖNõ NßؘC‘<ÕÕÕS“ÉäñƘ©T꡸ã‘îêë댢è(kmK&“Ñ ™¶L&W'ÍÕÕÕÖÚK€mÖÚÀà8cÌUTdlß¾½8 8+w<"ÒçyûgEQtJܱˆHoaVàþŽžw,""qpä9—(Ÿi­]‘ÉdjJJJ>h­õ€Õ™L¦À÷ý¬µ¾TðˆEvÖ-[ÂiÓ¦­‚@£Î"E¦¤¤¤5Š¢uƘ×ãŽEDzËf³/—––®^Œ;‘¸ ˜<'“É7ø~çcÖÚDQôü¦N.D€"#¡©©©¸+î8D¤o -è=*R´V­ZµØw""qpÚ¶1&ð<ÏÌ;w p&ð÷ÊÊÊû;ÛYk÷´ÞYDDDDDDÆ¥“çD"ñ$`£(z?À¤I“.Ê€ŸA+ aŒ¹ÀZ»¡àÑŠˆˆˆˆˆˆÄ`ÀiÛË–-{Á÷ý»Œ1Ÿ¯««;ÝZ{€1æ6ß÷ë¢(ºØßó¼U£¯Èn©ªªJLŸ>}&@CCÃ3qÇ#"ÝÍŸ?RyyyE†Ùt:½)îx&’¹×ÿôcï³Ø àUñà‘<ôÇ΋ä"à*â—••†a[:~>îxDDâ0hµmÏój­µw[kß´‹S©Ôוּ'Xk¿”J¥V8V‘ÝVYYY†á¼0 çA0èϽˆŒ®d29= ÃyÖÚ ãŽe¢˜¬9xîµk~h¢Ä,c͵ƚ%ž1÷?kNzdÞµ?;3î¥x$‰Ù¹÷è{ãŽED$.ƒîóüÝï~÷EàÜùóçOjllÜE÷ýqÿ#‘H\™+ô"R´ZZZlII‰~NEŠTiii¶£££ÕÏóƒ»Lô{•}·p,˜_^|íÚù7_sÎm£Ÿkí. Åó¼qÇ""íwÛƒïû÷c‚T*õ«¸ciAxϘ“Þ1„æ»BkN¼-8ço…ŽKd¢ò}[6›=våÊ•ÍqÇ""ë6ò|Ùe—íŸÍfkvó¹6¥R©ï@L"""R Ì;?b†–8”%Œý ð±BÆ$""2tKžwíÚu çy7ìÎYkï”<‹ˆˆ1Ïz¶ÆÞ°ËyUÁ¥MÁœöBÅ$""2tKžËËË·îÚµkN6‡_6)kí‰DâEkíAÖÚËç=Ïû—ÑXDDDvŸ5öÍÙÍfß½råÊ×zœWmmí1Œ¢hðÙB,²;/^\ÞÚÚz@EEÅuÚ‚E¤¸ÔÔÔTzžWc­mÉd2ߌ;žñÌ`¬eX#Ït$¢á ãNmmí Æ˜ ¬µOe2‘‘ iÀ-{êëëO°Ö¾ÃZ{c‰3™Lf=p§1æã‰PDDDFŽåÉažÑº3ܹµ ±ˆˆˆŒ!nUe­àyÞ¶AÚµcöÉÀDFÒ’%KÚªªªnH§Óu)2•••Íëׯ¿qÊ”)á,0 ?bÀŒ5wi½³lÛ¶íà Œ;‘¸ ˜<'‰'³Ù¬ÍMÉþôžçµpáÂòÙ쇀ÿ-PŒ"#¢©©©-îD¤o¹¥zŽ‚Y<øãg8é!àCh¾3JD×:&)~MMM!zŠÈ7`ò¼lٲ;ïÿÄóQß÷oµÖ~§¤¤ä™l6ûr"‘8,›ÍþS6›½Øß󣳈ˆˆì¦ ¢ùÁÝU‘‰~6@Ó¬ÁÔ¬¾úÜÇF+6‘b6àšg€0 /±Ö>|Âs6›}hÃpƒ1æ{ÀLàÊT*uW¡ƒ‘=ל½±#™=É`šècVð¨5欛¯9G…¡DDDryX±bÅ+A¼{ëÖ­s€cŽö^°Ö®Ê )Z‹-*kkk» ²²òVUÛ). ,8 ‘HœmŒy-“ÉÜw<Á÷þõCæÌî><4áû0j¬ÙîYó§ÃyðÁàýž”.¾ïÏŽ¢è”D"±5•Jý&îxdÂû𹎿üxø1ðôh5Š*-Ã<çí@f€ã;mÀvà1àN 9^_±WW»€S Ðçˆ4y†7Ö¢}?÷!2æ$“IÏó¼YqÇ!"}K$ežçͲֶÄËDÓœ½XwRܬµS=Ï›E‘ †I18xÇÚU_àß Ð()Ç%™G óÜ© íkÖéZ \d‡ÙW_&ŸÇ}OÞÒãXç÷³èë* )yë¶lÙÒ¾ï¾û6ÁƒD¤ˆxž÷е¶ÉóÕ|ÐhÆŽˆôò‰¯®™™©3p¦…=Ì6k£ ‘YœýpÜñáÖÖþðM\"xð·X#ž¾‚©OçËc¨H ˜<û¾?ø ðD†ç­X±b¼-¶™P6¦Ž9ÄØŽo­µ9wóaošO54(s.¾nÍå6ä?ÈÍ^1€Å‚1'B´pîµk¾¹ÙNþü½Á™qôæç/Sûic€÷ãòž#qÓ¾7ÿ üWÈj §oÆ}=¶âFnoš½s&pp4P‚+rö§\Ÿ[óÚÌËõ0…®©Ô?¤0S¡ïË»xîöã¸QüUœûà, 7Âý1à=¹cûÒû÷p_çžf—'⾞›rϳ–¾wˆèt|®¯ãpÓÎ_ÂÍ<¸-w¿§ÙÀG ,Þ›îßœëó „ÁGžÆý0ý§gË‚ H677Ÿ N§ïgà7žˆŒ²Ü¡ã1;S©ÔCqÇ3®%²—àþñkí@cÁâ‘1¡¾¾þÀ(ŠŽ²Ö¶h—™{íÚÏZkÿs€&žÅ3LÛ4`þ(…ÕŸÎâT¯ãªH÷T‰KrOíãØÅÀu¸„ì}?¸ø@Ç>•;÷S¸$<_nÝñGû8onö¿À3„nÈk35ïóõ&yÞ'ï~g=’™À¿ã¦¾ßMÿS¹¯Î~üÝcß?ïóé<Ͼ‹[ƒ¯ø¸‚c=/È”ßÁý¬õœ^…û>|÷½Êwt.–§pYîÈÅ—ïSÀÀÿ¶ 6o~;€µ¶è+Ÿ‰ dûöí%¸+`gA0.Ö\ˆŒ'žçíœEQQoQ1c‡[Ÿä„ç–ÍØ¯ ÁȘ†aîïè qÇ"ñš¬9Ê`o¼%€½xnp÷9…h@§_ÈÝ_¼ÚãøþÀ¯q‰s;nz÷ûsŸ_… ž‰K~ßÞãܽ€_àç,.Ñ=7Âú/¸QËC€ŸÓ;1ÿW\â¼W üŸq£sÿ& ¸‘W€@]ë”_Í}^jzüiy÷ÉÝ®ÆÀ&‹ú9ï\¢ p3ð.Οåû]±?ÑãÜI¸‹µ¯áÖ¨_ˆ+ZÖYÜìÜ×6_7R¿—8ÿ0×îÝ@ î‚ÉÞ¹Ø/î'æé¸¯í$à&\Â\ü!wü]¸ïÓÀ#Ïëš›››1çㆻEƤ-[¶„Ó¦M[FEŠLIIIkEëŒ1*NUh–‡{J”˜tnZ›LPÙlöåÒÒÒu¸éš2±]Á0vì1&únêk¡,ÅÕeÊW†›~}lîó[€/öqî5¸©ÖYà\\"Ýé>Ü6½÷ãF§q:ÿ¼—P[ÜhñyçÞŸ;÷÷À›pIäQt˜ÎÏÝÀyçý—d>†«z}1ðÜû.›òüaÜ(zº×3Rþ9¹¾™»ßœ»6ðIÜņž>›‚þ"îÂAG.Ö ÜÚéWé?vƒ>î£Ú7ã¾&3q_ëüYÇrƒ»PÒóëù=Ü(ùi¸Ñ鵸>ß~¹×öº×÷ºwáäÔÜëZ4à~ÙÚÚÚjc̵µµ7XkoÏf³›rEÆŒ¦¦¦vஸ㑾544´ ÷è(±-Ã-zj½%ÎܪU«6›ãŽCŠ€á}Ã<ãÔEßZ[¶ôòs[7¼»ÙÞ4A¯Â‡å¸ÑEp£Æ¿¦·M¸jÓwàÖÑž܃«z}Y®ÍítOœ;ý=׿—¸=™ÏÏk7-wÛW1Æm@-nyÍ#} õôžjžÀ%ìGãÖwZL÷‹«pÉóI¹¶÷xž¹¹Û[q‰ópý+½§ƒ·á.€|w"ß§s·Æm[ÖÓë¸Qé'q_ÓKè>¼ÓÒ»0v6×喝{ò€ÉóÂ… ÷ ÃðkÖÚƘ«Œ1W•––âû~¯¶ÚªJDDd,0Ð÷Ú¾þl˜Uûìß ˆŒ9ÃlŸÜþJx}† ké=òì‡âÞJ৸‘à‹éZ¿{2.7:ÙŸÿ‡KÀ&ã |݃+LÕ¹6v s=0wngòüntõ\býÜhuçÈôÏ(¬÷¡Í+¸ ·÷xü'¸â[Óq£±_É;v,®X¸iÒ»ãž~.w»7.Ñs÷ß™{ü{ô_ÓèÜì÷à¾}%Ï¿ëçÜ-y÷÷Ò” cÌ&ÿr(Ï%"""ñIDÑÊÐó>˧]ZcÜÒJD&œWé¿juŸ&Mš´½@±,¢ÿ}ž÷Æ(ÖâŠ~=Ž[K ]¤¡kMm_:pksߎKt‡s®Åô:0ï\pë©ïÁ%ï—æ>¶kpÉúÏ<ïžz˜ÞK0vâê]mÅ⮥ïJáí¸dÿ2\ðkèJZçånÿ‚[»=\!.iïKçÌCWò\™»îë¶;Vá’ç™ÀÿÁš{¸‘hpk…wG;ÃÛgO¿ù†4Å|°jÛ}ªªªJ Þª0.\¸—çywïòÍŸ?’çy?À}ãNËd2ïI¥RaXÈÊtR¤ZZZ¬µ¶ÅZ«¢7"E¨´´4›{Æ5:1¡˜€hf͆‰,gbø–Î-)-–¿X˧wì]vÊŒKžhŽ5P)ÖÚ]ÖÚÏó 9•TÆ€›ƒó~ŠòšÜGwîµ£Øf¯tæÀ{óí=\ÅlpEÀ†s.¸¢ZÐÿžÈ¯á¦j_Š›†|:ndܨtÓŒãÖ˜»ý0îkô‘Üçkè]ͺP¶Ò5R}ô@ üû0$ƒ®wò}:ð[ºJ½oÏ} ¼x_mmí{3™LM?O±Ç|ß/1Æ,²Ö^mŒÙ Wyîm}µ-++û¸µöcÌu©Tªót:ÝàûþÙÆ˜óëêêŽM¥R+T¼R|wÒw9})Ë–-{½GGݵOß Ü °yù[¦½º7;Þ2g}û€'É„´|ùòÇp#e"„‘ùd³wbéw&‚¿ëßô™9mýµ%n‹$p‰jgá©?â¦ê–àF~×õsþ?Ó5jÙYÌ꯸QÏ)¸=…ÓϹ'ÓU`íÞÜí;q«ŽÎÏ/Há W]•×þPºª@wVç.†Y”·á¶…:÷::·‹êoÊvg’;’±¿ ü x îû°¬Ÿv§äîß»'%øïâç´çy•étzßt:=³¢¢¢Üó¼w6Æ\RWW×ßFÙ{Ìs¸µö¿€XkO7ÆÜÑ_[k홹sÖôqx @EqnÖ.""Rt«YÿŠgŠÛ‚s^ÝMþ€uÛ=Õý¨i®}ÝN~WcpöÆÂË·7.—9>÷ù÷é*µ ·…À¿à°¾ÎÿzîþÜ€"¹çèL}àŸú8·X’»ß‚ÛkÜÔì3pIñ§{ŸÀ[s·°!ïñÎ ûÑ;+fä>ö¡ð^$—[áÖPWâFœûÛÓ»3öýû9¾»:g¿è+õ€oá¾>¸bg»mÀ‘çšššƒpWb~šN§ëÉ[ÀA<¸`Á‚sKJJŽ¢¨~OƒéO"‘x- Ë9äÛƒ ÈÖÕÕ ´Þæ€l6û\ÏƘ笵cŽí}šˆˆˆˆˆ ŽÁ™Yà;ÀwªƒŸT„^âÈD¯Üòåó7bÌpŠ>í©¥ôÞªj_\â{]ka7ãö Îw.é:7âû\B¸·Lô«¸AĨ¦k+)pžÎÇ­óýpnúõ\1°ësm}º*WoÅ›|7z½—œO΂\Ûеº*B—?ÌÅû0îÁƒ¹ã׿=G!5âF|ÏÊ}~ýÞêŒ}oÜëú_ÜÖ]{:£%| ·ïô-¸¯Ã­¹þ޾DמÖÝ/F Û€És"‘x«µÖ3ÆÜL?•ÏV­Zõß÷ï6Æ|hOHn:ßP÷ Û°žçõ*snŒy%—<0¢ŠˆˆˆˆLP+ƒ5®FÂÕ£Þý`3J-nÔw!½·#Ú‚Kü~‚+$öíÜG¾mÀ\‚œï¥¼sÆm‰õŸ=ÚìÀ­eþaǯŽÄmôiú¾W)¼çc¯ÓpIë¸Äþaâ±·†øàÜçUÙþnÚüT`NîãUö‹™ÚÚÚŒ1XkŸÊd2·ÅLxÒ5]·/;q‰ÙS¸å´}7B¹·6z.Gz—tßLÿ°žÄtÎÃ÷:7=x.Y\E÷‘ãN¯â¦n_„+¸õÜôvÜÞ;p[IõÌÁ^Âm uy.æt^´pR¹ûõÑçót}ÍžíãøîÈ?j€ÿÉ}ôg+n4ÿrà(\"ÝY€m}.¶¶‹zŠ®ø{þÿ\¡µU¸iïSpGîVÐkyà¾OÏÙמÖqw¶ym°‘çõÙlÖc>ŽVïåÒK/Ý/ Ãà¾ÑŠ•wïÅZ;)w»«¯ã9ƳעE‹ö^ºté«ù.½ôÒý:è íùÉWnïÃäK/½ÔÚÔÔôÆz±ªªªòéÓ§O ÃpW:~ãâû~I"‘Ø+™L†êcôúˆ¢(™H$’/¾øâdòöÌk¯C}¨ñ؇µv ŒÆÚëPêc¼ö†a·õ•cõui®ÿÎ}Œ”6\±©þ N ¤Xžûޏ=÷1OàöXîé9 ~€óž¢÷Höž2tâÊŽFëû‰á^/äõÇÜG,n„¿ç(ÿ@é'ž|Oä·0y^¶lÙ ¾ïßTù¾S†_]±bÅÓ¡ëêêŽ Ã0…[ð #ÐBz ØÇ÷ýÉù¿ìŒ1ûYk¡k“ì^Œ1“¢(Z°sçÎkkk¿Ÿ, Ãy@Û† ¾NÞÚŠD"ñ‘0 ßwß}›p?ì¿ÿþï Ãð c̃ä-ž÷<ïÐ0 çg³Ùéñ& Ãð õ1²},Y²¤­¶¶ö÷až œ6V_‡úPã¸9ÖÚ:::Ry]ŒÅס>ÔǸ죵µõ¦öööqÿðÙ×c³öÙgŸuµµµOç=~R6›=É3¤™ "Eètà\þU¬{R¨A߬žç-Œ¢èX`q"‘Xìûþó¸²à3¬µ{çšý ¢¢be!† @eEÓè1üEÑþÆŒ1›û>Õ5³Öî°Ö¾¼k×®ùÊË˱–"—H$vEQ”¼¥ˆŒ6cŒµÖvä¶•‘"ãy^ØÔÔ÷–CcYEÑÖŽŽŽLž<ù0cÌ6ú©+$R¤ŽÄM3n:4¸Âa¯ÅÐhÒ4‘K.¹dZ"‘¸ 7|vîá,°ÎZ›Îd2«Å7~]]Ý—­µ×c>‘J¥¾—Ì÷ý›€ÅÀyétzMc×áÊÌI§ÓMôÁ÷ýû1A*•êY@DDDDdDù¾¿-›Í»råÊæÁ[‹Äî>º¦jƒ+¨ö6ºïW=n išHnªöUÀUk=ŠòJ™1¦ÉZ»ØZ»7ÍÆ‚[o‚[Ì¿½¬¬ìqÆ("""""2m¢+ynÆUÍž‰3 1y®««{§µö àkétúq eáÂ…{e³ÙG†aøoùk¡ã”J¥þàûþ]Ƙó}ß¿¸Á³WEßfWõ,ð ãߢE‹ÊÚÚÚ.¨¬¬¼UÕ¶EŠË‚ H$gc^Ëd2}¨‘øø¾?;Š¢S‰ÄÖT*õ›¸ã‘Ø\Ü„Ë#ÿ‚+˜6axƒ5¨««;ÇZû{àSƘc;ooo?Øøl"‘øÃ¢E‹öî÷IFß\\iùO[k0ÆœÜN§¿oh‡d2éyž7Ëó¼YqÇ""½%‰²ÜûsFܱˆHoÖÚ©žçÍŠ¢èàÁ[‹È8Ö†Û ëL°ÄIžsÛ‡|ØaŒ97•J½1°|ùòg+**ö7Æ|8jçÎ_*t°víÚõíD"1;‘HÜÕ×ñt:½=NŸãyÞÛŒ1s­µòÑÓ***^ÑH¥ˆÈØ5?¸gRhÚæÃyX{ð:–G0ööÕלwOÜñ‰ÈÄãûþ>@IîÓ!í~#"ñ,y~Ü&îÀ÷×Ès¼µö#X\Œ1˜œH$öX¿~}KÌ!‰ˆÈnšÜõO‘y½ÉÀŒn‹v ïS3ﺵ?õ¢]7n‹-H™p²Ù씲²²IQ¤1‘±b°+]Æ÷ýÇC¢(:sùòåëz6ð}ÿ2àÛÆ˜e©T겂D9Š´ÏóøA²¹¹ùd€t:}?Zû.RTª««§&“Éã1;S©ÔC#ñœó®[ûv\ÁË)ƒ4ý“g'ŸÑœ¹s$úêë댢è(kmK&“Yw<ã‰öy;y¶Æ˜+¬µ?ó<ïO¾ïßgŒyÒZ» 8x;ðV`k"‘¸¾àÑŠì¦íÛ·—gAð@JžEŠˆçyûgEQÔ‚«â¹Gªî¸#ÁcÑ-`KœÞ™×¿{Ú¯Èx†a…1æ,à)@ɳˆLHƒnU•J¥~nŒ9x8ÝZ[ \‰Ûê-ÖÚµaž²lÙ² «ÈnÛ²eKhŒYgŒY§ÄY¤ø”””´cÖyž÷èH<ߤ¿Mý˜· ã”ËýÔC%ƒ7™˜²Ùì˹¿£OÇ‹ˆH\y 7…ù-—^z雳Ù워1{Û³Ùì_5ÅDÆ‚¦¦¦v Ï­ÍD$~ -Œä{ÔDg óŒýÚŸñ¸}+E¤‡U«Vm6LJˆHœ†”ºk×®³/^üÁ%K–´,R‘=PUU•˜>}úL€†††gâŽGDº›?þ¤òòòŠ0 ³étzÓ?¡1b©Æ!¥íÝã~EÆ©êêê©eee„aØ–N§Ÿ;‘8 Z0 ø..qþŽ1æ(à§’ÉäUÖÚµÀY­­­uŠqÔcÊ|ߟìûþd´qý¸PYYY†á¼0 çA0”Ÿ{EÉdrz†ó¬µŽÄóeK쀡ïÝlì«¿ôá—G¢o‘ñ(‘HÌνGßw,ãÁ¢E‹òÿב1bÀ$¢¦¦æ `p{:þt*•z xc'÷†††g=ôÐáÖAÏ+h¤£Äã‡xž7Ëó¼YA$âŽIö\KK‹µÖ¶Xk[âŽEDz+--ÍæÞŸÛGâùnÿây-À†Ø¼%qÕHô+2^YkwYk[<ÏÛw,ãA[[[EçÿšÆ ÔˆŒNÛN$oµÖzÖÚô×&‚¬ïû¿ætpq°ÖFÀÆT*5"Û¥HqhllÜ |3î8D¤o¹íGô=ºúšsSó®]sðúŸEôRdì‡W^sž–sˆ `ùòåÅÇx±|ùòg;ïû¾¯-4EƈGžs‰$žç vEl 7¾ˆˆ•ÕלË~ tt1/øN”LwëWÎû}lŠˆˆÈ˜1XÁ°G€¸øI_ ª««+€sŒ1pl"""{ìæàÜß¿«ºéŽò)¯–Ïì ±£ýØÏ7͙ƛˆˆˆŒ&Ïétú%ß÷`­ýDmmíÍÖÚÈV/Z´¨lçÎgc¾L‹¢(5‹ˆˆìަÏÌi;›ݪª½½ý²ÒÒÒ7cæc:‹‚uìÚµë5cLIîóå™LæöÂ…)²g/^\ÞÚÚz@EEÅuADƒ#"£§¦¦¦Òó¼kmK&“Q}‘"S[[{‚1ækíS™L涸ã‰Ã [ö466n+++;¸xx(ÁUDý¥1¦*N×¢5Ï""""""2N :ò °téÒ]À·r"cÎ’%KÚªªªnH§Óu)2•••Íëׯ¿qÊ”)º+R„¶mÛönkRÕ ‘ kHÉsOA$7mÚtàŒ3^ ‚ ;ÒA‰BSSS[Ü1ˆHßrK)ô)RMMM!zŠÈ×ç´íªªªD]]ÝE¾ï§æÎ;¥óñ ¼ÚÚÚë›››[’ÉäÖæææ×|ß_êûþäÑ YDDDDDdÔ”rçîÆù#ÓP¬ÃÅ<Ô~?¼|n7ú:'wîõ»qî˜ÑkäÙ÷ý}€ŸXkO˜2eÊ¿­ÍÍÍ7c®ÄMÙy¨>m­}kï'E˜Ƙ7×××oˆ¢è¯étºc°“DDDDD†¢¦¦æ˜d29 ÃAkIì 0+w¯Ý8fî¼½G,¢¡÷»?°ÏÚ|Øw±`82»yî˜Ò+y¶ÖÞ`Œ9ø›1æ¦(Š^ð}°hÞ—N§ïË8ÿÐsöÖ­[ç£{¡„ÖÚ'R©Ôƒq"#gÑ¢EemmmTVVÞ:N.ôˆŒ ,8 ‘HœmŒy-“ÉÜ9’Ͻ!5kF2a>æ|à0 ÃÀÃö¶Ž×MæM—?½k$û|ߟEÑ)‰Dbk*•úMÜñŒuË—/¬ó¾ïûúŸdüÛ€Kž·ÅH?Ž~LÛsgåέшŠT·+]‹-ÚÛS lÉf³'§R©étúukíy@ÒZûýt:}@:~=Š¢ËkŒùÔ¨G/2DÉdÒóE‹¬áL`:n+Û¬µéÃk7üwÌáÉÀŽþ 8+÷ù:\¼ßÎ}3ðuàüÜçËwÈÇXtº%Ïžçl­7µà óçÏŸœ d;::úšªó2nN½HQÊU ]w"Ò·Ü,§{>»êðI&´ ôS³‡#²Ùë…#Õ¿ÈxÓØØ¸âr*£ÌZÌæ³¯³6ú’í~roà"cÌEÏe޼-JfkŽX°qgB˜œüøP Tá’·q#©ßþÞã¼Ëq#¬pktûs6p:ððŸ}?·œõ4Ütì§€;Ûé{;·ë€IÀO€ûó¿(–âŠmÕ燯€§ˆõhàÓ¸dx_ÜßÒ 0ØÅ‹/âç÷µú×ÜëJòü/¸ÄÙæúú\.Ö‰•<“ûfGQT–ÿ`iiéiÀdàÜ/ÏžZ ¡ˆˆÈ0%²%Zcj{c™ÿÂêã®éEÉ2k™c v„C8˜‡KH¯>ÐãøûrWwç=~p°¸7RÞ—Ž¾ÑDZïà quz+p!°(Û?zœ³—do¥{ò¼˜ Üܼ¥Çyï.Ã],ø)½]ÜD÷ Åo>–{ ‰€&àà±AÚödŸá’ÿ‡†yî˜Ö튼µöcÌ[óÏ›²ýËžOpÉ%— AÑj‘¸DƾgX'Ê;²¯¿³@ለŒ›3Gg1_RcËG7­<²ª€áø¸ÄùǸÄs2p*n òÜHïñyíq‰ß$àÃý<ç[óÎékòçsÏýå\Û〯ÀI¸èáVP_Ž«v½ø(nÆïW]¸‘é¹>ó}—Ü{Àop Ž.þ7²ÜÄÜ×à|&Xâ =Fž+**þØÜÜü`~mmm:“ɬ_¸páaÙlvîí=Î7‰Dâßr÷ïF¤HAlnn> Nß#~TDö@uuõÔd2y¼1fg*•Úã?ƦûˆÀ„ÖLßÓ~EÆ«úúú£(:ÊZÛ’Éd´ j³$.gxÉá¸QÞB(~„K;kÚ܇K>ÿŒ[›{.±7-ùà\¡¬U}<çüÜí#ÀÿôqÜÖæ=öð°:÷Üex¯ù@\2º&ï±{g€•¸õägâF{Á%Ô7æîÿ ·Çr6÷ù\2}Ý/ô´'õ &líƒn?øAd1_ö6ÆRý‹Œ7«V­Ú lŽ;) -¸âWC65[þJbh Áv\µìèþ·`.ž‡›º_M{nîv ðB?ÏûÄ}v^\šŠ[oܳpXšù´+w[š÷Xç¨ó@³"àIàCŒA† ÏäÜn`S_Ç–.]ú*ðñB%""²'ŽX°qçÆÌ¬zc¼»|mÞ³^2yÍhÄ%"2<\4ÔÆþ÷ÀËÖjì`xm¹Û½{<¾ —<Ÿ€«NýH®Í¹ã} ë4ÐÖ[ù;6 gªzÏi׃Ù7wÛ6`+·Ý•Œ ~“ç ,aŒys}}ýv€(ŠþšN§;âJDD†çðÚgÖnÊÌþ„5f%®k_5!TÖ<>ì5Ò""»«¦¦æ˜d29 ÃáVfŽY”oÈÉsdÜOyO – î“»í9ü[\1®Y¸ªÕ_ÄUßžŒîkýq§öAžšw¿û¢wþÍêY»§IŒaBRòÜ[h­}"•J=8xS+ªªªÓ§OŸ ÐÐÐðLÜñˆHwóçÏŸT^^^†a6N÷9ëiw̨Ýðƒ-™#ïá³ÎfíÀÿ¸ýµ½Ë–¿eÎúö‘êOd¼ª®®žZVVv@†métº¿5¦2DË—/c{ ß÷{»*j3kžùÍs™#oÃðÉÁÚøã?¢}Ò çÈŽUЕ<÷üßÏâF—¯ÅUÆîLžnÃýèÏ¡;&wû…õíü;y4nMwõ|f0† IɳL•••¥­­­ó‚ ¸.‚1õ‡Jd¼K&“ÓÃ0œg­m¾9’Ï]Yûô`qîCDvC"‘˜†áÖÚ§pÉ…L`Þ>;k£×&•aùhm ü1kà ÞY·®38OÃM·î+Q½0wÛŽÛΩ§›kp ø;é**6Дm€Ò÷6T] ø½ƒ<ÇžZƒKøÀíkÝW‘Ì“p[`ÉcÓDDvOKK‹µÖ¶äþ1‘"SZZšÍ½?·ÚXDFµv—µ¶Åó¼ »¿«t9lΖ¶ÕOÏÁp†ÈÛ*Êb¶–O¿îsÚ¬Úgÿ^àP¦ÿÕWˆÀÕ¹ûß§ïäú9àžÜýoá¦l? üu>? üS7 °lçØS:w§ø&ݧ‹ƒÛú¦Ç0!»‘çK/½tV†ýV•«¨¨¸3W M&ÆÆÆŒðh–ˆŒœeË–½€Þ£"E+7Íø±AÊ„a ž¾¸có•寖8¹têKÏ{¸uГGV ®²õwpÓ¥ÿn:öA¸µÎWpn#nÄùݹÏuîôë\¿Æ%ð €KrÇ2¸}› )|ÜÚí€ûsñ<†IÿW\‚¿ —HËwÉsE5¸i }Ú´iÓÞhÏ3§æ^ÿ³cˆ¼#6|ª18ÿñ¸c‘ñí°9[Úp#¹£í!ÜÖS¦kÊt§§€ó€8ÿGÀR\õê,pûúü4ðuºoqÕipÙžc$ü®)äo~Øãø7pS·O¥x&„ñ˜<oŒÁs9]û¢½!™LT^^DdLšwíšý‘yKgÝÈxÌ»vÍ£ÆÚ½98ï§1‡(""2Òvgá¶ún ðs¸5ÁßcàÂ_à¶zº·>únúßÛ¹¸1wÿ.àÀ"àd\>õ8n»¯µÇ7àF€ÿÔãñ%¹Ç Æ¥¸}µÿØÇ±ŸGõ¸÷éÀF`5îkp)pß ÏŸon ùýClŸon´¿Ð£î±wɳ1æD`S*•Zw,""£an°æzàË®àf/oµÆüdÞµ?»~õ5ç}e”C)´·oóªÝ8·8=wÿ»´ë¾Ðã±Ï£Ÿ¯õóø5C8÷«ƒy€çoÂóçû·a¶Ï·dÎ3ÆUò\__`E?Ž;).‹/.omm½  ¢¢BÕ¶eܘ{íš¹¾‹™ÚÚÚŒ1XkŸÊd2Eù{Dd7ÌÁ­—Þ€ÅиJžÃ0|»1à/555Çyžw î ñ?¿P¡0O}kmÙönè{Çî,üGUpGSS0Gû‹ˆÈDõnàïÀ;è*TÙ@^Åp‘þŒ«äÙ󼬵s=Ï»ž¼9ŒÍÍÍëëêê.L¥ROÅ ÄfÉ’%mUUU7¤Óiýr”qa[Kt†ÁT ý [1™½Î~Y¨˜vWeeeóúõëoœ2eÊЮˆÈ¨Ú¶mÛ#À¸)²"cÙJº¶”x’áOo– j\%ÏÖÚ:ïc>šÍfN&“3+­µ°Öþ|îܹÇÝrË-£]B_Š@SSS[Ü1ˆŒ(ãf®éEÇQ„Ésn)…Þ£"Eª©©)DïQ)ÿžžßsŸ¡+y~7uûõŠKƹq•<·Zk3Æ,K¥R/å{øoß÷¼§¼¼|ðíøB¶t¸Ã´‘Õ~""2æ}.÷±;ÎfáfQl©€dbWÉs:^ƒ+ËÞ“ÅMÇxµötNžK­µÖÕÕ”J¥nÍ?P[[{À^{í•^²dI[Þã*=Ï[›?-¼¦¦ædcÌ»Œ1§Óé{ò¯4Æ|Äó¼—Õ‡úPêcwû ãÕWIîÍp$^ß|@mmíÅô:Ô‡úPêc"÷Á8û| °¸a"Ã6‘Þ¬›Œ1ƒý§™·Ö¯ÿ§üQìx饗¼çL5ÆìEQi·'J&'EQ´Ÿ1¦¼ÇãÉ(Šö‹¢¨£gçÆ˜ýÔÇÈö±hÑ¢²öööFQtL"‘xz¬¾õ¡>ò/Û¹ù¾{‚Iôì£í%­Ïl0Æì_L¯#×Ç¡QX[[ÛšÉdî,Pcþ{®>ÔG\}¼úꫳkjjNL$[S©ÔoÆê눫`zE隷¯ß¯óAkí ÖÚ·ÒÏ>ƒ"R|ÆMò¼pá½²Ùì €—N§öÑdFîvË@ÏcŒÙEÑêl6û›U«Vý#ÿXuuõ€Ù³gw[óSZZzW[[[Ùk¯½Ö’ÿx{{û:àÉd2ÙmuIIÉó­­­ikm¯_¼Ùl6­>F¾d2éíܹÜ:—ÆêëPê#ÿñ²›×ïœü¦›ñJ«{öцRûúímÙlQ½Ž’’’çÛÚÚ~àyÞEÖÚùÇÆÒ÷C}¨ñÜG2™<˜EQ8–_GÜ}ä×_©®®~ øi2™œÓó¹D¤8›+]AxÍÍÍÍÀAÀqétú‘üã¾ïÿxŸµöÃù£=ù¾¿1&H¥R¿*pÈ2Šªªªûî»ïÑ™Lf}ÜñˆŒ?¸kòNãýxç@í,üyçÔÖÓ›>3§( þø¾?ÙZ{„çyíÚA¤øÌŸ?ß’’’C£(Ú±bÅŠçâŽg<ñ}[6›=våÊ•ÍqÇ""7É3@]]ÝUÖÚ€õÖÚ‹2™ÌúÜ/û7ÆÔ[kï?ôÐCOËUuí“’gkª‚{ö*7¯/>Eïß둵ܺ“É—5gîˆ!<€’g‘±cÜLÛ8äC¾ÞÜÜ<¸Ôó¨ïû¯ûáþ™¼¯´´ô‚g‘±(—Ïûd°öÏDÌ›­ÅÏ‚¥&J0ïÚ5ƒ½aõWÎ]16î8GÓs+f½ÇXïú¢Ó Æè Šž[~äoÁ^=³fÃýqÇ8šššJÏój¬µ-™LFkŸEŠLmmí Æ˜ ¬µOe2™ÛâŽGD$š&""cÊÅÁšÓ"ýç€ò‡Óxñµwß~FpÏ„¹8ø\æM—c½{-œA÷ßëp&˜ß>—yÓåñD'"""2>L˜.eb[²dI[UUÕétZ£ÎcÔüàîÃ#Ý ì7P;kìÇfÒºøÜèDŸM™#?dý`h–ÀØo<·üÈggÖ<}×hÅ6•••Íëׯ¿qÊ”)jÆ€ÈX±mÛ¶G€'€0îXDDâ¢äY&Œ¦¦¦¶¸c=]LJ[‹¹b^°&½:8÷ɇœ‘Üd¶,aàĹ“¾aƒ3î6Á½Ù‡6l¹¥zŠ©¦¦¦½GEd‚Ó´mæ~ýS0|d§$1|¢`çÛ|*pÄ0N™µñÐ-ï)T<""""ã™’gZ³ÇÐ{óÀŒy{a‚)–w ÷”„lj…EDDDd¼Ó´m™-ZTÖÖÖv@eeå­ª¶=öXÏ–;”ÙÉù'ES M‘°^9Ã,*Y3¹@Ñì‘ H$Î6Ƽ–ÉdîŒ;éÎ÷ýÙQ’H$¶¦R©ßĈH”<Ë„L&=ÏófŇì>c¢-ØÄpÏÚT`Š„ç±Ù³¼–!Ú\˜höL"‘(ó3 !‰ˆˆˆŒKJžEdì0Æ>Gù\ƒý/ ¿Äø‰ÈF§Ýœÿ—Ñ -.G,ظ­Ôpš¥ÿ)êî.Éz§Î®{fûhÆ&"""2žhÚ¶LA$›››OH§Ó÷Ã,³$Å"7šü¹yÁš4†O8Ñʱl6†Ÿ?MþñDqÎwHõÓÿÎÞ´üM§YËG±GXcŸ2Qâ‡3jŸü}Ì!ªººzj2™<Þ³3•J=w<"Ò]}}ýQe­mÉd2Zb!"’’g™¶oß^œÁA(yãVç> qÇQLfÔ<õ;àwqDZ;<ÏÛ8+Š¢@ɳH‘ ðÂsðªO "”’g™¶lÙN›6m€g‘âSRRÒEÑ:cÌëqÇ""½e³Ù—KKK×/Æ‹ˆH\”<Ë„ÐÔÔÔÜw"Ò·†††ô)Z«V­Ú å>ñ""£EɳH« î(-7{½¢wcÍþó‚1ü÷ÍWŸýÆh]DDDDd”¨Ú¶H‘š{íÏ>0ÉLy ìZ0WcXö:kí}s¯[û§ù×­y[Ü1ŠˆˆˆˆLy– ¡ªª*1}úô™ ÏÄÏ`.¾ví'-öf Ñ×q'EÖ>0ﺻþyõWÎÿÃ(‡'2âæÏŸ?©¼¼¼" Ãl:Þw<"Ò]uuõÔ²²²Â0lK§ÓÏLjH4ò,Beeei†óÂ0œAQÿÜÏ¿þ®7YìrúIœ»˜½°^Óܯÿbʨ&R@Édrz†ó¬µÆ‹ˆô–H$fçÞ£ï;‘¸hä¹·„1æÍõõõÛ¢(úk:îɪnº£|ò«{j=;Ã`Ú-<²ú+çüu$ûk>Ü5=‰9Íó˜Á«&²¬Î±Ñ§––[RRÒ2RÏWHQh¾€aÒ›꽞õ%…ŒI¤ÐJKK³-Àö¸c‘Þ¬µ»€ÏóvÄËxPSSsL2™œ †aQ_Ô‘.&îŠïû÷c‚T*õ«îÔC%má‹ÆšÏ{ç3ð7cùlcpîÏGºßb67øÅýº1|’Þ#­wGž·øÖ«Ï~"ŽØâ2ïÚµ/þJ⊠IDATݧüvõ5çžQ¨xDDD¤p|ßß–Íf]¹resܱˆÈÀt¥k”,úÖÚ²ÿûZc͵ôHœ,ÖÌ»vÍ1„‹êàg³ŒÉþÙæÑ÷å³½(úÓ¼àî÷Œvlq™ܹï0g€Ù FDDDDDÞ äy”lo‰–`9kfpÓÜ`í¸_OtFpO2kÌÀŒAšîƒ‰~¼àßÖ0qÅ-œ2yw–Œè²éMÉó(øTðó#ÁøClîaì  ¨Ì4¯ÏŽbóÂ{e!ã)·\ùV`¸k½ÿVˆXDDDDD¤‹ †Ïd?fÊÉ] œ4÷úŸqËÕ|¶qÅ)2Ì1vX§Ì>¿»ý-^¼¸¼µµõ*€ŠŠŠë‚ ˆv÷¹FÁ€!_,0ÆÜQÀXDFEÍÿoïÞããªÊ½ÿžµçÒPJÓÒ iÊÅ£€‚7|,.¢€†ËKšNö¤­Q{x a+¼ µJ¥ÉìIÛHAñr=Š7D=JUÄ‚Ð-M"eÚ4Mfö~Þ?2Á4—æ>{2óû~>|šîýìµ~»f9YYû‹UcbªšN&“_ :¨¶¶ö4¹HU·&“É»‚ÎCD®<窜2ÚcŒoF}ÌT"ŠÑžß1UÎÏ”0Æ Ë­þ>Âò?í;i/ˆ!""""šdœ<çƒèˆW{)¤Ø¯ õ¿É¬iÙQÓkÍš5étú–t:}K¯:cãuçÿj.Áð¯ìÙ¡Æ»$ué¥^>rM¦ÊÊÊÖt:}K&“I…ˆjkk{"NßÒÖÖ– : QPŠ}‚VŒšgu”×(‹XÛ&)N¡xÀÑ£¨ÿ»{í9ãzÿk*•êÏñùt‡sÞ¯®¼ñ¡·ß_à¼~»³6Ya¹fãué 5QAËýRkÊŒQ¢R“J¥8’zn˜äHó ¹²/{5F¶úÜ‚~q²3ªÿù¯;Ñó1""""" 'ÏùîZŽLôd‹V&ŠÆo8ܧTÙôÿÚQíüàþø?ä`ó ˆm¸áýϧ¿úúúhggçePYYyg¡ß÷LTj–-[6ײ¬óDdO2™ü^Ðyˆè@¶m/ò}ÿ,˲v%‰‡ƒÎCD>0,Oî¸î’ÝaµÞ!*÷ìèvŸüÆ ç¯Ìs´À4;çÿÖˆ¼Sß^¡Û|à¼;®¿à›ãí+ cÌBcÌÂñ¶EDϲ¬hn|.:  ¤ª3Œ1 }ß?*è,DDAáÊs­wÎ}ÀKoP£ç×ãD¤¢6~÷š‹ÛŠÿ‚í5_ÁP}ÛU7>ôN_ý÷È<¨ìöÅÿuÙQGýÔŸ‘™ˆ~ZZZºËËËSÀë&"¢bŒyUUSƘÑ@™Lf{8Nù¾¿7è,DDT lÛ~4Ÿt""""*~¶m·ÕÔÔTƒˆ†Ç˶‰ˆˆˆˆˆˆ†ÁÉ3Ñ0xÏ3•ÇqB­­­o×uÅàm£)¤Å]¸Ø3æ#NäÀß)оì—÷Œøæ ¹Wžò§¦¦fF(:UDö'‰Ç‚ÎCDª««;Â÷ýŪšN&“[‚ÎCD®GO : QP8y¦’ÐÒÒâ‰ÈfÙì8W§(UÈŽÊ]›X À¢ìˆürû†ãßœÏl4>áp¸CD6cþt"(›ÍîÎ}Žn : QPxÙ6•„T*Õ à sÐøìÜpÂU½|¥‡ÀÇÝ%ÞòO¼„{jhhhHƒc”¨`mܸq'€Aç " RÑNžkjj*Âáp…ïûÙL&ó׿ææýAg"¢ñQõ¯FvÕ½‹0m—øÖä¦""""¢RPt“gÛ¶ß,"·«êÛU"‚H$²Ï¶í†h4ú™µk×v‘ˆFo{òÄãïÄÑ£‚sÁÉ3M€¢š<Çb±“ü\UË|]U1Æ”«ê*WwuuUÉ%ŸTdªªª¬9sæ χFÏ@+G³º™? QhTWWO+++«ðÑÔÔô·Þí+V¬X˜ÍfŠH‹ëºí³}V6›}‹1¦ƒ}ä§Õ«W—uttܬª³Œ17'‰'§ây°ž>®ýIÛ/S©ÔU;ï­¬ó^›vÒŸþ6ï-Ïï™Õ¹å•#~ÒÔÔô7ĦÆy°ô‘Édε,ë½¾ï?‘L&¿6}Ë¿û`Aô ]D.PÕ­Édò®©z…ØŠ|1‹¨˜å`]±bÅ,yÀTõ¾îîîs×®]ûÚHŽUÕˆª¾[U/®««{kßÿDä\y×´iÓÂ}‘7ŠÈ»DdN¿¶ä¶/ì·}¦ˆ¼Ë÷ýÓû÷Ÿ«g“Ѐ™cŽ›ÊçÁ>þÑÇüK[:mûãƒÛOÊ>õêQ'LÕó`:SDÎô}^œû`EÙ‡çy¡~Û§äyÕ€w‹È¿ôý¹Ò÷ý÷‰Èe¬þmQa*º•çX,v¤çyÿàMšŽ>úèŽãŒøòMé‘ßd³ÙG\×ý]ß}ñxüH(//ïßÞ3"²;›Íð¤îîîÃáðfUÝÙw»eY{Tu³ïû{é3û˜ø>Ö¬YÓYSS³Æ²¬ã=Ï{aªžû`ÅÚ‡ˆü|ÿþý?RÕ_Låó`ì£Xû…B§Óé?è}£É”< ú0ÆìÎd2›“ÉdkïÆšššöp8¼KU/ïß& :ÀDZµjÕá™Læ×Nð9×u?7Ú6lÛ~TDœD"ñã‰OHDDDDô¶m·e³ÙS6lØÐ:|5©¨.ÛÎd2·X à+c™8 ¦h.ÛŽÅbǸ4÷׫mÛ¾zˆÒë]×½1O±ˆˆˆˆˆˆ¨ÍäÀ‘®HUŸËC*0õõõÑÎÎÎË ²²òNÇqü 3Ñ?,[¶l®eYç‰Èžd2ù½ óÑlÛ^äûþY–eíJ$Ãþ¼EDTŒŠfòÜÔÔô[çƒ S(2Ƙ…ÃWQ,ËŠcªjzøj"Ê7UaŒYèû¾7|5Qq*šÉ3ÑÁ´´´t———§€«ÎD…Ç󪪦Œ1ÝÃWQ¾e2™íáp8åûþÞ ³…“g* ©Tʰ%èD48×u÷c”¨`577·h :QŠêiÛDDDDDDD““g""""""¢að²m* Žã„Z[[ß®ë> @ŽDD}ÔÔÔÌ…B§ŠÈþD"ñXÐyˆè@uuuGø¾¿XUÓÉd’·XQIâÊ3•„ööö0€%–8Ž#Aç!¢cfXâûþYAg!¢<Ï«@ÏçèiAg!" Wž©$´´´x³gÏÞ ŽãL™Uç¿®?qF²CñN¨Ì‚Ñ—Dñ³—½òψoÎh¢„Ãáß÷7‹È¾ ³Ñ@Ùlvw$Ù àå ³…“g* ©TªÀAçíM'üÔû* s@ ||®Õ¾mÇú…ËŽYþܯ‚MI41Ò˜bc”¨”lܸq'€Aç " /Û&*@Û›}L w 0wˆ’ã¡æáÖÿ¾¼#""""*Qœ<˜¾Q kFPQÅ7Ÿßxlù¤‡"""""*q¼l›JBUU•5gΜc ¡¡á¹ óŒzæZŒ|ln¼Ð _œÄHD“®ººzZYYY…çyY×u_:¨¦¦fF4ëy^§ëº/‡ˆ(\y¦’PYYñÛƒÎBD©j—ª¦1{ƒÎBD^¶M%¡¹¹y?€¯c8fŽ¿ßmÔ‡uNB¢¼Z·nÝK˜c”¨T555=à© s‰+ÏDdþ¥-¶æž˜¤8DDDDD”ÃÉ3QáùæhŠe”õDDDDD4zœ<˜¬çE€>mX~µ`ù¶oOn""""""â=ÏTV¯^]ÖÑÑq TTT|Þq?èLCY®ýy÷„£8ê ¥ñ­L•4_Ùˆ&K,«4ÆÄT5L&yï3Q©­­=MD.RÕ­Édò® ó+ÏDè8{ëŸLØœ`€î~»÷@õÖ²®è;Ž[¶ý¥â•®ñ†K·ŒëêÜSB·L@d"š®ëîÇ(QÁjnnnÐt"¢ ña˜Éã¯p3†þ%Ž@¤îÐö®dc ÀÉ3¢Å]¸‚GT,Xº½é„ &9ÑxÙ6³dtäßý€ÇÚŸã8¡ÖÖÖ·€ëº¢÷q"*5553B¡Ð©"²?‘H<t":P]]ݾï/VÕt2™ä-DT’¸òLÁðå_FyÄ»Õû÷k{{{ÀKÇ‘±¶CD“Ã3Àß÷Ï :  äy^z>GO : QP8y¦`Žå‘]Ç4k¬Ýµ´´x"²YD6;ŽÃUg¢‡;Dd³1æ/Ag!¢²ÙìîÜçè¶ ³…—mS0i(ŽÅÞÑÏÕüuLÝ¥R©nŒé`"št ipŒ¬7î°3èDDAâÊ3B¿å!¿ççÙI CDDDDD4 Nž)bÄÅ(Ú%"î$Æ!""""":(^¶M˜_³õw4-r‰ ügóglÝ4žþªªª¬9sæ ϧ-"šxÕÕÕÓÊÊÊ*<Ï˺®ûBÐyˆè@5553¢Ñè\Ïó:]×}1èÅÔýÌ úa¹Þxúª¬¬Œxž·Ô󼥎ãðûž¨À„B¡9žç-UÕ‹ƒÎBDY–µ(7FÏ: QP¸ò€÷V–éžiÿÇW,ÑnUyâØØ¶?+ßÞpé–nWmo:áÞÜ{œß ÀàwIÌŸ±uÓx'ÎN§5§ÇÛMŽH$’Íd2iíAg!¢Tµ @Ú³7è,DDAáûnû±mûQq‰Ä'ºíÇo ϵÚ? àj‡õÛý¤^=?öì'ºß©B˜–Ê7”W¶Ì}#""¢R`Ûv[6›=eÆ ­Ag!¢ƒãÊsžl½íøhÄ´}%C”œâCÜÑt¿Ûúµ¼†+âÀ¶¼t"""""¢þxïgž„ÁÈç^ЯlO.âýDDDDDDD„“ç<ØÙ´èxì–1ææI DDDDDDD£Â˶óÀ‡|€5âTÏÜž<ñ¸ckŸ~~òR•–Õ«W—utt\ŸwÇ:ýC,«4ÆÄT5L&KòÖ¢BV[[{šˆ\¤ª[“Éä]Aç!" WžóAqʨôÇѤàÊs~Œ|Õ9Ǩò› ´f͚Ϊªª[Àu]®:˜ÊÊÊÖ-[¶Ü2}út :  ÔÖÖö€§ñ¿>’ˆhªâ-ÏŽöUl›Œ(¥,•Juˆ—»•‚c”¨@¥R)£DTâ8yÈ‘ëêêÚÀ÷ý?º®›OƒjpŸø¸~‡l=ÆÞ¶e<}QaŠÅb'‡B¡àyo£$š"8yÈSÕ§‰Äï&ªÁck¶ýaGÓñ÷øàHêE冉ꛈˆˆˆ KSSÓS½_Û¶ÍÛɈ¦NžóÄ ‡–g3Ù“X|ÐBÕÆµÛîÎS¬’Q__íìì¼ *++ïäÓ¶‰ ˲eËæZ–užˆìI&“ß :ȶíE¾ïŸeYÖ®D"ñpÐyˆˆ‚ÀËDò¤òª¿î¶}‡Bî0ØqÚù䂨³+ó­„B!cŒYhŒYt"Ȳ¬hn|.:  ¤ª3Œ1 }ß?*è,DDAáÊsÍmyÀ-îÂ<ËœèqPéTÈŸÕÊüà¸eÛÛ :eqjiié.//O¯?˜ˆˆ ˆ1æUUMcºƒÎBDe2™íáp8åûþÞ ³…“çTÚÏ=à™ s”’ÜSBù6¢åºî>pŒ¬æææ6mAç " /Û&""""""'ÏDDDDDDDÃàeÛTÇ µ¶¶¾\×}ƒ?´ˆRSS3# *"û‰ÄcAç!¢ÕÕÕáûþbUM'“IÞbAD%‰+ÏTÚÛÛÖXâ8އˆdŒ™ `‰ïûg…ˆò<¯=Ÿ£§…ˆ((\y¦’ÐÒÒâÍž={38ŽÃUg¢‡;|ßß,"û‚ÎBDe³ÙÝ‘Hd3€—ƒÎBDNž©$¤R©nƒˆ×ÐÐÇ(QÁÚ¸qãN;ƒÎAD$^¶MDDDDDD4 Nž‰ˆˆˆˆˆˆ†Á˶©$TUUYsæÌ9ž :¨ººzZYYY…çyY×u_:¨¦¦fF4ëy^§ëº/‡ˆ(\y¦’PYYñsŒæ¸‘fTÕ“Tõrù½ˆ<8ÚLÅl¼ß/¾ïÿÀ\×}acÑ$à{ž:Â÷ýÏÈÇCkÌ$Mâ&²Ýñ´e<Ï˱£ísDõªÏóÞ3†LEÍó< `¡`ŒªNÖx9h×Å>FÇxì„QQy›ïû—Ž!SÑRU#";>À2ŠˆÀ÷}„¶'dŒŠˆd³YkÆI££ÈhD¼Õ÷ýø2³q}¿¨jÄsèD"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""¢<’ MÛ¶ç¸IDnK$OV³råÊC=Ï»Ò÷ýSD$+"?K$ß ùMKT¼lÛ¾HDÞšH$®;HÍ\àh;=ÏûÖúõë· Vë8N¨µµõRoVÕˆˆlž>}ú½k֬霜3 *bÛöM"ò»D"qß`Žã˜ÖÖÖ8@€Ç;;;ïÞ´iSÇ`õ+W®<*“É\iŒ9Î÷ý=–e=ÐØØøèPb±ØÙƘ³ÌðŒ1æ›/OÀ¹å'ÏTtr?\À…ªzn2™üQÿšx<~ŠªþÀ<{„D<F/^»vmW~SŸºººò}ÿWÚ\×=v°šÚÚÚO‹ÈM €Ýèù¡º[DìD"qGßÚå˗϶,ë'NÐ àPOXâºî‹“w6DS›mÛ×ø"€ÿçºîöß_SS3ò¬‡Dä,ôŒ­N‡ØfŒ9§±±q{ßúx<~®ª¦Ð3ÛLp›ëºŸè[››”À•ü\ý,ôŒù‹\×ýÕÄž-Ñä0A šH5553Z[[¿à¡jªªª"ªú€ÙªzE:.…BsTõÛÎëêêº1o‰ŠT,{»ïû?0s¨šx<~¾ˆ|ÀãÆ˜ã\×£ªoЦªMñxü”¾õ¡PèN‘Ïvww—£g¢}#€STõ“x:DS™Ø¶ý_8XQ(jÌMœÿkúôé3Óéôl¹À"ß÷ïAŸ—ººº£sçý¾ïÿ³ëºåø=€Û¶}Uß¶[[[?àJùžeYs\× àRôL¸¿]SS3c"O˜ˆh²pòLE#Ÿ …p €W‡ª›5kÖør2™¼'•JyëÖ­Û{ôÑG_૯¯?,?©‰ŠËÊ•+µmûóƘ_8@v¨ZUý @UïªV2™ü½ˆ|=WƒüGommmíiªú~UýA"‘¸©¹¹y¿ëº×u¯ð9§¶¶öÌÉ<7¢©&‹lÛöÜ =TÝòåËp™ª>êºî5kÖ¬éL¥R^"‘¸@3€·Åãñ³{ëUõ“èYqþDSSÓ#»òã|ô\Íõúm«W¯.p5€9ä444¤sõ)ù €#C¡Ðò‰=s"¢ÉÁÉ3…ÚÚÚ3Uõ!óTu©ª6¤ü<ÈýÖüuŽãd|@ÙþýûÏ´°DEÌ󼝸¬ˆl¶,ëtû««®®.ðUÝìºî³}÷%‰ŸxYU?ˆÜj—ˆœ›ûóÞþm‰È=`Œ¹xBO†hŠ3Æ<` €[Ô¤î},cÌ·Ù}OîÏKz7¨êyºüwßB×u_QÕ‡,®­­}ìÛ·ïLs<ÐÿÙ™L¦·mŽ]"š8y¦¢`Œéð_™LfQ2™Ü4Lù™p衇>=Ⱦg@DNàˆD%Á÷ýgDäòyóæÕÐÐðÜPuÑhô-DDžd·Ø`ÖòåË䶉žÔ{ž÷ ¨ê›Æ}DEDU¿­ªor]÷Sè¹yP"rÐ3~Üè9Ê æIDATûï3Æ0¾>úÑNp2€×u÷ ÒVÿÏÑ3rh{Æ ­:pìÑ” :ÑDH$x|„åGèìé¼"òªªBD*&4 Q‰H&“_Iª™ûòïC”ì€P(T`‡ª)"ðJÿÂH$’Îf³@ÏÓº‰('™L^5|UÏx¨ê€ñ‡_íêê€ ˆD"s˜Ájs^͵YÑÛvnûPõ»,°mûÁ&ãDD…„+ÏTRÇ ¡ç>Ì݃í‘ÞýéùÌET‚z$6èXDîpß÷§€ˆÌcÌ€À÷ìÙÓûŒŽ[¢±™ ¡PhÀx\»víkèYµ>`,ŠÈA?GÑóYûzÛªzбާžˆ¨`qòL¥hÈW´ù¾ß»ÏËS¢’¤ª½÷25M®ÎÏý] »»{@ýŒ38n‰Æ¡wf³ÙÁÆ£äþóÀ²¬ƒ¾æ´wlc»Æ˜ƒŽuÏóü!ö Nž©¤ä Ö…žWÜ "³r_¾–·PD%ȳ|ߟ5ØþÞ±hYVïXÜ›ûs°±; T•ã–hlö€1fÀx´mû0ôÜæ÷d³ÙŽÜ®A?GÑo<ªêÞ¾Û‡ªŸ?>Ç/y[EäæD"±¶oÞÚÚÚKEä?¼=+áªú?ªú馦¦§†û÷$"""êe†/!"¢©BD°Ðó¼²AvϰPD¢}¶+"ïVÕÈŠÈUu=€Ã|½¶¶öò¾ ´¶¶ÞàK:Eäó>`¯ªÞÇ\Ù#wŸ3€‡U5 …2è¹×ùU=²·½åË—ÏŽD"X¥ªOªêuªz z®Œúz<Oô;‡cücÌODÄ‘/h0[Uo³mûßz mÛ¾HD¾…žûƯGÏ„ÿ^¹Ðó‹êêêòü“àeÛDDSBWW×m¶mz¹q4ýØÚµk»ÆÑüñnu]÷äVymÛþ)€»DäJ÷@<?_U/‘GöíÛwÞ¦M›:rµ.€ÇUõš+V|µ¡¡Á±m{€SE¤ÁuÝßäêtlYÖçœ""ë***ê{/½^µjÕ­™LæÇªZ[[[û½d2ùPß¼"ò¥D"ñ©Þ¼µµµ‹ÈÝ®ðÍ\] Œ1ïmllÜÕ{p<oSÕOD£ÑóÜ=Ž7"""*!\y&"š®BÏdpÀ‘ñ6îûþ—ÑçòhcÌ/r_¾¾J¬ªW€çyNïÄ\×mWÕø¿™LfÄYÇ1è¹T»cß¾}Ÿê{Ïòí·ß¾[D®YÖÿX˲È+"òŠˆæÎíâ\_€}ûö}&›Í–H$8q&""¢ãÊ3Ñ "gzž×1ؾ  º}:šššþÖwÃQGõbkk«˜Þgó©àyÞýH&“÷¶Ó—^zi€ÙþØw2Þ«»»{s8~½ß>ö­[·î¥¾\×}ɶm¿o^ß÷׉ÈùÖ¶¶¶~Ö¶í‡Däþ}ûöýhÆ {F›—ˆˆˆJ'ÏDDS@$yf_UÕÖƒã8~î2ë¾–œ À߸qã+Ñi6›=ÌU}q°ý7n|Ŷí,€C‡Ë‹žUhí›7™L>Çß§ªð¯®RÕ«ÊÊÊ:mÛ¾@½ëº|m/Û&"*NáA¶2Î6;˜U«VÍg;€p8¼Œ1G¶¿®®n.z~É»{¬}$‰‡]×½¸³³s®ˆT¡çþm@ z|FDDD4"\y&"*"ªÚƘÃÙ½p  RUWðE„—mшq噈¨°¥¤;::tØJëׯß!"xZD–ŠÈWEäýªú1UMHg³Y¯Ï!mÚ‡ê[U_H™ã8þ´iÓ.p+€STõ6¹À<Yáºîu½µ™Lf#€_8À‡¢ÑèbcŒ -"¯?éÚuÝWB¡Ð;Ü à=ªÚ ª78DUÿcÞ¼yWôËtм^Ï›L&¿£ª5ö¸ADî‘/hWÕ‹‰ÄC´CDDD4€ _BDDSQ]]ÝÑÙl6RYY¹ÓqœìD¶í8N¨¥¥e~$éìÿÚ¨¾V¯^]ÖÑÑ‘u]73\›õõõÑîî×uÝAŸÀ=V5553ÂáðQªšv]wBžNDDDDDDDDDDD}üp½ß;Zßä IEND®B`‚aoflagger-v3.4.0/external/pybind11/docs/changelog.rst0000644000175000017500000033677614507760431021240 0ustar olesoles.. _changelog: Changelog ######### Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. Changes will be added here periodically from the "Suggested changelog entry" block in pull request descriptions. IN DEVELOPMENT -------------- Changes will be summarized here periodically. Changes: * ``PyGILState_Check()``'s in ``pybind11::handle``'s ``inc_ref()`` & ``dec_ref()`` are now enabled by default again. `#4246 `_ Build system improvements: * Update clang-tidy to 15 in CI. `#4387 `_ Version 2.10.3 (Jan 3, 2023) ---------------------------- Changes: * Temporarily made our GIL status assertions (added in 2.10.2) disabled by default (re-enable manually by defining ``PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF``, will be enabled in 2.11). `#4432 `_ * Improved error messages when ``inc_ref``/``dec_ref`` are called with an invalid GIL state. `#4427 `_ `#4436 `_ Bug Fixes: * Some minor touchups found by static analyzers. `#4440 `_ Version 2.10.2 (Dec 20, 2022) ----------------------------- Changes: * ``scoped_interpreter`` constructor taking ``PyConfig``. `#4330 `_ * ``pybind11/eigen/tensor.h`` adds converters to and from ``Eigen::Tensor`` and ``Eigen::TensorMap``. `#4201 `_ * ``PyGILState_Check()``'s were integrated to ``pybind11::handle`` ``inc_ref()`` & ``dec_ref()``. The added GIL checks are guarded by ``PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF``, which is the default only if ``NDEBUG`` is not defined. (Made non-default in 2.10.3, will be active in 2.11) `#4246 `_ * Add option for enable/disable enum members in docstring. `#2768 `_ * Fixed typing of ``KeysView``, ``ValuesView`` and ``ItemsView`` in ``bind_map``. `#4353 `_ Bug fixes: * Bug fix affecting only Python 3.6 under very specific, uncommon conditions: move ``PyEval_InitThreads()`` call to the correct location. `#4350 `_ * Fix segfault bug when passing foreign native functions to functional.h. `#4254 `_ Build system improvements: * Support setting PYTHON_LIBRARIES manually for Windows ARM cross-compilation (classic mode). `#4406 `_ * Extend IPO/LTO detection for ICX (a.k.a IntelLLVM) compiler. `#4402 `_ * Allow calling ``find_package(pybind11 CONFIG)`` multiple times from separate directories in the same CMake project and properly link Python (new mode). `#4401 `_ * ``multiprocessing_set_spawn`` in pytest fixture for added safety. `#4377 `_ * Fixed a bug in two pybind11/tools cmake scripts causing "Unknown arguments specified" errors. `#4327 `_ Version 2.10.1 (Oct 31, 2022) ----------------------------- This is the first version to fully support embedding the newly released Python 3.11. Changes: * Allow ``pybind11::capsule`` constructor to take null destructor pointers. `#4221 `_ * ``embed.h`` was changed so that ``PYTHONPATH`` is used also with Python 3.11 (established behavior). `#4119 `_ * A ``PYBIND11_SIMPLE_GIL_MANAGEMENT`` option was added (cmake, C++ define), along with many additional tests in ``test_gil_scoped.py``. The option may be useful to try when debugging GIL-related issues, to determine if the more complex default implementation is or is not to blame. See #4216 for background. WARNING: Please be careful to not create ODR violations when using the option: everything that is linked together with mutual symbol visibility needs to be rebuilt. `#4216 `_ * ``PYBIND11_EXPORT_EXCEPTION`` was made non-empty only under macOS. This makes Linux builds safer, and enables the removal of warning suppression pragmas for Windows. `#4298 `_ Bug fixes: * Fixed a bug where ``UnicodeDecodeError`` was not propagated from various ``py::str`` ctors when decoding surrogate utf characters. `#4294 `_ * Revert perfect forwarding for ``make_iterator``. This broke at least one valid use case. May revisit later. `#4234 `_ * Fix support for safe casts to ``void*`` (regression in 2.10.0). `#4275 `_ * Fix ``char8_t`` support (regression in 2.9). `#4278 `_ * Unicode surrogate character in Python exception message leads to process termination in ``error_already_set::what()``. `#4297 `_ * Fix MSVC 2019 v.1924 & C++14 mode error for ``overload_cast``. `#4188 `_ * Make augmented assignment operators non-const for the object-api. Behavior was previously broken for augmented assignment operators. `#4065 `_ * Add proper error checking to C++ bindings for Python list append and insert. `#4208 `_ * Work-around for Nvidia's CUDA nvcc compiler in versions 11.4.0 - 11.8.0. `#4220 `_ * A workaround for PyPy was added in the ``py::error_already_set`` implementation, related to PR `#1895 `_ released with v2.10.0. `#4079 `_ * Fixed compiler errors when C++23 ``std::forward_like`` is available. `#4136 `_ * Properly raise exceptions in contains methods (like when an object in unhashable). `#4209 `_ * Further improve another error in exception handling. `#4232 `_ * ``get_local_internals()`` was made compatible with ``finalize_interpreter()``, fixing potential freezes during interpreter finalization. `#4192 `_ Performance and style: * Reserve space in set and STL map casters if possible. This will prevent unnecessary rehashing / resizing by knowing the number of keys ahead of time for Python to C++ casting. This improvement will greatly speed up the casting of large unordered maps and sets. `#4194 `_ * GIL RAII scopes are non-copyable to avoid potential bugs. `#4183 `_ * Explicitly default all relevant ctors for pytypes in the ``PYBIND11_OBJECT`` macros and enforce the clang-tidy checks ``modernize-use-equals-default`` in macros as well. `#4017 `_ * Optimize iterator advancement in C++ bindings. `#4237 `_ * Use the modern ``PyObject_GenericGetDict`` and ``PyObject_GenericSetDict`` for handling dynamic attribute dictionaries. `#4106 `_ * Document that users should use ``PYBIND11_NAMESPACE`` instead of using ``pybind11`` when opening namespaces. Using namespace declarations and namespace qualification remain the same as ``pybind11``. This is done to ensure consistent symbol visibility. `#4098 `_ * Mark ``detail::forward_like`` as constexpr. `#4147 `_ * Optimize unpacking_collector when processing ``arg_v`` arguments. `#4219 `_ * Optimize casting C++ object to ``None``. `#4269 `_ Build system improvements: * CMake: revert overwrite behavior, now opt-in with ``PYBIND11_PYTHONLIBS_OVERRWRITE OFF``. `#4195 `_ * Include a pkg-config file when installing pybind11, such as in the Python package. `#4077 `_ * Avoid stripping debug symbols when ``CMAKE_BUILD_TYPE`` is set to ``DEBUG`` instead of ``Debug``. `#4078 `_ * Followup to `#3948 `_, fixing vcpkg again. `#4123 `_ Version 2.10.0 (Jul 15, 2022) ----------------------------- Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC 2017 is limited due to availability of CI runners; we highly recommend MSVC 2019 or 2022 be used. Initial support added for Python 3.11. New features: * ``py::anyset`` & ``py::frozenset`` were added, with copying (cast) to ``std::set`` (similar to ``set``). `#3901 `_ * Support bytearray casting to string. `#3707 `_ * ``type_caster`` was added. ``std::monostate`` is a tag type that allows ``std::variant`` to act as an optional, or allows default construction of a ``std::variant`` holding a non-default constructible type. `#3818 `_ * ``pybind11::capsule::set_name`` added to mutate the name of the capsule instance. `#3866 `_ * NumPy: dtype constructor from type number added, accessors corresponding to Python API ``dtype.num``, ``dtype.byteorder``, ``dtype.flags`` and ``dtype.alignment`` added. `#3868 `_ Changes: * Python 3.6 is now the minimum supported version. `#3688 `_ `#3719 `_ * The minimum version for MSVC is now 2017. `#3722 `_ * Fix issues with CPython 3.11 betas and add to supported test matrix. `#3923 `_ * ``error_already_set`` is now safer and more performant, especially for exceptions with long tracebacks, by delaying computation. `#1895 `_ * Improve exception handling in python ``str`` bindings. `#3826 `_ * The bindings for capsules now have more consistent exception handling. `#3825 `_ * ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can now be used to define classes in namespaces other than pybind11. `#3797 `_ * Error printing code now uses ``PYBIND11_DETAILED_ERROR_MESSAGES`` instead of requiring ``NDEBUG``, allowing use with release builds if desired. `#3913 `_ * Implicit conversion of the literal ``0`` to ``pybind11::handle`` is now disabled. `#4008 `_ Bug fixes: * Fix exception handling when ``pybind11::weakref()`` fails. `#3739 `_ * ``module_::def_submodule`` was missing proper error handling. This is fixed now. `#3973 `_ * The behavior or ``error_already_set`` was made safer and the highly opaque "Unknown internal error occurred" message was replaced with a more helpful message. `#3982 `_ * ``error_already_set::what()`` now handles non-normalized exceptions correctly. `#3971 `_ * Support older C++ compilers where filesystem is not yet part of the standard library and is instead included in ``std::experimental::filesystem``. `#3840 `_ * Fix ``-Wfree-nonheap-object`` warnings produced by GCC by avoiding returning pointers to static objects with ``return_value_policy::take_ownership``. `#3946 `_ * Fix cast from pytype rvalue to another pytype. `#3949 `_ * Ensure proper behavior when garbage collecting classes with dynamic attributes in Python >=3.9. `#4051 `_ * A couple long-standing ``PYBIND11_NAMESPACE`` ``__attribute__((visibility("hidden")))`` inconsistencies are now fixed (affects only unusual environments). `#4043 `_ * ``pybind11::detail::get_internals()`` is now resilient to in-flight Python exceptions. `#3981 `_ * Arrays with a dimension of size 0 are now properly converted to dynamic Eigen matrices (more common in NumPy 1.23). `#4038 `_ * Avoid catching unrelated errors when importing NumPy. `#3974 `_ Performance and style: * Added an accessor overload of ``(object &&key)`` to reference steal the object when using python types as keys. This prevents unnecessary reference count overhead for attr, dictionary, tuple, and sequence look ups. Added additional regression tests. Fixed a performance bug the caused accessor assignments to potentially perform unnecessary copies. `#3970 `_ * Perfect forward all args of ``make_iterator``. `#3980 `_ * Avoid potential bug in pycapsule destructor by adding an ``error_guard`` to one of the dtors. `#3958 `_ * Optimize dictionary access in ``strip_padding`` for numpy. `#3994 `_ * ``stl_bind.h`` bindings now take slice args as a const-ref. `#3852 `_ * Made slice constructor more consistent, and improve performance of some casters by allowing reference stealing. `#3845 `_ * Change numpy dtype from_args method to use const ref. `#3878 `_ * Follow rule of three to ensure ``PyErr_Restore`` is called only once. `#3872 `_ * Added missing perfect forwarding for ``make_iterator`` functions. `#3860 `_ * Optimize c++ to python function casting by using the rvalue caster. `#3966 `_ * Optimize Eigen sparse matrix casting by removing unnecessary temporary. `#4064 `_ * Avoid potential implicit copy/assignment constructors causing double free in ``strdup_gaurd``. `#3905 `_ * Enable clang-tidy checks ``misc-definitions-in-headers``, ``modernize-loop-convert``, and ``modernize-use-nullptr``. `#3881 `_ `#3988 `_ Build system improvements: * CMake: Fix file extension on Windows with cp36 and cp37 using FindPython. `#3919 `_ * CMake: Support multiple Python targets (such as on vcpkg). `#3948 `_ * CMake: Fix issue with NVCC on Windows. `#3947 `_ * CMake: Drop the bitness check on cross compiles (like targeting WebAssembly via Emscripten). `#3959 `_ * Add MSVC builds in debug mode to CI. `#3784 `_ * MSVC 2022 C++20 coverage was added to GitHub Actions, including Eigen. `#3732 `_, `#3741 `_ Backend and tidying up: * New theme for the documentation. `#3109 `_ * Remove idioms in code comments. Use more inclusive language. `#3809 `_ * ``#include `` was removed from the ``pybind11/stl.h`` header. Your project may break if it has a transitive dependency on this include. The fix is to "Include What You Use". `#3928 `_ * Avoid ``setup.py `` usage in internal tests. `#3734 `_ Version 2.9.2 (Mar 29, 2022) ---------------------------- Changes: * Enum now has an ``__index__`` method on Python <3.8 too. `#3700 `_ * Local internals are now cleared after finalizing the interpreter. `#3744 `_ Bug fixes: * Better support for Python 3.11 alphas. `#3694 `_ * ``PYBIND11_TYPE_CASTER`` now uses fully qualified symbols, so it can be used outside of ``pybind11::detail``. `#3758 `_ * Some fixes for PyPy 3.9. `#3768 `_ * Fixed a potential memleak in PyPy in ``get_type_override``. `#3774 `_ * Fix usage of ``VISIBILITY_INLINES_HIDDEN``. `#3721 `_ Build system improvements: * Uses ``sysconfig`` module to determine installation locations on Python >= 3.10, instead of ``distutils`` which has been deprecated. `#3764 `_ * Support Catch 2.13.5+ (supporting GLIBC 2.34+). `#3679 `_ * Fix test failures with numpy 1.22 by ignoring whitespace when comparing ``str()`` of dtypes. `#3682 `_ Backend and tidying up: * clang-tidy: added ``readability-qualified-auto``, ``readability-braces-around-statements``, ``cppcoreguidelines-prefer-member-initializer``, ``clang-analyzer-optin.performance.Padding``, ``cppcoreguidelines-pro-type-static-cast-downcast``, and ``readability-inconsistent-declaration-parameter-name``. `#3702 `_, `#3699 `_, `#3716 `_, `#3709 `_ * clang-format was added to the pre-commit actions, and the entire code base automatically reformatted (after several iterations preparing for this leap). `#3713 `_ Version 2.9.1 (Feb 2, 2022) --------------------------- Changes: * If possible, attach Python exception with ``py::raise_from`` to ``TypeError`` when casting from C++ to Python. This will give additional info if Python exceptions occur in the caster. Adds a test case of trying to convert a set from C++ to Python when the hash function is not defined in Python. `#3605 `_ * Add a mapping of C++11 nested exceptions to their Python exception equivalent using ``py::raise_from``. This attaches the nested exceptions in Python using the ``__cause__`` field. `#3608 `_ * Propagate Python exception traceback using ``raise_from`` if a pybind11 function runs out of overloads. `#3671 `_ * ``py::multiple_inheritance`` is now only needed when C++ bases are hidden from pybind11. `#3650 `_ and `#3659 `_ Bug fixes: * Remove a boolean cast in ``numpy.h`` that causes MSVC C4800 warnings when compiling against Python 3.10 or newer. `#3669 `_ * Render ``py::bool_`` and ``py::float_`` as ``bool`` and ``float`` respectively. `#3622 `_ Build system improvements: * Fix CMake extension suffix computation on Python 3.10+. `#3663 `_ * Allow ``CMAKE_ARGS`` to override CMake args in pybind11's own ``setup.py``. `#3577 `_ * Remove a few deprecated c-headers. `#3610 `_ * More uniform handling of test targets. `#3590 `_ * Add clang-tidy readability check to catch potentially swapped function args. `#3611 `_ Version 2.9.0 (Dec 28, 2021) ---------------------------- This is the last version to support Python 2.7 and 3.5. New Features: * Allow ``py::args`` to be followed by other arguments; the remaining arguments are implicitly keyword-only, as if a ``py::kw_only{}`` annotation had been used. `#3402 `_ Changes: * Make str/bytes/memoryview more interoperable with ``std::string_view``. `#3521 `_ * Replace ``_`` with ``const_name`` in internals, avoid defining ``pybind::_`` if ``_`` defined as macro (common gettext usage) `#3423 `_ Bug fixes: * Fix a rare warning about extra copy in an Eigen constructor. `#3486 `_ * Fix caching of the C++ overrides. `#3465 `_ * Add missing ``std::forward`` calls to some ``cpp_function`` overloads. `#3443 `_ * Support PyPy 7.3.7 and the PyPy3.8 beta. Test python-3.11 on PRs with the ``python dev`` label. `#3419 `_ * Replace usage of deprecated ``Eigen::MappedSparseMatrix`` with ``Eigen::Map>`` for Eigen 3.3+. `#3499 `_ * Tweaks to support Microsoft Visual Studio 2022. `#3497 `_ Build system improvements: * Nicer CMake printout and IDE organisation for pybind11's own tests. `#3479 `_ * CMake: report version type as part of the version string to avoid a spurious space in the package status message. `#3472 `_ * Flags starting with ``-g`` in ``$CFLAGS`` and ``$CPPFLAGS`` are no longer overridden by ``.Pybind11Extension``. `#3436 `_ * Ensure ThreadPool is closed in ``setup_helpers``. `#3548 `_ * Avoid LTS on ``mips64`` and ``ppc64le`` (reported broken). `#3557 `_ v2.8.1 (Oct 27, 2021) --------------------- Changes and additions: * The simple namespace creation shortcut added in 2.8.0 was deprecated due to usage of CPython internal API, and will be removed soon. Use ``py::module_::import("types").attr("SimpleNamespace")``. `#3374 `_ * Add C++ Exception type to throw and catch ``AttributeError``. Useful for defining custom ``__setattr__`` and ``__getattr__`` methods. `#3387 `_ Fixes: * Fixed the potential for dangling references when using properties with ``std::optional`` types. `#3376 `_ * Modernize usage of ``PyCodeObject`` on Python 3.9+ (moving toward support for Python 3.11a1) `#3368 `_ * A long-standing bug in ``eigen.h`` was fixed (originally PR #3343). The bug was unmasked by newly added ``static_assert``'s in the Eigen 3.4.0 release. `#3352 `_ * Support multiple raw inclusion of CMake helper files (Conan.io does this for multi-config generators). `#3420 `_ * Fix harmless warning on upcoming CMake 3.22. `#3368 `_ * Fix 2.8.0 regression with MSVC 2017 + C++17 mode + Python 3. `#3407 `_ * Fix 2.8.0 regression that caused undefined behavior (typically segfaults) in ``make_key_iterator``/``make_value_iterator`` if dereferencing the iterator returned a temporary value instead of a reference. `#3348 `_ v2.8.0 (Oct 4, 2021) -------------------- New features: * Added ``py::raise_from`` to enable chaining exceptions. `#3215 `_ * Allow exception translators to be optionally registered local to a module instead of applying globally across all pybind11 modules. Use ``register_local_exception_translator(ExceptionTranslator&& translator)`` instead of ``register_exception_translator(ExceptionTranslator&& translator)`` to keep your exception remapping code local to the module. `#2650 `_ * Add ``make_simple_namespace`` function for instantiating Python ``SimpleNamespace`` objects. **Deprecated in 2.8.1.** `#2840 `_ * ``pybind11::scoped_interpreter`` and ``initialize_interpreter`` have new arguments to allow ``sys.argv`` initialization. `#2341 `_ * Allow Python builtins to be used as callbacks in CPython. `#1413 `_ * Added ``view`` to view arrays with a different datatype. `#987 `_ * Implemented ``reshape`` on arrays. `#984 `_ * Enable defining custom ``__new__`` methods on classes by fixing bug preventing overriding methods if they have non-pybind11 siblings. `#3265 `_ * Add ``make_value_iterator()``, and fix ``make_key_iterator()`` to return references instead of copies. `#3293 `_ * Improve the classes generated by ``bind_map``: `#3310 `_ * Change ``.items`` from an iterator to a dictionary view. * Add ``.keys`` and ``.values`` (both dictionary views). * Allow ``__contains__`` to take any object. * ``pybind11::custom_type_setup`` was added, for customizing the ``PyHeapTypeObject`` corresponding to a class, which may be useful for enabling garbage collection support, among other things. `#3287 `_ Changes: * Set ``__file__`` constant when running ``eval_file`` in an embedded interpreter. `#3233 `_ * Python objects and (C++17) ``std::optional`` now accepted in ``py::slice`` constructor. `#1101 `_ * The pybind11 proxy types ``str``, ``bytes``, ``bytearray``, ``tuple``, ``list`` now consistently support passing ``ssize_t`` values for sizes and indexes. Previously, only ``size_t`` was accepted in several interfaces. `#3219 `_ * Avoid evaluating ``PYBIND11_TLS_REPLACE_VALUE`` arguments more than once. `#3290 `_ Fixes: * Bug fix: enum value's ``__int__`` returning non-int when underlying type is bool or of char type. `#1334 `_ * Fixes bug in setting error state in Capsule's pointer methods. `#3261 `_ * A long-standing memory leak in ``py::cpp_function::initialize`` was fixed. `#3229 `_ * Fixes thread safety for some ``pybind11::type_caster`` which require lifetime extension, such as for ``std::string_view``. `#3237 `_ * Restore compatibility with gcc 4.8.4 as distributed by ubuntu-trusty, linuxmint-17. `#3270 `_ Build system improvements: * Fix regression in CMake Python package config: improper use of absolute path. `#3144 `_ * Cached Python version information could become stale when CMake was re-run with a different Python version. The build system now detects this and updates this information. `#3299 `_ * Specified UTF8-encoding in setup.py calls of open(). `#3137 `_ * Fix a harmless warning from CMake 3.21 with the classic Python discovery. `#3220 `_ * Eigen repo and version can now be specified as cmake options. `#3324 `_ Backend and tidying up: * Reduced thread-local storage required for keeping alive temporary data for type conversion to one key per ABI version, rather than one key per extension module. This makes the total thread-local storage required by pybind11 2 keys per ABI version. `#3275 `_ * Optimize NumPy array construction with additional moves. `#3183 `_ * Conversion to ``std::string`` and ``std::string_view`` now avoids making an extra copy of the data on Python >= 3.3. `#3257 `_ * Remove const modifier from certain C++ methods on Python collections (``list``, ``set``, ``dict``) such as (``clear()``, ``append()``, ``insert()``, etc...) and annotated them with ``py-non-const``. * Enable readability ``clang-tidy-const-return`` and remove useless consts. `#3254 `_ `#3194 `_ * The clang-tidy ``google-explicit-constructor`` option was enabled. `#3250 `_ * Mark a pytype move constructor as noexcept (perf). `#3236 `_ * Enable clang-tidy check to guard against inheritance slicing. `#3210 `_ * Legacy warning suppression pragma were removed from eigen.h. On Unix platforms, please use -isystem for Eigen include directories, to suppress compiler warnings originating from Eigen headers. Note that CMake does this by default. No adjustments are needed for Windows. `#3198 `_ * Format pybind11 with isort consistent ordering of imports `#3195 `_ * The warnings-suppression "pragma clamp" at the top/bottom of pybind11 was removed, clearing the path to refactoring and IWYU cleanup. `#3186 `_ * Enable most bugprone checks in clang-tidy and fix the found potential bugs and poor coding styles. `#3166 `_ * Add ``clang-tidy-readability`` rules to make boolean casts explicit improving code readability. Also enabled other misc and readability clang-tidy checks. `#3148 `_ * Move object in ``.pop()`` for list. `#3116 `_ v2.7.1 (Aug 3, 2021) --------------------- Minor missing functionality added: * Allow Python builtins to be used as callbacks in CPython. `#1413 `_ Bug fixes: * Fix regression in CMake Python package config: improper use of absolute path. `#3144 `_ * Fix Mingw64 and add to the CI testing matrix. `#3132 `_ * Specified UTF8-encoding in setup.py calls of open(). `#3137 `_ * Add clang-tidy-readability rules to make boolean casts explicit improving code readability. Also enabled other misc and readability clang-tidy checks. `#3148 `_ * Move object in ``.pop()`` for list. `#3116 `_ Backend and tidying up: * Removed and fixed warning suppressions. `#3127 `_ `#3129 `_ `#3135 `_ `#3141 `_ `#3142 `_ `#3150 `_ `#3152 `_ `#3160 `_ `#3161 `_ v2.7.0 (Jul 16, 2021) --------------------- New features: * Enable ``py::implicitly_convertible`` for ``py::class_``-wrapped types. `#3059 `_ * Allow function pointer extraction from overloaded functions. `#2944 `_ * NumPy: added ``.char_()`` to type which gives the NumPy public ``char`` result, which also distinguishes types by bit length (unlike ``.kind()``). `#2864 `_ * Add ``pybind11::bytearray`` to manipulate ``bytearray`` similar to ``bytes``. `#2799 `_ * ``pybind11/stl/filesystem.h`` registers a type caster that, on C++17/Python 3.6+, converts ``std::filesystem::path`` to ``pathlib.Path`` and any ``os.PathLike`` to ``std::filesystem::path``. `#2730 `_ * A ``PYBIND11_VERSION_HEX`` define was added, similar to ``PY_VERSION_HEX``. `#3120 `_ Changes: * ``py::str`` changed to exclusively hold ``PyUnicodeObject``. Previously ``py::str`` could also hold ``bytes``, which is probably surprising, was never documented, and can mask bugs (e.g. accidental use of ``py::str`` instead of ``py::bytes``). `#2409 `_ * Add a safety guard to ensure that the Python GIL is held when C++ calls back into Python via ``object_api<>::operator()`` (e.g. ``py::function`` ``__call__``). (This feature is available for Python 3.6+ only.) `#2919 `_ * Catch a missing ``self`` argument in calls to ``__init__()``. `#2914 `_ * Use ``std::string_view`` if available to avoid a copy when passing an object to a ``std::ostream``. `#3042 `_ * An important warning about thread safety was added to the ``iostream.h`` documentation; attempts to make ``py::scoped_ostream_redirect`` thread safe have been removed, as it was only partially effective. `#2995 `_ Fixes: * Performance: avoid unnecessary strlen calls. `#3058 `_ * Fix auto-generated documentation string when using ``const T`` in ``pyarray_t``. `#3020 `_ * Unify error messages thrown by ``simple_collector``/``unpacking_collector``. `#3013 `_ * ``pybind11::builtin_exception`` is now explicitly exported, which means the types included/defined in different modules are identical, and exceptions raised in different modules can be caught correctly. The documentation was updated to explain that custom exceptions that are used across module boundaries need to be explicitly exported as well. `#2999 `_ * Fixed exception when printing UTF-8 to a ``scoped_ostream_redirect``. `#2982 `_ * Pickle support enhancement: ``setstate`` implementation will attempt to ``setattr`` ``__dict__`` only if the unpickled ``dict`` object is not empty, to not force use of ``py::dynamic_attr()`` unnecessarily. `#2972 `_ * Allow negative timedelta values to roundtrip. `#2870 `_ * Fix unchecked errors could potentially swallow signals/other exceptions. `#2863 `_ * Add null pointer check with ``std::localtime``. `#2846 `_ * Fix the ``weakref`` constructor from ``py::object`` to create a new ``weakref`` on conversion. `#2832 `_ * Avoid relying on exceptions in C++17 when getting a ``shared_ptr`` holder from a ``shared_from_this`` class. `#2819 `_ * Allow the codec's exception to be raised instead of :code:`RuntimeError` when casting from :code:`py::str` to :code:`std::string`. `#2903 `_ Build system improvements: * In ``setup_helpers.py``, test for platforms that have some multiprocessing features but lack semaphores, which ``ParallelCompile`` requires. `#3043 `_ * Fix ``pybind11_INCLUDE_DIR`` in case ``CMAKE_INSTALL_INCLUDEDIR`` is absolute. `#3005 `_ * Fix bug not respecting ``WITH_SOABI`` or ``WITHOUT_SOABI`` to CMake. `#2938 `_ * Fix the default ``Pybind11Extension`` compilation flags with a Mingw64 python. `#2921 `_ * Clang on Windows: do not pass ``/MP`` (ignored flag). `#2824 `_ * ``pybind11.setup_helpers.intree_extensions`` can be used to generate ``Pybind11Extension`` instances from cpp files placed in the Python package source tree. `#2831 `_ Backend and tidying up: * Enable clang-tidy performance, readability, and modernization checks throughout the codebase to enforce best coding practices. `#3046 `_, `#3049 `_, `#3051 `_, `#3052 `_, `#3080 `_, and `#3094 `_ * Checks for common misspellings were added to the pre-commit hooks. `#3076 `_ * Changed ``Werror`` to stricter ``Werror-all`` for Intel compiler and fixed minor issues. `#2948 `_ * Fixed compilation with GCC < 5 when the user defines ``_GLIBCXX_USE_CXX11_ABI``. `#2956 `_ * Added nox support for easier local testing and linting of contributions. `#3101 `_ and `#3121 `_ * Avoid RTD style issue with docutils 0.17+. `#3119 `_ * Support pipx run, such as ``pipx run pybind11 --include`` for a quick compile. `#3117 `_ v2.6.2 (Jan 26, 2021) --------------------- Minor missing functionality added: * enum: add missing Enum.value property. `#2739 `_ * Allow thread termination to be avoided during shutdown for CPython 3.7+ via ``.disarm`` for ``gil_scoped_acquire``/``gil_scoped_release``. `#2657 `_ Fixed or improved behavior in a few special cases: * Fix bug where the constructor of ``object`` subclasses would not throw on being passed a Python object of the wrong type. `#2701 `_ * The ``type_caster`` for integers does not convert Python objects with ``__int__`` anymore with ``noconvert`` or during the first round of trying overloads. `#2698 `_ * When casting to a C++ integer, ``__index__`` is always called and not considered as conversion, consistent with Python 3.8+. `#2801 `_ Build improvements: * Setup helpers: ``extra_compile_args`` and ``extra_link_args`` automatically set by Pybind11Extension are now prepended, which allows them to be overridden by user-set ``extra_compile_args`` and ``extra_link_args``. `#2808 `_ * Setup helpers: Don't trigger unused parameter warning. `#2735 `_ * CMake: Support running with ``--warn-uninitialized`` active. `#2806 `_ * CMake: Avoid error if included from two submodule directories. `#2804 `_ * CMake: Fix ``STATIC`` / ``SHARED`` being ignored in FindPython mode. `#2796 `_ * CMake: Respect the setting for ``CMAKE_CXX_VISIBILITY_PRESET`` if defined. `#2793 `_ * CMake: Fix issue with FindPython2/FindPython3 not working with ``pybind11::embed``. `#2662 `_ * CMake: mixing local and installed pybind11's would prioritize the installed one over the local one (regression in 2.6.0). `#2716 `_ Bug fixes: * Fixed segfault in multithreaded environments when using ``scoped_ostream_redirect``. `#2675 `_ * Leave docstring unset when all docstring-related options are disabled, rather than set an empty string. `#2745 `_ * The module key in builtins that pybind11 uses to store its internals changed from std::string to a python str type (more natural on Python 2, no change on Python 3). `#2814 `_ * Fixed assertion error related to unhandled (later overwritten) exception in CPython 3.8 and 3.9 debug builds. `#2685 `_ * Fix ``py::gil_scoped_acquire`` assert with CPython 3.9 debug build. `#2683 `_ * Fix issue with a test failing on pytest 6.2. `#2741 `_ Warning fixes: * Fix warning modifying constructor parameter 'flag' that shadows a field of 'set_flag' ``[-Wshadow-field-in-constructor-modified]``. `#2780 `_ * Suppressed some deprecation warnings about old-style ``__init__``/``__setstate__`` in the tests. `#2759 `_ Valgrind work: * Fix invalid access when calling a pybind11 ``__init__`` on a non-pybind11 class instance. `#2755 `_ * Fixed various minor memory leaks in pybind11's test suite. `#2758 `_ * Resolved memory leak in cpp_function initialization when exceptions occurred. `#2756 `_ * Added a Valgrind build, checking for leaks and memory-related UB, to CI. `#2746 `_ Compiler support: * Intel compiler was not activating C++14 support due to a broken define. `#2679 `_ * Support ICC and NVIDIA HPC SDK in C++17 mode. `#2729 `_ * Support Intel OneAPI compiler (ICC 20.2) and add to CI. `#2573 `_ v2.6.1 (Nov 11, 2020) --------------------- * ``py::exec``, ``py::eval``, and ``py::eval_file`` now add the builtins module as ``"__builtins__"`` to their ``globals`` argument, better matching ``exec`` and ``eval`` in pure Python. `#2616 `_ * ``setup_helpers`` will no longer set a minimum macOS version higher than the current version. `#2622 `_ * Allow deleting static properties. `#2629 `_ * Seal a leak in ``def_buffer``, cleaning up the ``capture`` object after the ``class_`` object goes out of scope. `#2634 `_ * ``pybind11_INCLUDE_DIRS`` was incorrect, potentially causing a regression if it was expected to include ``PYTHON_INCLUDE_DIRS`` (please use targets instead). `#2636 `_ * Added parameter names to the ``py::enum_`` constructor and methods, avoiding ``arg0`` in the generated docstrings. `#2637 `_ * Added ``needs_recompile`` optional function to the ``ParallelCompiler`` helper, to allow a recompile to be skipped based on a user-defined function. `#2643 `_ v2.6.0 (Oct 21, 2020) --------------------- See :ref:`upgrade-guide-2.6` for help upgrading to the new version. New features: * Keyword-only arguments supported in Python 2 or 3 with ``py::kw_only()``. `#2100 `_ * Positional-only arguments supported in Python 2 or 3 with ``py::pos_only()``. `#2459 `_ * ``py::is_final()`` class modifier to block subclassing (CPython only). `#2151 `_ * Added ``py::prepend()``, allowing a function to be placed at the beginning of the overload chain. `#1131 `_ * Access to the type object now provided with ``py::type::of()`` and ``py::type::of(h)``. `#2364 `_ * Perfect forwarding support for methods. `#2048 `_ * Added ``py::error_already_set::discard_as_unraisable()``. `#2372 `_ * ``py::hash`` is now public. `#2217 `_ * ``py::class_`` is now supported. Note that writing to one data member of the union and reading another (type punning) is UB in C++. Thus pybind11-bound enums should never be used for such conversions. `#2320 `_. * Classes now check local scope when registering members, allowing a subclass to have a member with the same name as a parent (such as an enum). `#2335 `_ Code correctness features: * Error now thrown when ``__init__`` is forgotten on subclasses. `#2152 `_ * Throw error if conversion to a pybind11 type if the Python object isn't a valid instance of that type, such as ``py::bytes(o)`` when ``py::object o`` isn't a bytes instance. `#2349 `_ * Throw if conversion to ``str`` fails. `#2477 `_ API changes: * ``py::module`` was renamed ``py::module_`` to avoid issues with C++20 when used unqualified, but an alias ``py::module`` is provided for backward compatibility. `#2489 `_ * Public constructors for ``py::module_`` have been deprecated; please use ``pybind11::module_::create_extension_module`` if you were using the public constructor (fairly rare after ``PYBIND11_MODULE`` was introduced). `#2552 `_ * ``PYBIND11_OVERLOAD*`` macros and ``get_overload`` function replaced by correctly-named ``PYBIND11_OVERRIDE*`` and ``get_override``, fixing inconsistencies in the presence of a closing ``;`` in these macros. ``get_type_overload`` is deprecated. `#2325 `_ Packaging / building improvements: * The Python package was reworked to be more powerful and useful. `#2433 `_ * :ref:`build-setuptools` is easier thanks to a new ``pybind11.setup_helpers`` module, which provides utilities to use setuptools with pybind11. It can be used via PEP 518, ``setup_requires``, or by directly importing or copying ``setup_helpers.py`` into your project. * CMake configuration files are now included in the Python package. Use ``pybind11.get_cmake_dir()`` or ``python -m pybind11 --cmakedir`` to get the directory with the CMake configuration files, or include the site-packages location in your ``CMAKE_MODULE_PATH``. Or you can use the new ``pybind11[global]`` extra when you install ``pybind11``, which installs the CMake files and headers into your base environment in the standard location. * ``pybind11-config`` is another way to write ``python -m pybind11`` if you have your PATH set up. * Added external typing support to the helper module, code from ``import pybind11`` can now be type checked. `#2588 `_ * Minimum CMake required increased to 3.4. `#2338 `_ and `#2370 `_ * Full integration with CMake's C++ standard system and compile features replaces ``PYBIND11_CPP_STANDARD``. * Generated config file is now portable to different Python/compiler/CMake versions. * Virtual environments prioritized if ``PYTHON_EXECUTABLE`` is not set (``venv``, ``virtualenv``, and ``conda``) (similar to the new FindPython mode). * Other CMake features now natively supported, like ``CMAKE_INTERPROCEDURAL_OPTIMIZATION``, ``set(CMAKE_CXX_VISIBILITY_PRESET hidden)``. * ``CUDA`` as a language is now supported. * Helper functions ``pybind11_strip``, ``pybind11_extension``, ``pybind11_find_import`` added, see :doc:`cmake/index`. * Optional :ref:`find-python-mode` and :ref:`nopython-mode` with CMake. `#2370 `_ * Uninstall target added. `#2265 `_ and `#2346 `_ * ``pybind11_add_module()`` now accepts an optional ``OPT_SIZE`` flag that switches the binding target to size-based optimization if the global build type can not always be fixed to ``MinSizeRel`` (except in debug mode, where optimizations remain disabled). ``MinSizeRel`` or this flag reduces binary size quite substantially (~25% on some platforms). `#2463 `_ Smaller or developer focused features and fixes: * Moved ``mkdoc.py`` to a new repo, `pybind11-mkdoc`_. There are no longer submodules in the main repo. * ``py::memoryview`` segfault fix and update, with new ``py::memoryview::from_memory`` in Python 3, and documentation. `#2223 `_ * Fix for ``buffer_info`` on Python 2. `#2503 `_ * If ``__eq__`` defined but not ``__hash__``, ``__hash__`` is now set to ``None``. `#2291 `_ * ``py::ellipsis`` now also works on Python 2. `#2360 `_ * Pointer to ``std::tuple`` & ``std::pair`` supported in cast. `#2334 `_ * Small fixes in NumPy support. ``py::array`` now uses ``py::ssize_t`` as first argument type. `#2293 `_ * Added missing signature for ``py::array``. `#2363 `_ * ``unchecked_mutable_reference`` has access to operator ``()`` and ``[]`` when const. `#2514 `_ * ``py::vectorize`` is now supported on functions that return void. `#1969 `_ * ``py::capsule`` supports ``get_pointer`` and ``set_pointer``. `#1131 `_ * Fix crash when different instances share the same pointer of the same type. `#2252 `_ * Fix for ``py::len`` not clearing Python's error state when it fails and throws. `#2575 `_ * Bugfixes related to more extensive testing, new GitHub Actions CI. `#2321 `_ * Bug in timezone issue in Eastern hemisphere midnight fixed. `#2438 `_ * ``std::chrono::time_point`` now works when the resolution is not the same as the system. `#2481 `_ * Bug fixed where ``py::array_t`` could accept arrays that did not match the requested ordering. `#2484 `_ * Avoid a segfault on some compilers when types are removed in Python. `#2564 `_ * ``py::arg::none()`` is now also respected when passing keyword arguments. `#2611 `_ * PyPy fixes, PyPy 7.3.x now supported, including PyPy3. (Known issue with PyPy2 and Windows `#2596 `_). `#2146 `_ * CPython 3.9.0 workaround for undefined behavior (macOS segfault). `#2576 `_ * CPython 3.9 warning fixes. `#2253 `_ * Improved C++20 support, now tested in CI. `#2489 `_ `#2599 `_ * Improved but still incomplete debug Python interpreter support. `#2025 `_ * NVCC (CUDA 11) now supported and tested in CI. `#2461 `_ * NVIDIA PGI compilers now supported and tested in CI. `#2475 `_ * At least Intel 18 now explicitly required when compiling with Intel. `#2577 `_ * Extensive style checking in CI, with `pre-commit`_ support. Code modernization, checked by clang-tidy. * Expanded docs, including new main page, new installing section, and CMake helpers page, along with over a dozen new sections on existing pages. * In GitHub, new docs for contributing and new issue templates. .. _pre-commit: https://pre-commit.com .. _pybind11-mkdoc: https://github.com/pybind/pybind11-mkdoc v2.5.0 (Mar 31, 2020) ----------------------------------------------------- * Use C++17 fold expressions in type casters, if available. This can improve performance during overload resolution when functions have multiple arguments. `#2043 `_. * Changed include directory resolution in ``pybind11/__init__.py`` and installation in ``setup.py``. This fixes a number of open issues where pybind11 headers could not be found in certain environments. `#1995 `_. * C++20 ``char8_t`` and ``u8string`` support. `#2026 `_. * CMake: search for Python 3.9. `bb9c91 `_. * Fixes for MSYS-based build environments. `#2087 `_, `#2053 `_. * STL bindings for ``std::vector<...>::clear``. `#2074 `_. * Read-only flag for ``py::buffer``. `#1466 `_. * Exception handling during module initialization. `bf2b031 `_. * Support linking against a CPython debug build. `#2025 `_. * Fixed issues involving the availability and use of aligned ``new`` and ``delete``. `#1988 `_, `759221 `_. * Fixed a resource leak upon interpreter shutdown. `#2020 `_. * Fixed error handling in the boolean caster. `#1976 `_. v2.4.3 (Oct 15, 2019) ----------------------------------------------------- * Adapt pybind11 to a C API convention change in Python 3.8. `#1950 `_. v2.4.2 (Sep 21, 2019) ----------------------------------------------------- * Replaced usage of a C++14 only construct. `#1929 `_. * Made an ifdef future-proof for Python >= 4. `f3109d `_. v2.4.1 (Sep 20, 2019) ----------------------------------------------------- * Fixed a problem involving implicit conversion from enumerations to integers on Python 3.8. `#1780 `_. v2.4.0 (Sep 19, 2019) ----------------------------------------------------- * Try harder to keep pybind11-internal data structures separate when there are potential ABI incompatibilities. Fixes crashes that occurred when loading multiple pybind11 extensions that were e.g. compiled by GCC (libstdc++) and Clang (libc++). `#1588 `_ and `c9f5a `_. * Added support for ``__await__``, ``__aiter__``, and ``__anext__`` protocols. `#1842 `_. * ``pybind11_add_module()``: don't strip symbols when compiling in ``RelWithDebInfo`` mode. `#1980 `_. * ``enum_``: Reproduce Python behavior when comparing against invalid values (e.g. ``None``, strings, etc.). Add back support for ``__invert__()``. `#1912 `_, `#1907 `_. * List insertion operation for ``py::list``. Added ``.empty()`` to all collection types. Added ``py::set::contains()`` and ``py::dict::contains()``. `#1887 `_, `#1884 `_, `#1888 `_. * ``py::details::overload_cast_impl`` is available in C++11 mode, can be used like ``overload_cast`` with an additional set of parentheses. `#1581 `_. * Fixed ``get_include()`` on Conda. `#1877 `_. * ``stl_bind.h``: negative indexing support. `#1882 `_. * Minor CMake fix to add MinGW compatibility. `#1851 `_. * GIL-related fixes. `#1836 `_, `8b90b `_. * Other very minor/subtle fixes and improvements. `#1329 `_, `#1910 `_, `#1863 `_, `#1847 `_, `#1890 `_, `#1860 `_, `#1848 `_, `#1821 `_, `#1837 `_, `#1833 `_, `#1748 `_, `#1852 `_. v2.3.0 (June 11, 2019) ----------------------------------------------------- * Significantly reduced module binary size (10-20%) when compiled in C++11 mode with GCC/Clang, or in any mode with MSVC. Function signatures are now always precomputed at compile time (this was previously only available in C++14 mode for non-MSVC compilers). `#934 `_. * Add basic support for tag-based static polymorphism, where classes provide a method to returns the desired type of an instance. `#1326 `_. * Python type wrappers (``py::handle``, ``py::object``, etc.) now support map Python's number protocol onto C++ arithmetic operators such as ``operator+``, ``operator/=``, etc. `#1511 `_. * A number of improvements related to enumerations: 1. The ``enum_`` implementation was rewritten from scratch to reduce code bloat. Rather than instantiating a full implementation for each enumeration, most code is now contained in a generic base class. `#1511 `_. 2. The ``value()`` method of ``py::enum_`` now accepts an optional docstring that will be shown in the documentation of the associated enumeration. `#1160 `_. 3. check for already existing enum value and throw an error if present. `#1453 `_. * Support for over-aligned type allocation via C++17's aligned ``new`` statement. `#1582 `_. * Added ``py::ellipsis()`` method for slicing of multidimensional NumPy arrays `#1502 `_. * Numerous Improvements to the ``mkdoc.py`` script for extracting documentation from C++ header files. `#1788 `_. * ``pybind11_add_module()``: allow including Python as a ``SYSTEM`` include path. `#1416 `_. * ``pybind11/stl.h`` does not convert strings to ``vector`` anymore. `#1258 `_. * Mark static methods as such to fix auto-generated Sphinx documentation. `#1732 `_. * Re-throw forced unwind exceptions (e.g. during pthread termination). `#1208 `_. * Added ``__contains__`` method to the bindings of maps (``std::map``, ``std::unordered_map``). `#1767 `_. * Improvements to ``gil_scoped_acquire``. `#1211 `_. * Type caster support for ``std::deque``. `#1609 `_. * Support for ``std::unique_ptr`` holders, whose deleters differ between a base and derived class. `#1353 `_. * Construction of STL array/vector-like data structures from iterators. Added an ``extend()`` operation. `#1709 `_, * CMake build system improvements for projects that include non-C++ files (e.g. plain C, CUDA) in ``pybind11_add_module`` et al. `#1678 `_. * Fixed asynchronous invocation and deallocation of Python functions wrapped in ``std::function``. `#1595 `_. * Fixes regarding return value policy propagation in STL type casters. `#1603 `_. * Fixed scoped enum comparisons. `#1571 `_. * Fixed iostream redirection for code that releases the GIL. `#1368 `_, * A number of CI-related fixes. `#1757 `_, `#1744 `_, `#1670 `_. v2.2.4 (September 11, 2018) ----------------------------------------------------- * Use new Python 3.7 Thread Specific Storage (TSS) implementation if available. `#1454 `_, `#1517 `_. * Fixes for newer MSVC versions and C++17 mode. `#1347 `_, `#1462 `_. * Propagate return value policies to type-specific casters when casting STL containers. `#1455 `_. * Allow ostream-redirection of more than 1024 characters. `#1479 `_. * Set ``Py_DEBUG`` define when compiling against a debug Python build. `#1438 `_. * Untangle integer logic in number type caster to work for custom types that may only be castable to a restricted set of builtin types. `#1442 `_. * CMake build system: Remember Python version in cache file. `#1434 `_. * Fix for custom smart pointers: use ``std::addressof`` to obtain holder address instead of ``operator&``. `#1435 `_. * Properly report exceptions thrown during module initialization. `#1362 `_. * Fixed a segmentation fault when creating empty-shaped NumPy array. `#1371 `_. * The version of Intel C++ compiler must be >= 2017, and this is now checked by the header files. `#1363 `_. * A few minor typo fixes and improvements to the test suite, and patches that silence compiler warnings. * Vectors now support construction from generators, as well as ``extend()`` from a list or generator. `#1496 `_. v2.2.3 (April 29, 2018) ----------------------------------------------------- * The pybind11 header location detection was replaced by a new implementation that no longer depends on ``pip`` internals (the recently released ``pip`` 10 has restricted access to this API). `#1190 `_. * Small adjustment to an implementation detail to work around a compiler segmentation fault in Clang 3.3/3.4. `#1350 `_. * The minimal supported version of the Intel compiler was >= 17.0 since pybind11 v2.1. This check is now explicit, and a compile-time error is raised if the compiler meet the requirement. `#1363 `_. * Fixed an endianness-related fault in the test suite. `#1287 `_. v2.2.2 (February 7, 2018) ----------------------------------------------------- * Fixed a segfault when combining embedded interpreter shutdown/reinitialization with external loaded pybind11 modules. `#1092 `_. * Eigen support: fixed a bug where Nx1/1xN numpy inputs couldn't be passed as arguments to Eigen vectors (which for Eigen are simply compile-time fixed Nx1/1xN matrices). `#1106 `_. * Clarified to license by moving the licensing of contributions from ``LICENSE`` into ``CONTRIBUTING.md``: the licensing of contributions is not actually part of the software license as distributed. This isn't meant to be a substantial change in the licensing of the project, but addresses concerns that the clause made the license non-standard. `#1109 `_. * Fixed a regression introduced in 2.1 that broke binding functions with lvalue character literal arguments. `#1128 `_. * MSVC: fix for compilation failures under /permissive-, and added the flag to the appveyor test suite. `#1155 `_. * Fixed ``__qualname__`` generation, and in turn, fixes how class names (especially nested class names) are shown in generated docstrings. `#1171 `_. * Updated the FAQ with a suggested project citation reference. `#1189 `_. * Added fixes for deprecation warnings when compiled under C++17 with ``-Wdeprecated`` turned on, and add ``-Wdeprecated`` to the test suite compilation flags. `#1191 `_. * Fixed outdated PyPI URLs in ``setup.py``. `#1213 `_. * Fixed a refcount leak for arguments that end up in a ``py::args`` argument for functions with both fixed positional and ``py::args`` arguments. `#1216 `_. * Fixed a potential segfault resulting from possible premature destruction of ``py::args``/``py::kwargs`` arguments with overloaded functions. `#1223 `_. * Fixed ``del map[item]`` for a ``stl_bind.h`` bound stl map. `#1229 `_. * Fixed a regression from v2.1.x where the aggregate initialization could unintentionally end up at a constructor taking a templated ``std::initializer_list`` argument. `#1249 `_. * Fixed an issue where calling a function with a keep_alive policy on the same nurse/patient pair would cause the internal patient storage to needlessly grow (unboundedly, if the nurse is long-lived). `#1251 `_. * Various other minor fixes. v2.2.1 (September 14, 2017) ----------------------------------------------------- * Added ``py::module_::reload()`` member function for reloading a module. `#1040 `_. * Fixed a reference leak in the number converter. `#1078 `_. * Fixed compilation with Clang on host GCC < 5 (old libstdc++ which isn't fully C++11 compliant). `#1062 `_. * Fixed a regression where the automatic ``std::vector`` caster would fail to compile. The same fix also applies to any container which returns element proxies instead of references. `#1053 `_. * Fixed a regression where the ``py::keep_alive`` policy could not be applied to constructors. `#1065 `_. * Fixed a nullptr dereference when loading a ``py::module_local`` type that's only registered in an external module. `#1058 `_. * Fixed implicit conversion of accessors to types derived from ``py::object``. `#1076 `_. * The ``name`` in ``PYBIND11_MODULE(name, variable)`` can now be a macro. `#1082 `_. * Relaxed overly strict ``py::pickle()`` check for matching get and set types. `#1064 `_. * Conversion errors now try to be more informative when it's likely that a missing header is the cause (e.g. forgetting ````). `#1077 `_. v2.2.0 (August 31, 2017) ----------------------------------------------------- * Support for embedding the Python interpreter. See the :doc:`documentation page ` for a full overview of the new features. `#774 `_, `#889 `_, `#892 `_, `#920 `_. .. code-block:: cpp #include namespace py = pybind11; int main() { py::scoped_interpreter guard{}; // start the interpreter and keep it alive py::print("Hello, World!"); // use the Python API } * Support for inheriting from multiple C++ bases in Python. `#693 `_. .. code-block:: python from cpp_module import CppBase1, CppBase2 class PyDerived(CppBase1, CppBase2): def __init__(self): CppBase1.__init__(self) # C++ bases must be initialized explicitly CppBase2.__init__(self) * ``PYBIND11_MODULE`` is now the preferred way to create module entry points. ``PYBIND11_PLUGIN`` is deprecated. See :ref:`macros` for details. `#879 `_. .. code-block:: cpp // new PYBIND11_MODULE(example, m) { m.def("add", [](int a, int b) { return a + b; }); } // old PYBIND11_PLUGIN(example) { py::module m("example"); m.def("add", [](int a, int b) { return a + b; }); return m.ptr(); } * pybind11's headers and build system now more strictly enforce hidden symbol visibility for extension modules. This should be seamless for most users, but see the :doc:`upgrade` if you use a custom build system. `#995 `_. * Support for ``py::module_local`` types which allow multiple modules to export the same C++ types without conflicts. This is useful for opaque types like ``std::vector``. ``py::bind_vector`` and ``py::bind_map`` now default to ``py::module_local`` if their elements are builtins or local types. See :ref:`module_local` for details. `#949 `_, `#981 `_, `#995 `_, `#997 `_. * Custom constructors can now be added very easily using lambdas or factory functions which return a class instance by value, pointer or holder. This supersedes the old placement-new ``__init__`` technique. See :ref:`custom_constructors` for details. `#805 `_, `#1014 `_. .. code-block:: cpp struct Example { Example(std::string); }; py::class_(m, "Example") .def(py::init()) // existing constructor .def(py::init([](int n) { // custom constructor return std::make_unique(std::to_string(n)); })); * Similarly to custom constructors, pickling support functions are now bound using the ``py::pickle()`` adaptor which improves type safety. See the :doc:`upgrade` and :ref:`pickling` for details. `#1038 `_. * Builtin support for converting C++17 standard library types and general conversion improvements: 1. C++17 ``std::variant`` is supported right out of the box. C++11/14 equivalents (e.g. ``boost::variant``) can also be added with a simple user-defined specialization. See :ref:`cpp17_container_casters` for details. `#811 `_, `#845 `_, `#989 `_. 2. Out-of-the-box support for C++17 ``std::string_view``. `#906 `_. 3. Improved compatibility of the builtin ``optional`` converter. `#874 `_. 4. The ``bool`` converter now accepts ``numpy.bool_`` and types which define ``__bool__`` (Python 3.x) or ``__nonzero__`` (Python 2.7). `#925 `_. 5. C++-to-Python casters are now more efficient and move elements out of rvalue containers whenever possible. `#851 `_, `#936 `_, `#938 `_. 6. Fixed ``bytes`` to ``std::string/char*`` conversion on Python 3. `#817 `_. 7. Fixed lifetime of temporary C++ objects created in Python-to-C++ conversions. `#924 `_. * Scope guard call policy for RAII types, e.g. ``py::call_guard()``, ``py::call_guard()``. See :ref:`call_policies` for details. `#740 `_. * Utility for redirecting C++ streams to Python (e.g. ``std::cout`` -> ``sys.stdout``). Scope guard ``py::scoped_ostream_redirect`` in C++ and a context manager in Python. See :ref:`ostream_redirect`. `#1009 `_. * Improved handling of types and exceptions across module boundaries. `#915 `_, `#951 `_, `#995 `_. * Fixed destruction order of ``py::keep_alive`` nurse/patient objects in reference cycles. `#856 `_. * NumPy and buffer protocol related improvements: 1. Support for negative strides in Python buffer objects/numpy arrays. This required changing integers from unsigned to signed for the related C++ APIs. Note: If you have compiler warnings enabled, you may notice some new conversion warnings after upgrading. These can be resolved with ``static_cast``. `#782 `_. 2. Support ``std::complex`` and arrays inside ``PYBIND11_NUMPY_DTYPE``. `#831 `_, `#832 `_. 3. Support for constructing ``py::buffer_info`` and ``py::arrays`` using arbitrary containers or iterators instead of requiring a ``std::vector``. `#788 `_, `#822 `_, `#860 `_. 4. Explicitly check numpy version and require >= 1.7.0. `#819 `_. * Support for allowing/prohibiting ``None`` for specific arguments and improved ``None`` overload resolution order. See :ref:`none_arguments` for details. `#843 `_. `#859 `_. * Added ``py::exec()`` as a shortcut for ``py::eval()`` and support for C++11 raw string literals as input. See :ref:`eval`. `#766 `_, `#827 `_. * ``py::vectorize()`` ignores non-vectorizable arguments and supports member functions. `#762 `_. * Support for bound methods as callbacks (``pybind11/functional.h``). `#815 `_. * Allow aliasing pybind11 methods: ``cls.attr("foo") = cls.attr("bar")``. `#802 `_. * Don't allow mixed static/non-static overloads. `#804 `_. * Fixed overriding static properties in derived classes. `#784 `_. * Added support for write only properties. `#1144 `_. * Improved deduction of member functions of a derived class when its bases aren't registered with pybind11. `#855 `_. .. code-block:: cpp struct Base { int foo() { return 42; } } struct Derived : Base {} // Now works, but previously required also binding `Base` py::class_(m, "Derived") .def("foo", &Derived::foo); // function is actually from `Base` * The implementation of ``py::init<>`` now uses C++11 brace initialization syntax to construct instances, which permits binding implicit constructors of aggregate types. `#1015 `_. .. code-block:: cpp struct Aggregate { int a; std::string b; }; py::class_(m, "Aggregate") .def(py::init()); * Fixed issues with multiple inheritance with offset base/derived pointers. `#812 `_, `#866 `_, `#960 `_. * Fixed reference leak of type objects. `#1030 `_. * Improved support for the ``/std:c++14`` and ``/std:c++latest`` modes on MSVC 2017. `#841 `_, `#999 `_. * Fixed detection of private operator new on MSVC. `#893 `_, `#918 `_. * Intel C++ compiler compatibility fixes. `#937 `_. * Fixed implicit conversion of ``py::enum_`` to integer types on Python 2.7. `#821 `_. * Added ``py::hash`` to fetch the hash value of Python objects, and ``.def(hash(py::self))`` to provide the C++ ``std::hash`` as the Python ``__hash__`` method. `#1034 `_. * Fixed ``__truediv__`` on Python 2 and ``__itruediv__`` on Python 3. `#867 `_. * ``py::capsule`` objects now support the ``name`` attribute. This is useful for interfacing with ``scipy.LowLevelCallable``. `#902 `_. * Fixed ``py::make_iterator``'s ``__next__()`` for past-the-end calls. `#897 `_. * Added ``error_already_set::matches()`` for checking Python exceptions. `#772 `_. * Deprecated ``py::error_already_set::clear()``. It's no longer needed following a simplification of the ``py::error_already_set`` class. `#954 `_. * Deprecated ``py::handle::operator==()`` in favor of ``py::handle::is()`` `#825 `_. * Deprecated ``py::object::borrowed``/``py::object::stolen``. Use ``py::object::borrowed_t{}``/``py::object::stolen_t{}`` instead. `#771 `_. * Changed internal data structure versioning to avoid conflicts between modules compiled with different revisions of pybind11. `#1012 `_. * Additional compile-time and run-time error checking and more informative messages. `#786 `_, `#794 `_, `#803 `_. * Various minor improvements and fixes. `#764 `_, `#791 `_, `#795 `_, `#840 `_, `#844 `_, `#846 `_, `#849 `_, `#858 `_, `#862 `_, `#871 `_, `#872 `_, `#881 `_, `#888 `_, `#899 `_, `#928 `_, `#931 `_, `#944 `_, `#950 `_, `#952 `_, `#962 `_, `#965 `_, `#970 `_, `#978 `_, `#979 `_, `#986 `_, `#1020 `_, `#1027 `_, `#1037 `_. * Testing improvements. `#798 `_, `#882 `_, `#898 `_, `#900 `_, `#921 `_, `#923 `_, `#963 `_. v2.1.1 (April 7, 2017) ----------------------------------------------------- * Fixed minimum version requirement for MSVC 2015u3 `#773 `_. v2.1.0 (March 22, 2017) ----------------------------------------------------- * pybind11 now performs function overload resolution in two phases. The first phase only considers exact type matches, while the second allows for implicit conversions to take place. A special ``noconvert()`` syntax can be used to completely disable implicit conversions for specific arguments. `#643 `_, `#634 `_, `#650 `_. * Fixed a regression where static properties no longer worked with classes using multiple inheritance. The ``py::metaclass`` attribute is no longer necessary (and deprecated as of this release) when binding classes with static properties. `#679 `_, * Classes bound using ``pybind11`` can now use custom metaclasses. `#679 `_, * ``py::args`` and ``py::kwargs`` can now be mixed with other positional arguments when binding functions using pybind11. `#611 `_. * Improved support for C++11 unicode string and character types; added extensive documentation regarding pybind11's string conversion behavior. `#624 `_, `#636 `_, `#715 `_. * pybind11 can now avoid expensive copies when converting Eigen arrays to NumPy arrays (and vice versa). `#610 `_. * The "fast path" in ``py::vectorize`` now works for any full-size group of C or F-contiguous arrays. The non-fast path is also faster since it no longer performs copies of the input arguments (except when type conversions are necessary). `#610 `_. * Added fast, unchecked access to NumPy arrays via a proxy object. `#746 `_. * Transparent support for class-specific ``operator new`` and ``operator delete`` implementations. `#755 `_. * Slimmer and more efficient STL-compatible iterator interface for sequence types. `#662 `_. * Improved custom holder type support. `#607 `_. * ``nullptr`` to ``None`` conversion fixed in various builtin type casters. `#732 `_. * ``enum_`` now exposes its members via a special ``__members__`` attribute. `#666 `_. * ``std::vector`` bindings created using ``stl_bind.h`` can now optionally implement the buffer protocol. `#488 `_. * Automated C++ reference documentation using doxygen and breathe. `#598 `_. * Added minimum compiler version assertions. `#727 `_. * Improved compatibility with C++1z. `#677 `_. * Improved ``py::capsule`` API. Can be used to implement cleanup callbacks that are involved at module destruction time. `#752 `_. * Various minor improvements and fixes. `#595 `_, `#588 `_, `#589 `_, `#603 `_, `#619 `_, `#648 `_, `#695 `_, `#720 `_, `#723 `_, `#729 `_, `#724 `_, `#742 `_, `#753 `_. v2.0.1 (Jan 4, 2017) ----------------------------------------------------- * Fix pointer to reference error in type_caster on MSVC `#583 `_. * Fixed a segmentation in the test suite due to a typo `cd7eac `_. v2.0.0 (Jan 1, 2017) ----------------------------------------------------- * Fixed a reference counting regression affecting types with custom metaclasses (introduced in v2.0.0-rc1). `#571 `_. * Quenched a CMake policy warning. `#570 `_. v2.0.0-rc1 (Dec 23, 2016) ----------------------------------------------------- The pybind11 developers are excited to issue a release candidate of pybind11 with a subsequent v2.0.0 release planned in early January next year. An incredible amount of effort by went into pybind11 over the last ~5 months, leading to a release that is jam-packed with exciting new features and numerous usability improvements. The following list links PRs or individual commits whenever applicable. Happy Christmas! * Support for binding C++ class hierarchies that make use of multiple inheritance. `#410 `_. * PyPy support: pybind11 now supports nightly builds of PyPy and will interoperate with the future 5.7 release. No code changes are necessary, everything "just" works as usual. Note that we only target the Python 2.7 branch for now; support for 3.x will be added once its ``cpyext`` extension support catches up. A few minor features remain unsupported for the time being (notably dynamic attributes in custom types). `#527 `_. * Significant work on the documentation -- in particular, the monolithic ``advanced.rst`` file was restructured into a easier to read hierarchical organization. `#448 `_. * Many NumPy-related improvements: 1. Object-oriented API to access and modify NumPy ``ndarray`` instances, replicating much of the corresponding NumPy C API functionality. `#402 `_. 2. NumPy array ``dtype`` array descriptors are now first-class citizens and are exposed via a new class ``py::dtype``. 3. Structured dtypes can be registered using the ``PYBIND11_NUMPY_DTYPE()`` macro. Special ``array`` constructors accepting dtype objects were also added. One potential caveat involving this change: format descriptor strings should now be accessed via ``format_descriptor::format()`` (however, for compatibility purposes, the old syntax ``format_descriptor::value`` will still work for non-structured data types). `#308 `_. 4. Further improvements to support structured dtypes throughout the system. `#472 `_, `#474 `_, `#459 `_, `#453 `_, `#452 `_, and `#505 `_. 5. Fast access operators. `#497 `_. 6. Constructors for arrays whose storage is owned by another object. `#440 `_. 7. Added constructors for ``array`` and ``array_t`` explicitly accepting shape and strides; if strides are not provided, they are deduced assuming C-contiguity. Also added simplified constructors for 1-dimensional case. 8. Added buffer/NumPy support for ``char[N]`` and ``std::array`` types. 9. Added ``memoryview`` wrapper type which is constructible from ``buffer_info``. * Eigen: many additional conversions and support for non-contiguous arrays/slices. `#427 `_, `#315 `_, `#316 `_, `#312 `_, and `#267 `_ * Incompatible changes in ``class_<...>::class_()``: 1. Declarations of types that provide access via the buffer protocol must now include the ``py::buffer_protocol()`` annotation as an argument to the ``class_`` constructor. 2. Declarations of types that require a custom metaclass (i.e. all classes which include static properties via commands such as ``def_readwrite_static()``) must now include the ``py::metaclass()`` annotation as an argument to the ``class_`` constructor. These two changes were necessary to make type definitions in pybind11 future-proof, and to support PyPy via its cpyext mechanism. `#527 `_. 3. This version of pybind11 uses a redesigned mechanism for instantiating trampoline classes that are used to override virtual methods from within Python. This led to the following user-visible syntax change: instead of .. code-block:: cpp py::class_("MyClass") .alias() .... write .. code-block:: cpp py::class_("MyClass") .... Importantly, both the original and the trampoline class are now specified as an arguments (in arbitrary order) to the ``py::class_`` template, and the ``alias<..>()`` call is gone. The new scheme has zero overhead in cases when Python doesn't override any functions of the underlying C++ class. `rev. 86d825 `_. * Added ``eval`` and ``eval_file`` functions for evaluating expressions and statements from a string or file. `rev. 0d3fc3 `_. * pybind11 can now create types with a modifiable dictionary. `#437 `_ and `#444 `_. * Support for translation of arbitrary C++ exceptions to Python counterparts. `#296 `_ and `#273 `_. * Report full backtraces through mixed C++/Python code, better reporting for import errors, fixed GIL management in exception processing. `#537 `_, `#494 `_, `rev. e72d95 `_, and `rev. 099d6e `_. * Support for bit-level operations, comparisons, and serialization of C++ enumerations. `#503 `_, `#508 `_, `#380 `_, `#309 `_. `#311 `_. * The ``class_`` constructor now accepts its template arguments in any order. `#385 `_. * Attribute and item accessors now have a more complete interface which makes it possible to chain attributes as in ``obj.attr("a")[key].attr("b").attr("method")(1, 2, 3)``. `#425 `_. * Major redesign of the default and conversion constructors in ``pytypes.h``. `#464 `_. * Added built-in support for ``std::shared_ptr`` holder type. It is no longer necessary to to include a declaration of the form ``PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr)`` (though continuing to do so won't cause an error). `#454 `_. * New ``py::overload_cast`` casting operator to select among multiple possible overloads of a function. An example: .. code-block:: cpp py::class_(m, "Pet") .def("set", py::overload_cast(&Pet::set), "Set the pet's age") .def("set", py::overload_cast(&Pet::set), "Set the pet's name"); This feature only works on C++14-capable compilers. `#541 `_. * C++ types are automatically cast to Python types, e.g. when assigning them as an attribute. For instance, the following is now legal: .. code-block:: cpp py::module m = /* ... */ m.attr("constant") = 123; (Previously, a ``py::cast`` call was necessary to avoid a compilation error.) `#551 `_. * Redesigned ``pytest``-based test suite. `#321 `_. * Instance tracking to detect reference leaks in test suite. `#324 `_ * pybind11 can now distinguish between multiple different instances that are located at the same memory address, but which have different types. `#329 `_. * Improved logic in ``move`` return value policy. `#510 `_, `#297 `_. * Generalized unpacking API to permit calling Python functions from C++ using notation such as ``foo(a1, a2, *args, "ka"_a=1, "kb"_a=2, **kwargs)``. `#372 `_. * ``py::print()`` function whose behavior matches that of the native Python ``print()`` function. `#372 `_. * Added ``py::dict`` keyword constructor:``auto d = dict("number"_a=42, "name"_a="World");``. `#372 `_. * Added ``py::str::format()`` method and ``_s`` literal: ``py::str s = "1 + 2 = {}"_s.format(3);``. `#372 `_. * Added ``py::repr()`` function which is equivalent to Python's builtin ``repr()``. `#333 `_. * Improved construction and destruction logic for holder types. It is now possible to reference instances with smart pointer holder types without constructing the holder if desired. The ``PYBIND11_DECLARE_HOLDER_TYPE`` macro now accepts an optional second parameter to indicate whether the holder type uses intrusive reference counting. `#533 `_ and `#561 `_. * Mapping a stateless C++ function to Python and back is now "for free" (i.e. no extra indirections or argument conversion overheads). `rev. 954b79 `_. * Bindings for ``std::valarray``. `#545 `_. * Improved support for C++17 capable compilers. `#562 `_. * Bindings for ``std::optional``. `#475 `_, `#476 `_, `#479 `_, `#499 `_, and `#501 `_. * ``stl_bind.h``: general improvements and support for ``std::map`` and ``std::unordered_map``. `#490 `_, `#282 `_, `#235 `_. * The ``std::tuple``, ``std::pair``, ``std::list``, and ``std::vector`` type casters now accept any Python sequence type as input. `rev. 107285 `_. * Improved CMake Python detection on multi-architecture Linux. `#532 `_. * Infrastructure to selectively disable or enable parts of the automatically generated docstrings. `#486 `_. * ``reference`` and ``reference_internal`` are now the default return value properties for static and non-static properties, respectively. `#473 `_. (the previous defaults were ``automatic``). `#473 `_. * Support for ``std::unique_ptr`` with non-default deleters or no deleter at all (``py::nodelete``). `#384 `_. * Deprecated ``handle::call()`` method. The new syntax to call Python functions is simply ``handle()``. It can also be invoked explicitly via ``handle::operator()``, where ``X`` is an optional return value policy. * Print more informative error messages when ``make_tuple()`` or ``cast()`` fail. `#262 `_. * Creation of holder types for classes deriving from ``std::enable_shared_from_this<>`` now also works for ``const`` values. `#260 `_. * ``make_iterator()`` improvements for better compatibility with various types (now uses prefix increment operator); it now also accepts iterators with different begin/end types as long as they are equality comparable. `#247 `_. * ``arg()`` now accepts a wider range of argument types for default values. `#244 `_. * Support ``keep_alive`` where the nurse object may be ``None``. `#341 `_. * Added constructors for ``str`` and ``bytes`` from zero-terminated char pointers, and from char pointers and length. Added constructors for ``str`` from ``bytes`` and for ``bytes`` from ``str``, which will perform UTF-8 decoding/encoding as required. * Many other improvements of library internals without user-visible changes 1.8.1 (July 12, 2016) ---------------------- * Fixed a rare but potentially very severe issue when the garbage collector ran during pybind11 type creation. 1.8.0 (June 14, 2016) ---------------------- * Redesigned CMake build system which exports a convenient ``pybind11_add_module`` function to parent projects. * ``std::vector<>`` type bindings analogous to Boost.Python's ``indexing_suite`` * Transparent conversion of sparse and dense Eigen matrices and vectors (``eigen.h``) * Added an ``ExtraFlags`` template argument to the NumPy ``array_t<>`` wrapper to disable an enforced cast that may lose precision, e.g. to create overloads for different precisions and complex vs real-valued matrices. * Prevent implicit conversion of floating point values to integral types in function arguments * Fixed incorrect default return value policy for functions returning a shared pointer * Don't allow registering a type via ``class_`` twice * Don't allow casting a ``None`` value into a C++ lvalue reference * Fixed a crash in ``enum_::operator==`` that was triggered by the ``help()`` command * Improved detection of whether or not custom C++ types can be copy/move-constructed * Extended ``str`` type to also work with ``bytes`` instances * Added a ``"name"_a`` user defined string literal that is equivalent to ``py::arg("name")``. * When specifying function arguments via ``py::arg``, the test that verifies the number of arguments now runs at compile time. * Added ``[[noreturn]]`` attribute to ``pybind11_fail()`` to quench some compiler warnings * List function arguments in exception text when the dispatch code cannot find a matching overload * Added ``PYBIND11_OVERLOAD_NAME`` and ``PYBIND11_OVERLOAD_PURE_NAME`` macros which can be used to override virtual methods whose name differs in C++ and Python (e.g. ``__call__`` and ``operator()``) * Various minor ``iterator`` and ``make_iterator()`` improvements * Transparently support ``__bool__`` on Python 2.x and Python 3.x * Fixed issue with destructor of unpickled object not being called * Minor CMake build system improvements on Windows * New ``pybind11::args`` and ``pybind11::kwargs`` types to create functions which take an arbitrary number of arguments and keyword arguments * New syntax to call a Python function from C++ using ``*args`` and ``*kwargs`` * The functions ``def_property_*`` now correctly process docstring arguments (these formerly caused a segmentation fault) * Many ``mkdoc.py`` improvements (enumerations, template arguments, ``DOC()`` macro accepts more arguments) * Cygwin support * Documentation improvements (pickling support, ``keep_alive``, macro usage) 1.7 (April 30, 2016) ---------------------- * Added a new ``move`` return value policy that triggers C++11 move semantics. The automatic return value policy falls back to this case whenever a rvalue reference is encountered * Significantly more general GIL state routines that are used instead of Python's troublesome ``PyGILState_Ensure`` and ``PyGILState_Release`` API * Redesign of opaque types that drastically simplifies their usage * Extended ability to pass values of type ``[const] void *`` * ``keep_alive`` fix: don't fail when there is no patient * ``functional.h``: acquire the GIL before calling a Python function * Added Python RAII type wrappers ``none`` and ``iterable`` * Added ``*args`` and ``*kwargs`` pass-through parameters to ``pybind11.get_include()`` function * Iterator improvements and fixes * Documentation on return value policies and opaque types improved 1.6 (April 30, 2016) ---------------------- * Skipped due to upload to PyPI gone wrong and inability to recover (https://github.com/pypa/packaging-problems/issues/74) 1.5 (April 21, 2016) ---------------------- * For polymorphic types, use RTTI to try to return the closest type registered with pybind11 * Pickling support for serializing and unserializing C++ instances to a byte stream in Python * Added a convenience routine ``make_iterator()`` which turns a range indicated by a pair of C++ iterators into a iterable Python object * Added ``len()`` and a variadic ``make_tuple()`` function * Addressed a rare issue that could confuse the current virtual function dispatcher and another that could lead to crashes in multi-threaded applications * Added a ``get_include()`` function to the Python module that returns the path of the directory containing the installed pybind11 header files * Documentation improvements: import issues, symbol visibility, pickling, limitations * Added casting support for ``std::reference_wrapper<>`` 1.4 (April 7, 2016) -------------------------- * Transparent type conversion for ``std::wstring`` and ``wchar_t`` * Allow passing ``nullptr``-valued strings * Transparent passing of ``void *`` pointers using capsules * Transparent support for returning values wrapped in ``std::unique_ptr<>`` * Improved docstring generation for compatibility with Sphinx * Nicer debug error message when default parameter construction fails * Support for "opaque" types that bypass the transparent conversion layer for STL containers * Redesigned type casting interface to avoid ambiguities that could occasionally cause compiler errors * Redesigned property implementation; fixes crashes due to an unfortunate default return value policy * Anaconda package generation support 1.3 (March 8, 2016) -------------------------- * Added support for the Intel C++ compiler (v15+) * Added support for the STL unordered set/map data structures * Added support for the STL linked list data structure * NumPy-style broadcasting support in ``pybind11::vectorize`` * pybind11 now displays more verbose error messages when ``arg::operator=()`` fails * pybind11 internal data structures now live in a version-dependent namespace to avoid ABI issues * Many, many bugfixes involving corner cases and advanced usage 1.2 (February 7, 2016) -------------------------- * Optional: efficient generation of function signatures at compile time using C++14 * Switched to a simpler and more general way of dealing with function default arguments. Unused keyword arguments in function calls are now detected and cause errors as expected * New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward`` * New ``pybind11::base<>`` attribute to indicate a subclass relationship * Improved interface for RAII type wrappers in ``pytypes.h`` * Use RAII type wrappers consistently within pybind11 itself. This fixes various potential refcount leaks when exceptions occur * Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7) * Made handle and related RAII classes const correct, using them more consistently everywhere now * Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are now stored in a C++ hash table that is not visible in Python * Fixed refcount leaks involving NumPy arrays and bound functions * Vastly improved handling of shared/smart pointers * Removed an unnecessary copy operation in ``pybind11::vectorize`` * Fixed naming clashes when both pybind11 and NumPy headers are included * Added conversions for additional exception types * Documentation improvements (using multiple extension modules, smart pointers, other minor clarifications) * unified infrastructure for parsing variadic arguments in ``class_`` and cpp_function * Fixed license text (was: ZLIB, should have been: 3-clause BSD) * Python 3.2 compatibility * Fixed remaining issues when accessing types in another plugin module * Added enum comparison and casting methods * Improved SFINAE-based detection of whether types are copy-constructible * Eliminated many warnings about unused variables and the use of ``offsetof()`` * Support for ``std::array<>`` conversions 1.1 (December 7, 2015) -------------------------- * Documentation improvements (GIL, wrapping functions, casting, fixed many typos) * Generalized conversion of integer types * Improved support for casting function objects * Improved support for ``std::shared_ptr<>`` conversions * Initial support for ``std::set<>`` conversions * Fixed type resolution issue for types defined in a separate plugin module * CMake build system improvements * Factored out generic functionality to non-templated code (smaller code size) * Added a code size / compile time benchmark vs Boost.Python * Added an appveyor CI script 1.0 (October 15, 2015) ------------------------ * Initial release aoflagger-v3.4.0/external/pybind11/docs/cmake/0000755000175000017500000000000014516225226017607 5ustar olesolesaoflagger-v3.4.0/external/pybind11/docs/cmake/index.rst0000644000175000017500000000042114507760431021447 0ustar olesolesCMake helpers ------------- Pybind11 can be used with ``add_subdirectory(extern/pybind11)``, or from an install with ``find_package(pybind11 CONFIG)``. The interface provided in either case is functionally identical. .. cmake-module:: ../../tools/pybind11Config.cmake.in aoflagger-v3.4.0/external/pybind11/docs/pybind11_vs_boost_python2.png0000644000175000017500000012024114507760431024267 0ustar olesoles‰PNG  IHDRÏw³bKGDÿÿÿ ½§“ IDATxœìÝ{|\u?þ×ûs&I›&MS¡…‚P •"®—oÜ…®¢âéâÏÝ(ZŠ%93­V¨—õ² #xYtP$É9™–p©\²»(7‘…Å-(ª½@)M¡[è=M&çœ÷ï™°aȽ™ù$™×óñÈ£Ó9ŸÏ9¯3M:yÏçs> """"""""""""""""""""""""""""""""""""""""""""š¨Äv""¢¾V®\Y†á1"ÒYQQ±ýꫯˆˆˆ(f;ÑXK$ÿ*"玠˷}ßo×uo°¨ïsñxüÝÆ˜°ß÷ýÇ>ñ踮ë8[D~äyÞå¶óªt:m¶oß~yŸ0EU‘Ífà¶³ª•+WÁÃÍf¶µµí>”ýõù¿Ö÷ýoŒIH"""‹g"štD¤Àœt©íóø°|ßWŸ‘ªüsûÇ$àØyr¹êl Û¶m[&"_Êÿõe;Tõ763•l63ÆŽã˜CÝ_Ÿïñ‡º/"""ÏD4™=nŒI ÕÈó|ïcùOUÝàOEM6Dä¿Uõ ª>n;ËX‘æÞà,ß÷{læ!"""ê‹Å3MfûZZZÖ¤ÃDšþìyÞÕ¶3Œ%U)"‘û<ÏcáLDDDã ‹g"¢1’L&ç‡ax€=S§N}z´ ]¹®[EÑ<©q§£¥¥å¹±M:¸åË—Ï‘#qˆçŸýìgßÐÓÓ3ODŒª>çûþöÚŠˆ€(ŠºåxÙlöDÇqöVTTl(̾bÅŠã£(ší8γMMM/µ¿x<>ÛqœãÃ0TcÌFß÷wÕ'NǶmÛv<€ÃTuS&“yi´çs(V¯^=µ³³óMaN¯¨¨ØÖÜܼÙF""¢É‚«mѤãºîZxÐ÷ý÷Œ¤o"‘¸KDÞàë¾ï_™î="òKä «-ìãºnÀ?˜Ûçéý2A\¼víÚ}Ã9v<?Éó] ïu±[üÀ÷ý&Úç¸ë|\D¾ïyÞ%ù¬ˆÈÛ†:–ˆ<îyÞûû>—L&—«ê?8®à<ÖAðážGþ\c.pFßsQÕõƘ¯{žwŸó¸ À‡»Î< @7€Nß÷è®ë‰ÜôúgÃ0<3‹ýHU?‰ÿû`x‡ˆ\äyÞMÉdòmªšÁk{RU?ÝÚÚúº)ú©Tê½Q}À_÷y:ð€¯ø¾ÿÛþ2%‰•"òuGõöQÕÿðyÂ0|Ú5k^ÉŸÃ7¬VÕ;Z[[?ÓOŽwDQt?€È÷ýÃúœ{ï÷ø5¾ï®àu9LD¾«ªKT÷ÙôŒˆ\ìyÞ-ýe'""¢Áò¢%DD“I~q°)*†ÓÞuÝ&­ÈÎðÜŒ\‘{Q,{pÕªUÓ‡ÚO<?Úó+°YDÚ4ø-€cü8™LþSA·×e‘Dds_ªº@}þkOÁyü8_\Wp€ÏÇb±‡\×ÖÂd‰Dâlc̯¼Àöü¹ø6ŠÈ)ªzo2™|õZtUÝàwø¿Ù¶ø]o±9cŒÉŸËlÇqîSÕO‹Ècnð€Yªzc2™,8À½ù û0Äø€/õ^½jÕªªîîîfäF|¯Çãe2™g •JEÑjä Öó}ßõ5L&“ç¨jûÎgÔb±Øuæ!7"Žçy›z·¹®û1·¸$•JýwKKË/K‘‰ˆˆh²àÈ3Mfo3Æ<8ØWWW×1£Ý¹ˆôŽ_Ñ·p€µk×v¨êòü_—æG¤ªóòûücߦM›v%€ €>ì°Ãú¡ÊöíÛ¯ðq¯8ŽsÖµ×^û¿ýœÇU} gð}{E½…ÿ’x<>à4jÈߣy€M•••Ëû~0‘N§ÏóþQD‹¢è+£9—þ¨êU¾ï?Ðû÷5kÖ¼""7õþݳ¬ï5Ξç=àÏ "}ïÝýEä>X~tΜ9«û®ø¿~:™ï7Íqœ {·EQt!r—BÝTøzž÷3U-úânñxüÝ> Œ¢èÓ¾ïoê»Ý÷ýŸ"7@¢(úÇbç!""šlX<ÑdÖà¹Á¾zzzÅŒëº'8Dd]mZ[[EnªoÌqœ÷÷צ—ˆ<•øy×u¿™L&ç÷n»òÊ+ú¾Ÿð}ÿ»ÍÍÍ»F‘õ"U½@OE ÍÍÍO÷n‹ÇãÇ8 Œ1ýžG&“ùrS©cƘAÏÀóç³n€…ƹàƒétzLÞ‡Dä…ÏEQôBþáÎþË‘ ªSû<ýÁüsm…b@¾˜nË·ù0Õpf~ŸÿÞ_>UýIÏ%cÌYù‡Ìd2Oã§ù‡ï[µjUU±3M&œ¶MD“Ùú‘.6\ªz’ˆô>¾ÒuÝp€¦Ó@Dæ°ùíרê2ǸTU/u]w€Ÿc~vÄG<Ò_17”D"q6€Éãs™Læ¿únwç$ÕÜda^áºn0À®zJô<œÿó‰AÚôn«ïèè˜ `Ȭ‡â8NGásƘ n/¼¾ ªHþ²¡¡¡¹×Žã 'ÿñdË–-o¨¨¨˜‘ßçsýu¨¨¨Ø†}‹Œ>ß“Gº®ûŸ4ë]@¬ª»»ûh›hGDDDX<NßųÎaû×iiiÙáºîB_p€Ã‘+T¿EÑ—;:::‰Ä[[[onÀd2ùNU½€£ªßö}ß,—ˆ¼÷PÏ@ïâh®ÌmŒÙ×[HÆb±©µ édó@¼Æ¬Y³j{zr³´ƒ 0¿ˆìËå •••3z?€0Æô{[ªæææ]®ë0&ç;€Þ›YÈMßn{"""NÛ&"9ØÝÓÓ3Ëqœ™ƒ}øÚPûô}§ïû_صk×‘Þ à[z§ßΑu‰DbX#éñxü8U½¹‘ïö£Ž:ªß–£(ê=¬1fö0Îc¨ë”ä÷[3Pƒ ¦÷yüòpÎg(ÙlV‡n58cLïjß‘óGQôêíííYU}u*½ªV÷×'?EzÊ ‡ïwuwU¬O¡N 7e~¨GÇqfîÚµk°Ñu"""*À‘g"¢Qˆ¢hsîNI¨ªªªšÝÜÜüÇþÚ566ÎÙ·oßÎÁVÈΓåË—†áKmmm]ÈÝ¢ê·ÒÉdòͪúsä¦/Eî¶CZ¾|ùLcÌÏÌð€eMùvgsEPÁ]+;Ü󑪺À_¸m€f•ÿs—ïûƒ—ÔÕW_Ýíºî Ž‘¿ðëþÚ‰È[ó·€ïû/»®»ÀŒ(ŠÞ`CaŸ®®®c{§‡÷¥ªÝ"Uí÷vfƘ#Fp ›òûEÑ£ê‚ ø;äýê°´ïýŽûEÑ7Œ1pbEEÅÆd2y‡ªv8*Š¢¿PàÑššškÚG"‘x?r‹@†á-®ëÖÔ>Š¢³3™ÌSsæÌùQþ<>®ª7»®û9U]Ÿ?ÅÈ-@Õ%"Ko¸á†íššš¶&“Éåªzƒˆ,p†ëº?ÐÓÑÑñ~ä ÏÀ—=Ï{d°}ÙÉdžL$‰ÈEä+‹]×½OU¥££ãÃÈ-âÖ£ªÉ¾·üò<ï‰D"ñ5ù>€ç?„ø­ª‹Ü÷ÇsÈ]ó\Ù÷x»wï~ ¾¾þ opK"‘X)"[¼À[´çû;ȯÎðK'AðT"‘¸Ý³ ÀUýH~?Çb±oŽþU"""*Oy&"¥t:íÚµëTõË^TÕE"ò…|Ñx8€Ed‘ïû µ¯L&ó¬ˆ,BnºVU—ø2€O€ˆ4e³ÙV„cúfG W?Зã8•}Îã¾`;€ÓûœÇ,yHUÿÖó¼û‡óºxžw‹1æ ä®>Àg\„\áü€ø¾åpöeCkkk“ª~À¼ÀçEd€y"ò_"òžÖÖÖúé÷/ªúi›Uu‘ª~ @€ßFQô!ô³êw{{{ÁYªú3š_ñü3Èé?¨ªªZŠ\Q<,¾ïÿ%‹½KUoP!"ŸRÕ/©êÙÈ}ó㪪ª÷655íbWDDDTàu×sѨH<_àH{‚ ØÔÖÖ¶{4;ZµjÕôžžžcÂ0R6òñ=òÐúñ=rôD¤ZUßàéÑôÅbéééyeŒc?ÉdòL×u.űR©Ô)ãy¿‡²ŸÑöI¿bµ-Ë–-›‘H$Þd;Ç`JýoV¬ãÅãñã.¸à‚Ãu?®ëV§R©·Œ¶ÿhÎo¤}†Ûž?¯7Þ_ùøyhýø9zK—.–H$Nm×uw766ÎËLDTÆv>U-Ê'¼cµßCÙÏhûޤ_±^¿r`Œ UµÇvŽÁ”úß·ˆÇë1Æ„‡º“l6…a˜mÿÑœßHûðgrôÆûkg#ß#­ßxÿžÏ;ì°È3êÿo‰ˆÊF)Gž©tø©:ÑøÁŸG¢ñ…?“c‹#ÏDGž‰ ÄãñEQ-ŠÇã³mg!*w©TjVE‹’ÉäßÚÎBD@*•:-Š¢E+W®<Âv"¢RcñLT@DX "u¶³•;U­° ÿED–…ax"€Ùl¶Þv"¢RãjÛDŒ1ëlÃp§í,Dåγ3Š¢›£(âJÛD〪>fŒÙRUUµÃv"¢RcñLTÀó¼'lg ¢œæææ]î·ƒˆr2™ ïELDe‹Ó¶‰ˆˆˆˆˆˆ†À♈ˆˆˆˆˆhœ¶MT Ÿ Ú³Ñ÷ý=¶ó•3×uë¢(š 3“É}º†á~ß÷{lç!*g®ëV8ŽS³wïÞpݺu{mç!*wµUUU±;whooÏÚÎcÓùßý7=r€ãivÔܳô²;ß}Ã7Ïæˆ&8Ž<¨®®þd†ªê`o†DT"27 à kjjε…ˆÇqÂ0¼°®®îÛY¬ËV]ŠÁ ç^Ó%’kЇˆŠÅ3QÉŠÈA mg!*wƘPDFQTÖ#\Dã…1†ï‘®¸u*ËFÐåŒeé;+•§mð}ÿ:Ûˆ(§¹¹y3€Ëmç ¢Ïón´a<˜ºêÛT¤O(r€¿'•Gž‰ˆˆˆˆF@£XýHûÁˆûÑøÂ♈ˆˆˆhŒ _i^,F"*ÏDDDDD#°%šö / ‹ÂèE DD%Ákž‰ $‰sÌVÕÛ3™Ì³¶ó•³T*57 ÃsTuG&“¹Év¢rçºnƒªÎ‘;}ßßd;-¿LŸ,½ôΉʷ†Ó^Tn¹î‹·;Gž‰^¯VDêE¤Âv¢r§ª"Rï8N­í,D¨j­ˆÔGQTi;‹m3f˜ËydMŸà\Xô@DTt,ž‰ ˆÈmAø===ÏÛÎBT»·Aàg³ÙÛlg!"@Dn‚À‚ ìgf]ýù³ºCŇìÿ§ßB£E7¤?´£dÁˆ¨h8m›¨€ïû;mg ¢œ¶¶¶.¶sQß#_k]ú¬½>~Þ¥w.2‘œ Á[8€lô¶ë/>ëvˆ¨íœD46X<‚/>û!½nÃ%¥ÏBDÅÃiÛDDDDDDDCàÈ3Qx<¾Èqœa®Ïd2#¾#T*5KUO°Çó¼mç!*w©Tê4Ué8ΣMMM¼o1•Ž<‘ªºPDêlg!*wªZ§ª ,°…ˆ€0 OTÕ…Ùl¶Þv"¢RãÈ3QcÌzU­¢ˆ‹¢YfŒÙ†á}Qí·…ˆU}LDž©ªªâêÑDTvX<ð<ï Ûˆ(§¹¹y€_ÙÎAD9™LæIÛˆˆlá´m""""""¢!°x&""""""§mˆÇã'¨6Ælô}íì8Î---;úkßÕÕµDDŽð9Þž¨¼%‰sÌVÕÛ3™Ì³¶ó•³T*57 ÃsTuG&“¹Év¢rçºnƒªÎ‘;}ßßd;Q)M¸‘ç•+WÖcnpª1ffmâñø"ÿ#"ËEĈÈTùJE§R©¹ìú\=7):Mµ"R/"¶ƒ•;U­‘zÇqjmg!"@UkE¤>Š¢JÛYˆˆJmB<»®{L·8u 6Ë–-›bŒ¹@OEïËd2¿€D"±RD~†¡àƒ}û¬X±¢> Ã÷¸÷šk®y¹ˆ§@€ˆÜAeE¯ØÎBT»·c|UåŒ ¢q@Dnç{$•« Q<§ÓéXGGÇ*ßP àÞÒ_ÛŠŠŠs)"—öÎÐÚÚÚäºî‡Edq2™|³çyîÝÁiùQÆ{G“ODª‰ÄÉS¦LÙzõÕWïí}>•JÍ ÃðpyÅ÷ýí½Ï/]ºtÚ”)SæFQÔ½fÍš}÷•H$N€ 6<ýË_þ2賯¹aNã1Š ß÷wN†óà1xŒÉpŒŠŠŠzÑ÷ù‰v<1YŽÑû™J¥æ&‰ {ãì"š&Ä´ííÛ·à ;1ï‘[j+"ïËÿyW?›ï€(ŠÎêû¤1æ]ù?ÓOŸ!©êá"rQWW×Y©Tê”Þ/ù¨ˆ4ˆÈ;ú¶Ÿ6mÚá"Ò`Œù`á¾òíÞøÆ7Võ}> Ã÷ŠHCWW× º¼™Çà1x ƒÇà1x ƒÇ÷ÇxÍúq¹HU'Ä`M‘gÇqöA°lΜ9ëÒétL&ϤùÛÀó|áÙ¢ª‘7l:!œÑ.|Ñ)":޳¾¹¹ysï“ñx“ù™í<6•´Šþd8mEôŠËŸÞWìLDT\œ&BT@D²"rPDF:‹ˆÆ˜1&‘ƒQemg!"ÀÃ÷ȼcnÁ5ÃhzïŽ`ÆeEDDEÇ‘g¢¾ï_g;å477op¹íD”ãyÞ¶3Œ'Ç,ßø¹-™ùMãõ ©uúÃÿ g|ãÉßñ20¢I€Å3Ñ(ßðà 7λ¶²F„7‹¨5›³At×¼›ú½­*ML,ž‰ˆˆˆˆÁüó6îp«íDT\¼æ™ˆˆˆˆˆˆhy¼Ïóä’H$Î0[UoÏd2ÏÙˆŠ&•JÍ ÃðUÝ‘Édn²‡¨Ü¹®Û ªsDäNß÷7ÙÎ3Qñ>ÏD‹ç1Àû&"ÏTUUí°…ˆ¨ÔÄv€‰.™Lž àrI€1f{SSÓV˱ˆˆˆˆhœJ&“óE¤Â0¼/ Ãk×®åˆÆ9Ž<U=èyÞzÛ9ˆˆˆˆhüóý½;ë+²²LïSÅlìRèÃ1SqíµßøPÙ}XnŒÉ8("|<žçmè}ìºnd3  ŸØ0Ñ%“É3U5íûþi¶³ÑØ9/}÷ÇŒèZõýlîRѯÝpñÙW•:M.®ëî‚àÍk×®í°…ˆÇi"DDDDò…ó¿£ÿ¦ˆÊ•ç_z×WK™‹ˆˆìañLDDDÔDzôm3Œè ç÷$ÅwλôŽ·?ÙÆkž‰ˆˆˆúP©¼ÀÌa67Få³Ü"FWv\srMgUöïD¢SE¥ÐÀüç1ñ ÚÎFDTL,ž‰ $‰sÌVÕÛ3™Ì³¶ó•³T*57 ÃsTuG&“¹Év**xt$=ä}ÅÊ2Þüì{§_µ·â—W@k ’™€~ãù̼ßtéã›6ÚMIDTœ¶Môzµ"R/"¶ƒ•;U­‘zÇqjmg¡2¢˜5ÂG%Ç8ó|ë¼o?üÅÏW˜°¦¿í ¼;‚üæÿø7•:Q)p䙨€ˆÜAeE¯ØÎBT»·c|Uí±…Êˆ`÷ÈFž1éß/¶øóNVÁ0ôZÞs³¦ñNIƒ·`"¢I…Å3Qß÷wÚÎ@D9mmm]xû*)…>,Ž ÃCEŒ3>|Ãÿ½ñ[Žžÿ`Ã]ÅŒDDTjœ¶MDDDÔ‡]ààpÛD­EŒ3^|d$èˆÚM,ž‰ˆˆˆú¸þ‹·©èׇ×Z[ÛÒ‹YÔ@–m½õè©IUS¤8DDÖpÚ6Qx<¾Èqœa®Ïd2/ÙÎCTÎR©Ô,U=ÀÏóx*™.>ûªó/½k ßàôßJ[jççJÌ‚£ÿüB÷óGÏë0ì…4Ut#YÁây ˆÈÔT*u c¶755mµ‰FOD¨êQ"ò4ÏD©jª.‘,ž©¤®¿ø£ÿü™Kï¹C5¸0w;* È.Qy84QÓŸ=ù¯u iD[ÖÈ ú®awŠð»"Fšð’Éä|©€0 9”h‚`ñ<Tõ çyëmç ±aŒY¯ªµQqá0"ËŒ1;Ã0¼/Š"Žb‘×]üá?pmç°MTÛnñ܃ÜRÔ@œçyz»®ËUɉ&ÏD<Ï{Âv"ÊinnÞàW¶s•»}Ó«25û²Ë†3ú,‚ËŽŽo|¡¹ˆˆJ‰ÓDˆˆˆˆhP'âOY bç@ñûA*®zcãÆï•(QI±x&"""¢!ÍM>µ=Ч)ôË€>ÝgSÈýPù౉«E ÖB§mˆÇã'¨6Ælô}í}út' Ãý¾ï÷ØÎCTÎ\×­p§fïÞ½áºuëöÚÎCTîk«ªªb;wî<ÐÞÞžµ‡ˆ¨”8òLT ººú“a^¨ªÇÙÎBTîDdn†ÖÔÔœk; Žã4„axa]]Ý ¶³•Gž‰ ˆHVDmg!*wƘ0Š¢ƒQq„‹h0Æd¾GQÙañLTÀ÷ýëlg ¢œæææÍ.·ƒˆr<Ï»Ñv""[8m›ˆˆˆˆˆˆh,ž‰ˆˆˆˆˆˆ†ÀiÛc@D¦¦R©SÀ³½©©i«íLDDDD4>%“Éù"Rar0‹h‚`ñ<Tõ çyëmç ±‘H$Î0[UoÏd2ÏÚÎCTÎR©ÔÜ0 ÏQÕ™Læ&ÛyˆÊëº ª:GDîô}“í<•çyz»®ÙÌBDÃÇâ™èõjóŸWØBTîTµBDê1mg!"@UkE¤>Š¢JÛYˆˆJÅ3Q¹-‚Ê(Š^±…¨Üuwwo5ÆøªÚc; "r;ß#‰¨\±x&*àûþNÛˆ(§­­­ @‡íD”Ã÷H"*g\ €ˆˆˆˆˆˆh,ž‰ˆˆˆˆˆˆ†ÀiÛDâñø"Çqf„a¸>“ɼd;Q9K¥R³TõT{<Ï{Ðv¢r—J¥NSÕ™Žã<ÚÔÔô¢íó­».Pà’Á[é ú³ ¾ý‹·_ûm-M2oV¬XqbOOOM›ÚÚÚvÛÎCDTJy&* "§c«êlÛYˆÊˆÌ2Æ,vg‘í,“ÕÒübš—³ùÌ0 ¾UÔ@ãØ‹×¿uší ¶Apš1fq,;Òv"¢RcñLTÀ³-Š¢ÍªÚi; Q¹‘ÎüÏã6ÛY&­=pøð;hêÝ]U´<ãÌÖµóÞ³%3ïg[2óöug;÷oÉÌëÚ²fÞý[Zçýƒ*Äv¾R3ÆtDQ´ÙsÀv"¢Rã´m¢žçÝm;å´´´lp½í“™ˆ¼u„=j^y'øsQš†Ùrô¼‰"¬.ØTÅû xß–5ó~Úáu.™“ì(›[=Ï»Çv""[8òLDDTÎ#E„SŠe<ÙúÆÒ‚×ί!ÀÇzbÕו*ÙÅ♈ˆ¨œ ža¨ #í3¡l½öøùªòµa5VüÃs­ÇŸUäHDD4pÚ6Q%K–LŸ>}º†á~ß÷{lç!*g®ëV8ŽS³wïÞpݺu{m癌'vw†ù;¯Iø•"Dz* ÍÁïHN@Y\òÓØØX[UUÛ¹sçööö¬íN§#p]÷ïlq' à!«!©ä|ßßi;å´µµu質 .½ûk#è‘Zž¾çÒ5é¿2fƹMÞñuNÌù€Q=&‚öˆèŽ©Ýüˆ|¼œ‰øIDemÔųëºuùk„Ÿ›¨ÿ‘FQô1ÕªúÝÞÂ|ßßžJ¥N‘=ãÑ[ú­»N†È±#èR••àýÚ‹•i¼xÌ[Xq˜Ù“ÁEP­VTðüÞy›¶ørѱî†;mç$""²eÈâ9N›ŽŽŽÏXàûþJH&“WÕëUu€l2™ügÏó.)vر¦ªïݽ{÷#+W®<¢§§çL©‘‡ZZZ·ˆˆÆ–9:ºYsL¢Œ+ºõäÊš½{îpæMN€ÑÛŸËœðù¹ñM?.e6""¢ñbÈâ¹££ã;¾ `€•Ë–-›¢ª­¦¸À“ɼd;Q9K¥R³TõT{<Ï{ðP÷§@çHûtÒ¯¸]»¯û»:páÜKrÕskæýnîò”$;©Tê4Ué8ΣMMM/ÚÎCDTJƒ.¶zõê©>àÉ(ŠÞ •••ï0À¾ïŸ‹Åþ ÀYQô´}¸®[×ÐÐ0äJ •étºß ¢(ª0À"r!€ÃEäd¹Àç“ÉäçÆ65M"²@UŠHí,DåNUëTu!€c±¿ª)•OÈŽ¤ˆ>6ǯž½vîªX5ÌæŽ(¾UÔ@4®…ax¢ª.Ìf³õ¶³•Ú Åó¾}ûÞ À·ûÜïöc ª·@SSÓ~¹ À[‹´¯x<þn/Ïœ9óïj“H$Îu]÷Oõõõ:::º‰Ä¯X={*€Ë<Ïó}ßßéyÞŸ{zzü¯ª^X¬s ñ˳À}QMÈkù‰&cÌNä~×Åþü¯ž¹G ?A—ÿ¹î›ýýX{¼’0v€‘ÜvèŒMÞñüp±L©êcªÚa; Q© :mÛqœZUEE½ÓrÀÙ²"ÒwÑN‘2¾F2™œ¯ªÿ1Øñ‰ÄJ¹Às®P!"q¹?•J}°¥¥å— "{Àóó¾ý×®]»/‘HüZDÎY½zõÔ+¯¼ò`±Î‡ÆÏóž°ˆrš››wøÕXîÓÑè«Aî¶„Cœ*² "“ûòÅ õˆqŽð‡â¢ñ,“Én @|T$éÜLKX J|D7@Y»]R¨-]h“&™{¿¿?Î ™N“I&Íäf2Ÿ÷‹yerï9÷|g’2ùÞ³e ¯ƒm°bmýtfQ¯*`§–öeÓpRD"ªrœ ÈÿfêIÿ<ÀÀ?Bókkk«àó° „ýÀ»üe̘1·€ª^à"OG"‘k dYYÙ~Îp;€w‰È_û*+"³SOwé-‘?€ªžo¾ùæo<-"—×ÕÕ®ëŽÛ¾}{Àþªúƒ†¸‡ˆœ%"'Åb±cÓ‘ãEäà̪:ADŽ‚àݽÄx¼ˆ?f̘²¬ãG¥Îíu­ilchÛ¨­­=¼¶¶ö˜Ô^æEû:ØÛ%m|TDæVVV¾c¨Û¸ãŠSÖÝvÕi_óúƒ?*{ãwß+ëXwHÇáÛ÷¼ýª3ν㛧¾T„ïÕ Ú¸ÿ•C× ?VÖµW/ûÅŠ£vêy ¯ƒm Oõõõ³RÉàqÅü:Bjc§¿ƒ ø¸ˆœ…ašú8ÊD¼™ãáø€œä99edŸD½"÷{Ö ›@¯ÝQébؤv(ô{m*†¶!noÈõ»U•çy¿©­­å8ÎÉAlܼyóCwÓ~ àwãÇ¿­ó‚Uu½ˆÇ—@4ÍUü(//ßeû„ ^¨ê,ÀÞˆÅbŸRÕ{üÊuÝ7`çÀE\—ÇÖ[›Uõgªúì¢E‹2ï(nPÕƒa ß&"[Tõ cÌö^^ë°cÇŽî¬ãÏX£ª; 3‘U©:lcˆÚH}ÀMQÕ;‘škYŒ¯ƒm°ÑЀUõ£‘HäýÞ^¸kH_‡ï?aü·°yÅëZ¿Óê¤üóøOGå@ýaö5³ŠŽÿ[¿ß÷Fâë`ÃÓF2™œmŒ™Á¿¼\¬¯#¤6vù;1™L.O%Ð4´ÿÖÞ IDAT €½œšzÌ0yî¶0  9õõ¾\¿2õ˜ࣰ£Ž?»eñî:@À>(Lìâ(ïÂD£Ño¨êµ"rN<¿+óœëº¯Ø{òäÉå AÖ¹÷ø»ª>ØÜÜüö°ï¹sç:{î¹çG¥ª¾ïÿvñâÅËËɪÚàyÞìþKS1ˆF£§ù¾¿7€ß'‰5ýV ¢‚‰ÅbS’ÉäG1=Ï{ ìxF³U‹gþD—ä(²]5˜7½nåƒÃ8Ñhôß÷'có<¯àëÝ”×u7'“É#–,Y2â{ÝF/HO=Àº¬óåf8ÀûRǾàËÃ]á|Àõ^GŽ5 úð!ôŒÌ½½/ƹGêº `GÀ¯0¸žîl ®°ög“éØQÎÈ=?týö<§ÕÖÖ¾_DæŠÈáV{žF£Ÿ‚`kssó#Œ1_•¶e'Î)[@DÆfL OÿmêA%.óC¢bÑ¢EkÜv¥`Ú‚åŸ_•˜ñ„ €ÌÊ8åx_›^³òù£"?v 4ò¸ ¿×…È$3¶kã’¯žùÖ07ÿ'+û8×›0~@ 6ëm”S©ùìÐì¾$üÀûa{ìðÜ0Ä5âõ›<744DÖ­[׬ªf~Tõ3"rN]]ÝMS¦Lù}$¬Ã­@5l¯úNÛ‹cªƒ €ˆð Q–iµ+~ à§«3f˜©0í¦Ìyî€ ^ÜvlD4¨Êù×üz€…; Ç vDpþÕ< hs‡¶Ç[æ…=Lº6þlÛáž5¢âÐà[Ò[ Lž `u¿¶¶¶ëTõBU} À¼ÔW€ªÞà¹tݺu#e¾Æf‘K/½t—ÕäTuÏÔÓ-Ù爈ˆÈšZ»bùÔÚM«]ö8g"Ê6÷w=ïš[ý) ÀÎ9ÅQ€üx¬Œüs×Ý»oX1fÈ\±¯mööðmرvÕéUÃöºæ²'ìpäØ;Zg ìBÇïÉQoØžðg`çb°s‹ïðiì<½vìÙÚŒ6Ó£fßßO|ƒ•9Òh¿Ô×kSm¶ôS÷ìT¹Ÿ8:õü¼Ô¹Éè‰ý]½Öæxv”@ìPï`צêËXØáüNÕSØ÷óï£ÎqY¯çc~ û;X àÀt…œ=Ï—^ziuggçB˜2eÊÉ I×uÏIÞÜÜüÈ‚ Žwçù .pW®ë “—ÜÞÞ> ÀÖ¬s“@U— eƒ"26µº6Œ1ëWåõixÍŸ?¿ºººÚñ}›çyÜË”(D®ë–9ŽS¹uëVéÒ¥ÙÿO'¢aVSSSUQQÙ°aÃöÌí˜(?Ñhô™¾ïÝVUc·ŽO@ð™~ŠW–ŒÜ;·áî…Üý‘Ô×u^èåüIî†]` °IWÀT5.ðE?î¥îq°ÉYæüã.Ø·Î…]¨ì*ؤ3Óþ°ÉaæÜß°‹iÍI=–Â&œ `lb—Vžñ}¡¶ žšñ<}b€o¤ž[ýfù"ì\ó›aóÆÌØÇf|¿gV=à!µ=r†ƒaç«À±6d?¶—üˆŒc]°ïç§R%°C÷3ÿ¶ß;˲Ôõ¯ÇÎ7-àø €¼óëŽ;Þ  BDšúÚïxñâÅoªê=";Í ˆüŒ1È>§ªéE½þ’}nw¨jÇ¢E‹ž\´hÑ“Lœ‹ß¸qãÎò}¡ªv,D¥ND¦û¾¿°²²òì°c!"Àqœ¹¾ï/œ0aÂŒ°c)fñx|YúoG Óìü†û?Á9,~ÜXSé4 ¾Mp%€KSß »®¶}$€{a“¨×ü€1°Ééqþ»•Ø€]^óA€M„×ølbXà݆MÄ®PŸU÷zØÄylòV‘ª;=½ óѳP×3f¤êv®©Çïû{#é³ÏÓÛ·ÂngØ×Û›CѳHÛ­©º3ÐsóazbÏÞ~x lâü{'Ø v¨ýâÔùƒ|3«Nì{}ló%°7*RmÜš*Wà»}Ä<Àw`ßçOÂ&Í3Så5Çw€~†mcÊSOss6Æ8°?ðÐ%“ÉŸHŠÈW.¼ðÂ=ÒÇkkk‡]ï•É“'ê—ŒFé‘ñû/MD…dŒñE¤#öpÆ~F–8“_2¬Zèäù1ØÑôãuØÜå ØU¥·ÃwîmñÉïÀ&_a{‰žûI'Ã.H?ÀÎùÎÕ°IÕ6ØDï§°½Ç€Â}:lR—ngŒºgd\ãwm®]é:=¿8›ÜgJÏ¥¾öFDo¾Û‰Z {o[–Ý„Þ÷(ÕF9€ªœ=Ï‹/~-µ@ØÅÑhô‹ ;%Û_|ñÔd2Ù ûæ-Íu­¡¤ª6õÕáyÞ宀¾öd“ª~º¹¹ùþÞêQ4×¢M½Jv˜¼ëäá ѬÇBÿÛk\ àK°I^æÜ䢧ç4×6¥EÏÛôÐ÷ÂöV6©ëË °=˜éöÒÒ’ø?ØáåïEÏ|Û×P¸Ä°Ã™ÉzÌBO⬰=Àï𬺄]c °CË3`:lò{ç cû{ÇÓû CϺ]“`‡‰¹[Ñ“ä°2Ù¯3-s~uU¿[U‰H-€'Tõûmmm×"u'ÀuÝg“Éäa""òÇòòòŸôw­¡âyÞ÷|?Gõ<ïÛ 7¬_¿~ÿÎÎÎí‹/~3Gy"""""ê—¼Ûƒ7P~GuÇ  ìpé¾öyl‚w;ìpÝï gXñ~eVdWʲv^tºNfÝ\m§ëÎÄΉûaçEà¨ÔãjØaÛ÷ vá²B¸».öåÃw_ ›H®ï§þµ°½ï_€í¡zz†}-ùêFßûpgöF§ozd¾§ýý —÷R'Óæ>Žgþ "ý&Ïžç­p]÷=ªz­ˆÌ…½{ï€SÐÜÙÙùíx<ÞÙ÷U‘žÍ¼ˆˆˆˆˆ†‚âQòY0_œ×ÛÜÖá²vq«Óaé(ìèñevôR/S:ÏIçN»S°9Ô»a‡DŸ ÛÃëÀI¾$õxv˪—0ôîð‹Ý¨ß»ÍÖDØ÷õ°=ÂéØ;d;ß›ã2ž÷—‹öösÈ4 uúMžÀó¼ujçÎÝk¯½¦ú¾¿GYYÙF®,mq«ªÑ¥®®îlûªê}‰Dâ•°ã!*e±XlºïûgªêúD"1¶C$*i®ëÎUÕÉ"r¿çyýõôPŠy«*cðã@Qƒ~~›Ê Ñ€< ›ä9°C–ŸÃÎ "ïžÅ¸z“ÞR)Ý›Oݽ²ê¦í€^º(uý“a“åÓa“ó#`“Ò£°óœã‘` ìüâÃÎqþìb]U° ƒÝ7Lqdÿréëç—œÉóe—]6vûöí?‘–x<þ—ÖÖVÀ«Ùå\×]`‚çy}-Y>ª©jG<2ì8hÈT¥>ÐÊ„¨Ô©j™ˆL4Æ„ÙkAD)ªZ%"ƒ (ï¿4õ%/K?w]w¤%F9µ\yú³ç_}ÿu€do´+ÑŸßvåiÿ‹†ÂÇÕÌý„·¥¾f.òu4úÞòi<ì|` g(rvݾ†nG`GëfÖM?vaÀ&ß?K=ÆÂ.BV›@ »âõHÓ›<Ÿ Ûü_©ã™«ŽÚ«°‹|•Ãþ~£ì»S_3œüm9ïmß¾½€AŸ{8Ï;×½CrÜîB4RˆÈ=ÉdÒëîî^v,D¥®³³su2™ôºººî ;"Dä¾d2é%“IŽÌ*a·]yúU¢r r÷ˆÞn‚ñçAD‡+®>L@ÏÊØkÐ3¥óiôÌs½0GýùèéPI/Jõ<ìvFýÕýtªý̺'ÁÎë}À;{©Ó»¢uZæüòôÐâ‘ÐÁsl/ó8ØUË?‘:Þ×íôïÊPÆÞŽž-¬ÎEßÃG£'yε°X¿vi ®®îëÆ˜Ï€ª: "WE£ÑÏg—M•Ùv|þv'¢‘Âó¼ ý—"¢áÐÒÒ²=+lQÈøI½¸êÂkøy z)€“™›ŒþÉhàµ4Ìy,Ü Qàð‹„MN»=I\'ìþ¿—Ã&^¿==è(Ø­“»]Õ¿RÏÀ`wô™ ;ü:ÓL7¦ž?à‰Ôó§a{fË\;Ü9û&Dzîðvôìù ôìé<v˜ræ"W{ÁvhÀ3©G!í€í)Á®l^ »'óßú(ŸŽ}lo~_ ƒåëFØ}¶€ýy| öç“¶l/9üÀÿîNc»$Ͼïß*"_‡³ž6]U§ç¸ÎK©:DDDDDTZ®<ýYnÈaü»&Ÿãa“ÓLøAÖ±ka‡¿va±OÃöLvÂŽªua‡Q¿‰ž•¤Ón„íq=@lâzl’øؤ² v˜ø91¾›À©øoƒíO'Àéý§¿»ÍRZzćMŽ_ðCØÄÿ`ôôú^Â'Ï€MJc°7 Òß÷%ûØaèË`_ߣ»Ã}–Às¿ öç¶v‹©ÃSñí»Y rÏOï×.Éó’%KÚ.¾øâɪZÖÕÕUí8ΫªzI$Ùe¡énllÜ–}œˆˆˆˆˆhLèçü+°Éí`çÇfÚà£<ó|6õÈô'ØžéW³Ž'a“ÜŸÀÝ>#õÈô÷TݳŽßÛSûï®[ðvÁöæ^—uüÑÔ50-õø+rÏõ-¤¿Á&ÂéEÍrííüìöXï€ï}ì¢c»›<@ì(µ/Ãî㜽—ó+°[”ýqwêu\x:!>õÔSÛ§NðhSSÓ¦ÝmŒ¨ÔÖÖžà8ξï?™H$ ¹A=õ#‹MRÕãl‰Çã‡Q©‹Åb³UuOÇqžjll|=ìx¨dýÀºçØÆú[Ãf+€³a{¡O‡íEu`“å_óîK€®‡MœP‘ªû[ôÌÇͦ®‡¶}ì0ì^€Ýë¹·)KŽÏ¨óVF+`·ävÝéëÎK=ïkhõ`ü6yþ ro¼¶WøS°ïÓô$³§b˵]Ôãè‰?{K«À7a‡Îv‘µjØŸýŸR×ïm~þ?2®Ù×>ÏÿÎ(󟜫mO:u ì<€ƒêë뽦¦¦þ6/I"bjjjª`üøñ]7ÝtÓˆÛóšNDSÕ)"ò&ÏD!RÕ ªzŒˆ´Á~pQˆ|ߟ%"Óººº–ÃîUKƒpÙe—ݲeË€¶Œ¥^-CÏJÕCå9ì<¿8/c×!á± ÀMyÖIÏ5Îö&ìJ×}ù€Ö<ÛêO9l"ØùãýiGï½ÓËS\^K=rY ;Ê` Ö¡ÿ÷d}f™œÿh#‘ˆŸL&«E䫾ïÙuÝGUõVù_ÏóÚsÕ-1eƘ »»{#vsÿ0 —1æIU­ ‚€‹¢…̳Á÷ýG‚ à!¢@UŸ‘—+**ø·Înxë­·ö2Ƥ×’Pƒ!¼s`{Àƒá†2<úýÇz饗Vtuu}\Uσíf/ƒ¢p¿ªzÍÍÍ¿ÃÎ+š•”h4z²ª6xž7;ìXˆˆˆˆ¨¸¸®»9™L±dÉî,@ÅàlØ!؇Á.L6ÀWaçqzýI Aþ€_-X°`ÏH$ò٠Α¹"2×uÝÕªzg$á°n"""""¢Ñ«v‘µ´øqH± »¼æZ,^¼øMØÕè¼h4zˆª~ À‚ŒaÝ¿QÕ›§L™ò`CCC®MÓ‰ˆˆˆˆˆ¨¸üÀ±°£‘ïp ì<ì’0¨… ,X0SUç¡gµ4ÀNò>^DNikk{¶¾¾~nSSÓKC(Ñp©­­=À8cÌrÏó¶„Q)s]wB3´'‰Âއ¨ÔÕ××Ïêîî®L&“+ZZZúZ–ˆF¯o¸%:m× ´àE]´ëºŸF£qg€oÁ.å¾Èsœçy³***¦¨êåÞáûþ/|}¢‘BDŽ7ÆÌQÕ}ÃŽ…¨PÎûîÃãÃŽa Dd’1fŽã8'„ Édr¶1fN$Ù?ìXˆ(4%™8ýô<744˜µk×Î3ÆÌWÕO(SÕÀoD¤¥³³óž–––·»éoºé¦­þÇuÝS|¨­­m_äÞƒhÄ1Ƭõ}¿v9}¢QaîÝw;ã^¾Ú¹JïC{²ìü«Ø Åoøîí §çÚÇ24"ÒîûþJcÌÆ°c!"ÀÓæû~Ò³=ìXˆˆ†[Îä¹­­­JDîRUX."·:Žskccc® °›t´Mž<ù?C(Ñp‰Çã%±Ô>•Žsþçþ‰‘ä8)ëÔÌà³ç]}ÿ•·_uÆu¡˜Ã¢E‹Ö¸-ì8ˆÈŠÇã…QX²Ïó-AÜ’H$žÀ»è7mÚtfkkk×DXD¤ÂuÝûÏó-·Ü›D4"̽ûn'ò‚ü/vMœ3|뼫Ø|ûU§ß<\±…í¹»,¯ÚÚY«Ð³9@9€—r¯ïû7͈®äšDTµµµc*SßrŸg¢"‘3ynllÜ &ß‹–RâœÒ]QQÑaCD”–ª+q~›@¿s^Ãí·7|b}¡ã ÛkK=[;ïSàȬ¿[ß+Ð÷FsÉ«‹g~zú‚å +F"½ªªª6&“É­ÐÙÙY²óG‰ŠMÞ«m×ÖÖ¾ÓãªêV‰H‹çyÿ(@lECUƒÔ|oæÏŸ_]]]íø¾¿Íó¼î°ã!Ú ©øºRiLòlŒ ý]×-s§rëÖ­þÒ¥K‡äÿ³kn=l/¿;ù€ƒrÛO½Ú|Èû§×-ã*ßD)555U‘ 6l/ÁÎ’!sã7vè×uCކˆª×ä9~TU¯ðnkDäñx|Q4=SU "òöúK¢Ñè—ãñø†)f¢‚7nÜY¾ïOQÕ;¼v2íŽãÌõ}Ú„ ~€7–ˆ¨¤ì²•T4=YUðA€ªÚäºî—Tµ @€ëDä?à«ê õõõ³†5r¢‘.é?ìXˆvÇÜ[Ç(Ë«’Aua¢cŒ/"A I×ê»+À…yT9镸¡‡ EÛD£1†Ÿ‘DT²véy‚à["pñ¦M›¼ªªªq‘HÄð]¢ªŸknnþiªø]uuuëEäÛ¾ïÏpí0ÆNTžçÝv DC¡õ‹ó:οúM&¸’bmá"Ê_SSÓJ×Õõü·Æ-À¸|êH$˜ àšЍ˜Åãñ;ÂŽˆ(,;õ<_|ñÅ•"ò^ÿð<¯©µµÕ_²dÉ[ÉdòK°+ªtnÞ¼ù™u‚ ¸3õô¨á ™ˆˆLñÛ¼Š«þ¦P¡ŒA0ð iªù×!""¢Qg§ä¹««kŸÔ±5™Ç—,Y²ÀÿÉ^bܸq¯§žò "¢Fí¨¡`€Å_\ñ÷2ž° ä¼ë¨¼Þ)"""í²ç<UÍÞ§Xl°Ë6L{íµWwªNÞ+wQaÝÞpúÓ ½rE·CäœÇNJ<¨M[;õ󨢦Üô„@‚³xå¢zÏÔÚå÷‰@ÃŽˆF?×u7'“É#–,YÒv,D”ÛN=Ï‘Hd£ïûƒÚOÓ³rhB"""Óê^þ#€?îr¢nøc!""¢‘m§äyÑ¢Eë|-¤XˆˆˆˆˆˆˆF$n/E”¥¶¶öÇqöð}ÿÉD"‘÷ž°D4tb±Ø$U=À–x<þxØñ•ºX,6[U÷tç©ÆÆFîND%… e‘ÃTõ™v,D¥NU'¨ê1 ;"|ߟ¥ªÇtuuM ;"¢áÆžg¢,Ƙ'Uµ*‚ aÇBTêŒ1|ß$‚maÇBD€ª>-"/WTTp%z"*9Lž‰²ÄãñgÂŽˆ¬¦¦¦Mž;"²‰Ä¿ÂŽ(à Ôóõò½¡; vÄïFo a\ý9€“jwËÊ—8 @€uy¶å8ÀÖäY·hpØ6Q߯X‘zœ>ˆúÏx@ÍP5‡ù¢–¿ ÀÓjÑÖSuÿß ê &ÏDDDDDD¥í³¾2ȺŸpíÆ2bqØ6Q–ÚÚÚÃŒ3Æ,÷`æ@ƒ-VLž‡€ˆŒÅbÇ€1f]ccãê°c¢Á‹Çã†Y‹-Z à¶°ã "+?v £A4=DD&€ïûE·Ѳ;fV—ïØòK¨œ´ëYÙ_ß ÿ³¯ÜrØi]ôâ«ájØ…»np7€ïÂÎÙ  ÀS¾àþ¬z Ø¡ŸpAŽëÀ</˜ßËùÃöº›ú~3€_hÐ[ð(€ñ¾àgLJMxÏ ®K½®ŠÔ÷ÿà‡°ÉioØEÈ8,õý°‰í·s¼>ølâ¼ À¥îðÉ~ꤛ8¯ð%waäIRLž‡€ªvÄãñ'ÃŽƒˆˆˆˆF¾x<¾,ýÜuÝ¢â\¾CïzKœwr¸ñ“÷·Å';9Ú6Ô£ù¦8À‹þÀTØDn5l9À¯| À73ê=`€÷À®,ýj/×6°Éä~ÞËùsa\ݶÊÀ&¡5>»xÖß²ê¼v˜ó~YÇPàc°Éþ¸ÔqM]ÿ=°7†½a©ÀÒT›Ð »ÅÔþ®prçz¯À×¾ ö†C>Öøì͈Ž<ëµ¢»ÓEDDDDDáXµxæ'èvMGv;ã.-`8óLÝi*€ã`“G/uþþ+£üRØ$SœÝÇ5?›8©òÙ΀MºO€â¼lOô:´Â&Äùø>lïõùö‚‚ý1¯¥Î_Ž]ï¯Ã&Î àØ¡ÞÓRå8)O_.‡M~óMœÛC~J,qØóL´‹ùóçWWWW;¾ïoó<¯;ìxˆJ™ëºeŽãTnݺÕ_ºtéÖ°ã!*u555U‘ 6lommÌÝTäTóÞ«¸Àõ…ˆ%åj?Êø¾@ 6‘<%Õö=©soÂöHv¨ôwz¹ÞyLÞ©Å IDAT©¯¿AïC°·8vÿä´ßÂ&ÕƒMâkܘÇk|(ëš¿ƒÝŸù÷°Éô‡Ñ3ä{O_N=ÿ1l/zÚÆTû`_' !ö<e7nÜY¾ï/TՃŽ…¨Ô‰Ètß÷VVVöÕC@DÃÈqœ¹¾ï/œ0aÂŒ°c¡Ð¼/Ïò3WÄÎÕº;¶ø^/Çvi8À;3ε¤¾;l:ÓxعÀ€Ý^ª7K°s’›öéusòýÌz°kþ@º#gbÆñS`‡xèûÆDö0oLž‰²ˆH—ˆtˆˆv,D¥Îã‹HGìá"Œ1üŒ¤|‡$cL™T"Øä²¯ùÔFOâ9;ãøÃ°sƒ]› ;7y ìZ½ùmŽxþúúnØÞâúWÇ“Ò+–g¾ïé׳ v¸xoþ »x !Û&Êây^_w‰h˜555­Da‡ûQâñøaÇ@aÓ6@fåQ¡»}›¬/P0+sœë°vôþÇ“î€]Qû_¾”²ýSô”¿ÖÇqX›úZ;w¹¯Ä6[®iIÉÔW'ãXz;©5ý\÷ lë) ö<Ñ€ˆÈ#ùUÀùÂòÎ…Óß>È餸,ëøbءݓœ˜:6v^1Ð÷m¤êõ%óuæ“gå»âúØÔ×dÎR%¸ W¡1y&""""¢ü=áûeT¿[ÀprÍ¥6°½¿À®=À/økêù9_ؽÿ’ãº{ç8—nOa'+”ôpì‰9K…._²˜<Ñ€L½hå2|m`¥µej튇 ÎQ9ÎÍBOís½œoI}=v*k …¥ÍÌqî=©¯ËPØ^ß—R_Dßs«#°ï !Îy&ÊRWWw6€}Uõ¾D"ñJØñ•²X,6Ý÷ý3Uu}"‘¸+ìxˆJëºsUu²ˆÜïy^o«S ˜¶`ù^[<£*7ÓK‘@7N]=õk½/"=dÞ`zoäÂÔ×MïåüOa·“Ú 6q>vøtóúφÝ9[ì‚cðë~®±»îÝfk<€³ÜÞK™OÂ.~FCˆÉ3Ñ®ªDd"vCEæük|·*>"À>ÝÅŸÂSO444ä;·hTx:~LÙ>fë‰*8N •Piƒ£X³üù°c닪–‰ÈDc çmªZ%"ƒ Èg%a…\°â¦ñƒïuŒ‰ŠÁ‰Pì`DÿdŒ&¦^´òY`y¡Ã0nƒÝºé­Œã°0õüè}˜ùVØ$t>lí ï½3}@=€¦Œcå°ó¨÷‡}S>/b^†] ü“¾àï2?˧øac(ILž‰²ˆÈ=Éd²<‚BÎU¡ªi¸ÿàncCõDIS`%Þ÷ì… º- §ý5Ç%Fך9²¥ ÀŒô{Q ^K̼/p’у.zõõCìUggçjcŒ§ªž_GD…#"÷ñ3’ÒfDW®pEˆ!tø €ga‡[¯ðØÞavîò }Ö¶C·ç8 õý@v\Y  Àiíý»o´ø(pw{Ê%Þ »èÙS°ûO?»¯u ìõõ& C,%ƒÉ3QÏó6„ Þy×Þx2ÇEµ¯=Ž D;ïêûϼýª3ÖàB²*1ãl…Þ·¹ÈôIãGÞ½¦yæ¨[Þß¶ꥥezöã$¢ñ3’F˜?ÃɾÀ•Ç}ØDøb]9êÿv;§ƒ`{¢9€6/p€3R´M°½Ý½ ¡.„5°7 ðùŒsÛœ›Š‡ÉóbòLD£Æ‰ FLÐþsͽ&Tä®Ï5üêлæŒê?WÅgÎPàô8§MõEïð¡a‹ˆˆh((lÒ|ì¼å}`÷a~¹÷€Î¬ÿlòœkoçN'§žÿÀlØ¡âÇÂÙ~À¯lî£þé°y×ËYÇÏ„ý|Î>žinªÞÆÀ¯JÅrS®í½F &ÏCcL,{7tuu½±dÉ1,bµµµ'8޳‡ïûO&‰7ú¯A#…2GE^^0£ìP`¸®r4%ç|Gg|?€Ÿ‡ &ÏDYâñø3aÇ@ƒè¿ 81ÿ*T(#̃ÿjBžè;\GFÖ{ÒÔÔ´ ½Ïã"¢$‰õÿ*YOÁnÅô|{ñ €=°Ió7‘ÚÑ’¨?œcAD£†cÌÈã0¾í$Bäó»UÌO  ÑÐø €yQ÷ ÂNÝú2€CvLž‰hÔh¹òÔ§¹m`¥å/;ß~ga# ŸSÝy3€VZo<°æålíADDDTr8l›(KmmíáÆc–{ž·%ìx(?UÛêÇn·TNËQìŸAÄ|¦uÞ¼Q¿ÀßÔyk:VÅgÎQ˜ÙW9fêƒÛÚ±p\×ÁLí‰Db€7ˆ¨PêëëguwwW&“É---}íiKD4*±ç™(‹ˆoŒ™£ªû† å¯õ‹ó::kÿ¤ ê,Ûù¬´rå fßqÅ)ëB 0Ó¢ËWNò}€Þ`ç…ðϪàÜ© –Ÿ+ %ɰo"2É3ÇqœÂŽ…ˆ€d29Û3'‰ìv,DDÃ=ÏDYŒ1k}ßïÐv,48©åE]ô­‡§A÷$ˆÙ|ë7N] Éc#èQä ‹^Ý à«z7._»ùà¾HUñ×tÑ«v«™áÆ×i÷}¥1fcر`Œió}?iŒÙv,DDTd¢ÑèÉ®ëþ)ì8ˆˆˆˆ¨ø¸®»¹¦¦frØqQÿ8l›ˆˆˆˆˆˆ¨Lž‰ˆˆˆˆˆˆúÁ9ÏDYæÏŸ_]]]íø¾¿Íó¼î°ã!*e®ë–9ŽS¹uëVéÒ¥[ÃŽ‡¨ÔÕÔÔTUTTD6lذ½µµµ+ìxˆˆ†{ž‰²Œ7î,ß÷ªêAaÇBTêDdºïû +++Ï;"Ç™ëûþ &Ì;"¢áÆžg¢,"Ò%"FýÀD#1Æ‚ #öpƘ."ÂÏH"*9Lž‰²xžwkØ1‘ÕÔÔ´ÀõaÇADV<¿#숈ÂÂaÛDDDDDDDý`òLDDDDDDÔ&ÏDDDDDDDýàœg¢,uuugØWUïK$¯„Q)‹ÅbÓ}ß?SU×'‰»Âއ¨Ô¹®;WU'‹Èýžç­;"¢áÄä™hWU"2@YØ•:U-‘‰Æ˜Ž°c!"@U«DdbåaÇBD4ܘ<e‘{’Édyo† Q©ëìì\mŒñTµ;ìXˆ‘ûøID¥ŠÉ3QÏó6„Y---;´…YüŒ$¢RÆȈˆˆˆˆˆúÁžç! "cc±Ø±`ŒY×ØØ¸:예ˆˆˆhdŠF£‡¤ÖWïûìÌ"*Lž‡€ªvÄãñ'ÃŽƒ†Fmmí Žãìáûþ“‰Dâ°ã!*e±Xl’ª`K<<ìxˆJ],›­ª{:ŽóTccãëaÇS¬âñø²ôs×uƒ0c!¢còL”EDSÕ)"ò&ÏELNŒ¬žºêè² ›ªÿœ:o Wm."ª:AU‘6Lž‰Bæûþ,™ÖÕÕµ“g"*)Lž‰²cžTÕª ¸(J‘zå–écLùê*]ó¨ÙSRǃ­cÚW-žy‹‰D®:à‚7†$ ˆ1fƒïûA°-ìXˆPÕ§Eä劊ŠõaÇBD4ܘ<e‰ÇãÏ„ Þ²;fV›xÀz9=N—øÝÉS_[rèÉÖ¼¼r¸ã£ü455mðDØq‘•H$þv DDaáD4ª”ïÀmè=qÎt0‚àÞçî>²|8b""""¢âÇ䙈FÕKf~À™,þŽª·ºj ¶M”¥¶¶öpãŒ1Ë=ÏÛv<4pA Ÿ¤ÿ‚=åϰ¨pÑîr]wB3´'‰Âއ¨ÔÕ××Ïêîî®L&“+ZZZ6‡ÑpbÏ3Q9Þ3GU÷ ;–Á¸°áÑ1 ¥úoûˆ| ‹à… „††ˆL2ÆÌqç„°c!" ™LÎ6ÆÌ‰D"û‡ ÑpcÏ3QcÌZß÷;´‡Ë@]píƒ3_ÑOhßo%ÞœõÏŠèí•í7·~q^ilÏ$â@óªá(""ÒîûþJc WG'Œ1m¾ï'1ÛÃŽ…ˆh¸1y&ÊÇ ;†|œwÍýgk ·ˆ`LÆaà]ªò®±o¯¹àÚçÜúÍÓV„ã°Q¬ðÁ—YV¸`h(,Z´h-€ÛÂŽƒˆ¬x<þPØ1…¥T‡v ç^ýÀÉ¢r°Sâœíp ‚‡.l¸gáŠ+,*zO>åúËBÅBDDDD£ “g¢"åÆŸ.3ÐF hè±ÌôQþõ‚²W¯¸À“+­ë:+ð“‚DDDDD£‡me™?~uuuµãûþ6ÏóºÃާ/ëÖŸ‘™-/" NlxôŠÇNJ2®0I‚ñ`n™cþ¨À´E·ªÈg9wùÖa ŽÅuÝ2Çq*·nÝê/]º”?/¢ÕÔÔTUTTD6lذ½µµµ+ìxˆˆ†{ž‰²Œ7î,ß÷ªêAaÇ’“Ñcó« {MCûÁ… fä˜]¹*©þ±~ô²|˜à÷oŽ›¾`ù_†=8Ê›ˆL÷}aeeåÙaÇBD€ã8s}ß_8a„aÇBD4ÜØóL”EDºD¤€v,¹ªdà[¨.L4#ËÁu¯¼àì5Í3ÿÛNT#ûCuc Ο^ðÒKaÇGgŒñƒ è‚€=\D#€1¦ @‡ˆŒèÏH"¢B`òL”Åó¼[ÃŽa DЖo-sÖ"–‘ꀺåkÜv4xMMM+\vDdÅãqþ?•ˆJ‡m)_å·yVyöŽ+NYW`ˆˆˆˆˆF9&ÏDEjiÃiÏ ð«–{ˆˆˆ‰É3Qó#NÀêþÊ)té­Wžzç0„DDDDD4*qÎ3Q–ººº³쫪÷%‰WÂŽ'—;®8eÝü†?èHp Ç÷R¤[7®Æø+ ²ëÊÓD#\,›îûþ™ªº>‘HÜvn½êÔßø]Øq ¥ÎÎÎÕÆOU»ÃŽ…ˆ¹¯?#‰ˆ†“g¢,žçm;"²ZZZvùoËFD…ÁÏH"*e\0Œˆˆˆˆˆˆ¨Lž‰ˆˆˆˆˆˆúÁaÛDYjkkOpgß÷ŸL$o„Q)‹Åb“Tõ8[âñøãaÇCTêb±ØlUÝÓqœ§_;"¢áÄžg¢,"r˜ª#"ÂŽ…¨Ô©êU=ÀaaÇBD€ïû³Tõ˜®®®‰aÇBD4ÜJ¾çù /‰DŽìãô‰DbͰD¡3Æ<©ªUApQ¢c6ø¾ÿHÛÂŽ…ˆU}ZD^®¨¨Xv,DDíä“犊ŠTõ7}œþ>€ÿÎx(|ñxü™°c¬¶ø¡{w9ÁT Д%WtÑ«;ÂŽ‰hw455mðDØq‘•H$þv DDa)ùä9‚w‰|]DvÚ³Ð÷}~@PQXµxæÇ¸ª[ƒ÷ ``ãG¶¿–˜ÑšôõªÑ•«ÂŽ‘ˆˆˆˆ¨˜•|òlŒ9ZU·Mž<ù†††† ìxˆòõZóÌU\ @²Näˆ#s^[|ð§\°’½wDDDDDƒTòɳª àïLœ)­¶¶öpãŒ1Ë=ÏÛv<¹¬j>ä"½ªŸb{Aͽk—Ì8zJÍŠÕÃÑq]wB3´'‰Âއ¨ÔÕ××Ïêîî®L&“+ZZZ6‡Ñp*éäù /`€g¢ÑèwUõDcü1‰üOcc#$"Ç‹ÈU½ÀˆMž_¿íãwtµ_ŸÝÝ܇=»U®PSРˆ†˜ˆL2ÆÌ‘6Lž‰B–L&gc¦E"‘Ÿ`òLD%¥¤·ªª¨¨xì „sTõ#þûAPŸL&ÿîº.·F)AƘµA¬TÕö°cÉeGgÇ'Øg åE1wÙgV2&¢¡&"í©kÃŽ…ˆcL[+1ÛÃŽ…ˆh¸mÏs]]Ý'E䟞çõ¹R,›¤ª‡ù¾¯AüsÉ’%oež÷}¿Úqœ¿«êÝžçÝ>îºîZ4øH¡^LñxüÁ°c¾3Ï*•啘àùBÄCT‹-Z à¶°ã "+?v DDa)ʞ纺º¹WDf÷vÞuÝ2×uÁZUýƒ1æñH$òºëº_Î,—H$~Çß›™8€çy·ŠÈ_œ¸`Á‚= øRˆÏ ï^dµÓˆˆˆˆˆ(OE—<»®û)iÊUFDnp €‡UuŽª~À7¸®H;ªú<‰D"{ívÐD… òjž5'¨È·¡ˆ†m_vÙecÛÛÛ¿©ª_Eޤ?¡ª <±iÓ¦3[[[}¨­­}Âó €o]vÙe·ÝxãÑhô,êìì¼¢—#÷à———sÜ3þüêêêjÇ÷ýmžçu‡O_"&x0Hþw¬šZûÜ›ý—#9\×-s§rëÖ­þÒ¥K·†Q©«©©©ª¨¨ˆlذa{kkkWØñ §¢Hžc±Ø¤íÛ·? `*€G¼Û³¼ U=€‘Ÿ¤gH$o¸®{ €¯µ··Ÿ àAL‘‹ËÊÊþ  9]¶¾¾þ`ß÷Oð»›nº©s!îF]cÌ#MMM+ÓkkkqçU}Þó¼·÷Ø­©©™\VVv†ªnò<¯5óBÑhÔ€7ß|óöÖÖÖŽŒãsìÏ6 ߯¸qãÎò}ŠªÞFO©¯ãê¿êóW÷診èŸ>ºfÆÓsç¾gìH{lƒmäjCD¾ÁqãÇÀÍÅú:ØÛ-m8Ž3×÷ýi{ì±Çúh4š,Ö×1’Ú‚ (þ'¢"IžUu_UÝ)S¦,^·nÝåªÚWñ÷§ê<ÝËuž¨êq~¡ª·‹ÈWDä{®ëªˆüÀ¾ïÿ Uþ« qœª¾/™LnÅb{§ŠÈ‘¾ïO‘5™…ËËË˃ ˜¬ª»¼ÿª:ÆŒ³Sïz{‰Èäd296óx$© ‚€m a"Ò%"°¿s#úuT”ýbgWûю;n¦çßÜ÷n›¾u̘Žù:ØÛÈÑÆ>Æø¾Ÿ,ò×Á6ØÆ¨hÃÓ #‚jUS¬¯#¤6ŽÍü;QUߣªÇˆÈw$¢°Eò\^^¾ª³³óÐææænˆFsN[žÿÉ>á8ÎÆ `ðvoôG,М‘¿("Ÿð<ïŸ q½ã8ÿ#"ë·¥Ö××/sg¢ïû; 5ܸqã{ï½÷m;vìØeH°ã8·ÀŽ;vd÷}ÿ7cDd}æqyÆqœUlcèÚð<ïÖô¹úúúý:ö;ÿ_ÛÛâ“OêvÆþØõßôýÊ}¯¼ó ǹ¯ƒm°mü6mÚôZ‘¿¶Á6FEñxüàíØ¢}aµ‘ýw"€ßø¾?/ûZD42å®h4ú U½VDΉÇãwežs]w€jÏó*ìÔ=][[ûNcÌ3"òp<?%óÜE]´ã83DäÍæææ—óˆådUmð<¯×•¿©0Îk¸ÿ"˜˜w@àˆËT_ÞÖpêý×Ö4Ï<À‡ž¦Å KTŸ‘ê·§Î[ÓÑm""" ƒëº›“ÉäK–,i ;"Ê­(zžó4@;²gPÕöÔÓ²ìs·ÜrËìÒ[M#Ë… Ž Ð~5  ©ÿàKç_ýÀ¯»58ÿ®†9ÂŽu¸P·| /ì8ˆˆˆˆˆF£¢ÛªjÚTÍ;×É>QVV¶'¨*Wl-B'6< ¤ã—Ô¢ïßÝSËÄ<~aÃ={ glDDDDD4ºÆžç ö™4iÒ6fžð}¢ˆ@D²·¥¢"0U:ú‰=\¥ü{jÓN]]ÝÙöUÕû‰Ä+ƒ¹ X,6Ý÷ý3Uu}"‘¸«ÿDTH®ëÎUÕÉ"r¿çy+ÂŽ‡ˆh8Æäùy‡wwwOFVòlŒ9 µ(سCÙ ˆŒÅbǦÚX×ØØ¸z(¯O@CCƒY ýï–Wà‚ó¾üö†O¬ï¿ô.ªDd"zÞODÃKUËDd¢1†s÷‰FU­‘‰A”‡K1‹F£‡¤þÖ€ïû£q$(Ѩ4ê’gyDU?àãÈJ’Ußîµ||(ÛTÕŽx<þäP^“vö*Þ÷NûåQ%b$ùQy÷T‰È=Éd²<‚7ó­KDC«³³sµ1ÆSÕ]V¶%¢á'"÷ñ3r÷Åãñeéç®ëaÆBD7ê’çH$ÒÚÝÝým_u]÷7žç= Ñhô³ªúiŽÇã»ìM#[ ²/kÀå®™<˜¶<Ï+¹ÅƈFª–––¸-ÑÁÏH"*e£.y¾ùæ›7ÖÕÕ],"KüÉuÝ_¨RÕÓl ‚`Pó`)d*oAòKžpa8"""""Å:Çây­"²ª·“ÍÍÍ?UÕx À‡¬ª-Ƙc‰Ä Ã' ‘Œù'€ùÔqDÿZ pˆˆˆˆˆ¨ÄeÏs<ÿ€_ä*ÓÜÜüžˆ¨ÐZNÚvþÕþ Ð Xåo-Wž>¨…ájkkOpgß÷ŸL$o æD44b±Ø$U=À–x<>¤ëUQþb±ØlUÝÓqœ§_;"¢áT¬=ÏT‚"Ú}9€uéï«ÌVT± 3Ǽˆ‰ÎNë–ìÑKÛŽˆ¦ªÇˆÈ„Ý—ˆ†€ªNPÕcv,Dø¾?KUéêêšv,DDí({žGnU5<–4œÙv~ïO9°bùë~`¿+V@2{½{2~¿õ´í/uõÙ–«Îøû`Û1Æ<©ªUApQ¢c6ø¾ÿHÛÂŽ…ˆU}ZD^®¨¨ÌV”­ªˆŠ“„@±‹F£'«jƒçy³ÃŽ¥¼ºxæ|Q,Ð×þ’ Å5Ö-oưˆˆˆˆÅuÝÍÉdòˆ%K–pg¢Žwº¨h¬Nzl?‰3W½š8äœáŠ‹ˆˆˆˆˆF?&ÏT4ÁõÈ8¿M ×??¦¬À!Q‰àœg* ¯Æß_Ñýá<ª°wdóñÍ·­ÚÚÚÃŒ3Æ,÷ö<UíˆÇãO†Çhv`ÍË+W%f>£À»Xes¹¿=ïùÎDDDD…Ç—¥Ÿ»®„  ç÷¥ë&›d7Ù=»;¯çã‘ÇLÎùœï¼g“oN>sΜ³pYÞY`ªqä3ΉÅûnðÎ×ÝôÐs9ݤ—ÈCpéþæt׿ŽSµÍlÀÌöHJC\‡ „fY¶'Ë2ŽpÓ@a@Ò3c ŸR©tFÇßÏ;fž8Ž{ÛÛÛÏ;€ã´m€æ€à;χ™Í-—˧IRa[WW×#ygÀôT*•žof­’”¦)³€‚æù0p÷=•Jåö¼sàðèèè8OÒ1î~sµZ}0ï<@#+—Ë'¦iúfw¢Z­Þ˜w ÑÅqÜæîÇ›ÙW“$y ï<3U¥R¹oøyǾC€©Eó ìmAýÓ়ƒÎݛ̬5„°'ï,$w_`f­Y–5ç¦Í30Š™}¹V«5gYödÞY€F×ßßÿH!q÷Á¼³Ììfö‘Íó ñ‹êɧšì4W¶@fÛ²,ýæI>žw®Ù(I’íyg0¤§§§OÒÖ¼sÂ>@#£yžæNNz¥‡Ð%i…ä2™äRdQúpõäkÓìÏ–•6?•wN˜Í¸ºß4ö‹ ËÎò¾#iÅ>VG.µ¢ðƒ­•,žêlÐH8òÈêL‘nšÌ8¤X,¾HÒ¼ÂýI’pm Gq/̲ìdI»«Õê=yçÝêÕ«Oœ_«ÕèéééÍ;L%N™¦æèï$=tpÕÞýÜöû9ò|˜˜Ùï„Îq÷còÎ4:3[B8'Š¢ÓóÎ@ªÕj¯ !œS(ŽË; L5šçiêùrÿÎàé›$ß¶¿:—nØmOU®FBØ’eÙfwßw Ñ™Ùîú|Ü’wRak–e›C»òÎSÓ¶§±çt<øÓ‡7œ²Â½ö1ÉΓ4gÄê­2]öÜ÷_aE¥yeœ*•Ê×òÎ`Èúõë·Hº6ï†T*•[óÎy¡yžæNXõó­’.zìÚ—½»`×˃´@‘oyöC›ï²Nq ˜4Ï3ıïüé.IßÏ;4"šg`”óÏ?ÿÈ#<2JÓôé$IóÎ4²8Ž›¢(š¿sçÎôúë¯ß™w Ñµ··/hii)lß¾}ׯòÎS‰ †£Ì›7ïÓ4½ØÝŸ—w Ñ™Ù‰iš^<þüóòÎ@Š¢¨-MÓ‹.\¸,ï,0Õ8ò Œbff¶GâBl@ÞBi–e{²,ã0 „$í13ö‘Í30J’$×äÀuëÖm–ô‰¼sR©T>—wÈ Íóa`fÖÖÖÖ\ÿmºqãF>À>uvvîºë.¾> Ì04χ»·,Z´èÅ’dfKÚ–s$LS>úès-Z´°þ[šh`† y><úº»»ße[ƒôk:ÏþÎd½&&GµZ}pøyÇYžY<šçiî‚|õ<óÝŸ‘ëh3I2™$—>ôÎßr[æÑŸë<óþœcÎ*çI:ÆÝo¹s0õÊåò‰iš¾ÙÝŸ¨V«7æhtq·¹ûñföÕ$IÈ;L%N™Æ.üð×V›Û ’Ž£äÕÁ²ÛÞÙyË ¦2WX`f­fÖ”w Ñ¹{“™µFQ´ ï,$w_`f­Y–5¸fšçiêÂÜú.ÿŒ$Û¥?K¦Ïwvvògy˜˜Ù—kµZ288øpÞY€F×ßßÿH­VK¾œw’™Ý\«Õ’Z­Æ™Y§mOSîéûuð>§>h+Î’tË$FjI’lÏ;€!===}’¶æÀö‘G+§¯³ÆWnã¬,šçi¨íò›æJZ<ÎÍN˜Œ,NÛž–~cçÝý›í•ƒ’ú‚U.==‰‘J±X<=Š¢EišÞ^­VÏ;ÐÈÊåòw•¤§*• ·çrV.—_ãîGEQô]]]å¦Gž§¡ÎÎÎÌ¥qÝ7ÚewLVžFcf/t÷åf¶0ï,@£s÷…î¾\Ò óÎ@JÓôw_>00Кw˜jyž¦Ì¼Gn¯<Èò¾Ìõ…I Ô@B·»û‚,˸( ³Âö4M¿™eg×Ó€»ÿÐÌîmiiy"ï,0Õhž§©=Ùîê;b¥In Í>zý_¾ñÑ)ˆÕ*•ÊOòÎ`ȺuëvHú^Þ9 ©V«?Í;ä…Ó¶§©oðBôf“mÚ_¹ÿݵÿ÷¬OU.hD4ÏÓØç>xæ6ó¹¯1ó÷IúùˆU5É¿•Io¸¦ó.‘™ç•§mOs=¿Û'é“’>ÿõ7öõõ- šÿD}9&A±X|‘¤y!„û“$y*ï<@#‹ãxa–e'KÚ]­VïÉ;ÐèV¯^}ÊàààüZ­ö@OOOoÞy`*Ñ<Ï ÉÎxJÍÜ$3³ß1³¥î~ƒøy¹2³%!„sÌl«$šg gµZí5!„ …Â$Ñ<h(4χ™Í-—˧IRa[WW×#ygÂÄ…¶¤iÚ/iwÞY€Fgf»Ó4ÝBøUÞYH!„­išÖB»òÎ2“•J¥ç›Y«$¥iÊ×(4†R©tFÇßÏ;fž8Ž{ÛÛÛÏ;€ã“.€æ€à;ÏÀ(çŸþ‘Gyd”¦éÓI’ æhdq7EQ4çÎéõ×_¿3ï<@£koo_ÐÒÒRؾ}û®7ä¦GžQæÍ›÷Çiš^ìîÏË; ÐèÌìÄ4M/ž?þyyg EQÔ–¦éÅ .\–w˜jyF1³3Û#)Í; ÐèBi–e{²,ã0 „$í13ö‘Í30J’$×äÀuëÖm–ô‰¼sR©T>—wÈ §mp4ÏÍ3ÀwžQ:::ΓtŒ»ß\­VÌ;ÐÈÊåò‰iš¾ÙÝŸ¨V«7æhtq·¹ûñföÕ$IÈ;L%šg`o $-6³¦¼ƒÎÝ›$-Ž¢hOÞYHî¾@Òâ,ËšóÎSæÅ̾lf§õ÷÷?œw Ñõ÷÷?ÒÒÒòƒÿÈ; ÉÌn®ï#93 @Ãá;ÏÀ(I’l7³í===}yg]OOOŸ™m¿úê«™wì#46šg€æy‰ãø¥ÓyÜCg¢ÛŽg»Éúù5‚ööö«V­znÞ9ögªÿ|'ëõÊåòÒÕ«W·ê8+W®œ³jÕª“'ºýDÞßx·aNNÜtÿÙå‘}ä¡m7ÝÿNMg—\rÉÜ8Ž—åÀä£yžABs§ó¸‡2ÎD·Ïv[[,Oϲìôb±xÌD2ÍFY–E!„–¼sìÏdÍ©~½Z­ÖÜ××wÈ×£hnnMMMs&ºýDÞßx·9˜úr¹¼$˲ÓK¥ÒkÇ›g6›ê¿ïã•G>ö‘‡¶ÝÁÖ–Ëå×dYvúš5kŽH¦ÙhûöíÁÝ'üï-€™Ãò0Ó•J¥3%}8„pæd¿VáY–mš®ãÊ8Ýv<Ûlm­V{gá’®!pIî¾ÐÝOçŸÇdÍ©~½Z­öÜÁÁÁ]sçÎÝ~(ãDQ47˲Ýýž‰l?‘÷7Þm¦>˲e’Öºû¢(ºf^yäcyhÛlmš¦ç›Ù+ݽ+Š¢{Ç›i6r÷yî~BágÙ>MÓ_ôõõ½øÚk¯Ýr¸³8¼¸Úö¡{‰»¯HÓô±É~¡,ËÌÝ}ºŽ{(ãLtÛñlw°µff’äîç¥i:ÞH³ÚtþyLÖü˜ê× !¨¹¹ùÖišÊÌ4шyãÝfœsòíiš~b^yäcyhÛ£vøÀ ûÈÌìPþÝnjii9ZÍ30YÞ€¼ÅqünI&IrËX5årù´,Ë^-i™ýè¸ãŽû§ÎÎÎÚÔ¥f—R©tf–e§twwz¬šr¹|bš¦g˜Ù±îþ 3»9I’§Æ(·ŽŽŽß“ôr3 fv[¥Rù®$Ÿ”7ÌP«V­znaõààà_÷ôôôî«&Žãyîþ&3[ff;kµÚ×7lØpÿXc‹ÅEQô?Üýhwÿ¹™}5I’Ýûªmkk‹Ž:ê¨7ºûo˜Ù€¤ïT*•¦·“Šæ ­££ã<3»ÑÝ/ïîîþ_£×wvv¶mÛÖãîçZµIÒ$I²mj’³G©Tz¾»ÿ»¤‡“$yù5kÝý2I-#ÿÒÝÛº»»ÿudíÚµkìïïÿGI¯5Ì×%½u¬ÿÄfíÚµ-}}}·šÙëÒ4=qÆ ®)‹ËC_‘ôì‹SI‘$É¥£ëã8þ˜¤÷KŠF,~HÒ9I’Ü9²¶½½ýøB¡ðuI/¹Üݯííím߸qc:ñw“/äÈK½q¾f5Û¶mûx½qÞEѲV3û¤¤WHºqJ‚³HÇ/u÷oIj«¦££ã,wÿ´¤Íî~ÚG1OÒù:óãË]tÑÑ#ëûûû¯ÓPãü·’Ž/ Ç™ÙM’Î’ô©I{3À Rÿé‹föº±jV¯^ÝB¸EÒQîþ'µZíHw?UÒý’>V*•þhd}ÇEI.éöÂK%afïÑPã}ó%—\2wD¹ …ôR3û@SSÓâÂóÌìŸÍì‹-úàa~ËpØòLµ8Ž›Ù¥îÞ!©o¬ºr¹¼$˲wIºgÇŽoñ‰øûJ¥Òqî~~±X|}µZýç) Ì`q7¹ûI—êÀÜvJªI:§»»ûú²J¥R‹»_ÕÔÔt±¤IR©TZQ?½ô«•Jå½Ã´µµ½£µµõ¹’V­ZµêÒ}aE±X|}ÿ:I/ÐÐ~oξêÒ4]#éIïîîî¾¾¾øÇÅbñ†îs÷NI_’†ÎÌÚºuë‡$=EÑÙëÖ­ÛQ¯¿"ŽãE’>²{÷î %­—¤R©ô&w_áîë“$ùD½öW+W®<»¹¹ù3{ßš5k.ïêêzz~pXpäèÇõÆù‹î~ÑXEîþIs%Ý8úT²,Ëz$ÉÌÚ&3(0[¸{ÕÌþNÒƒîþ[cÕÅq|œ™&éß’$y`äºyóæ}^CÿñÛˆqß$IY–]7²¶>g¯“EQtîá{'ÀÌÒÑÑñ–·$gf¸ûþ>ð}³¤4Š¢F.¬V«Jú†¤—ÆqüBIÚ²eË©’žkf_Ñ8K’ …B$¹ûȹúfIŠ¢ès#k{zzú$}^Òü4MÏœàÛ€)AóŒ†cfÿifg'IòVI;ƪ˲ì´zý]ûã®úã©“˜EB;$½»¥¥eùÒ¥Kÿs¬ºzã¼Ïy÷©O}j¤%ÜÞÞ¾`d½¤½êCwIRý´S QE’>S«Õ^X©T>7VÑÚµk[$ý¦¤m£›aIr÷»¥ÿÞï Ͻ,Ëöš{]]]HÚ)iäÜ®ßkþÏwæ*€éŽÓ¶Ñp*•ÊÁ~²}œ$eYö«Ñ+ZZZžìïï—¤çÆhÀ¬U©Tþtøyggçþö=ÇI’»ï5ïê~%ÉBÏ–t»'IMMM{Õ×jµ'C23æ)Vww÷M’n:PÝàààbIÍšc{1³'ëOO¨?'I!„±æê“’Nloo_pÕUWýW½¾–$ÉÎ1j%ö©¦9Ž<c[XÜ>zÅW\Ñ/i—¤ySš˜ýÆœwuÃÿÉž{ %é—¿üå“Q ` µZíÈúÓýÎ=wŸ[<¨úÂðü;RCù^·KÓ”¹ `F yÆ`f…úãX·ÎHÅíÞ€ÃÊ݇ow³Ïy7<£(ž{‘¤l_õÍÍ͵ú˜ÌSàBÃû¼Ú¾Ö»{­¾ÞêÃgìo©ææfÓо2ÒÐ…÷EÑðræ*€i惙í’$w?jôº8Ž›$-ôÔTçf3wßUº×¼«¯–$ÕjµÞú¢Ý’Â’%K®Í²lqý)ó8€(ŠÆÜçÕýÚ|ÞGjŒ¹*éY’´{÷î^ mÞ3¼ì@cÀtEó ŒÁÝ·J’™íu?ÚB«†>!ët5`f[ëOǺt«$577ÿJúïyÚ××·W}­V^Æ< MÓÇ4tÇ>›áûÂíÒÏ=í®îª_M[’¶Jš³råÊ}Ý&‹¹ `F yÆv§$™ÙI£W¸û²úÓMSš˜ýî”$wßkÞÕ/4v¢¤G\ øNIŠ¢h¯z3cž)I’Ý’´´~åíÑ–I’»ÿ¨þ8æ\ãx±¤EföÌÜ3³;%©©©iÙèúc3WLk4ÏÀ¢(úš$w÷½îëîo©?~cʃ³X’$?“ô€™½~åÊ•¿v*ö–-[ÎÐÐ×%Fλ[ê4z¬Â[êO¿9YYèIsúúúÞ8raýÖpo´eÇŽwKÒààà÷4t;ªsê_ezF}¿i£ö‘·HRaô>ÕÜý$ ˜Ù¿Öw‡Í30†uëÖm–ôeI¿Çñ_uvvI*•Jo—ôI÷õöö~1ÏŒÀläî—KZÐÒÒòÅáû9—Ëå—˜YUÒ`E—×ööö~SÒO$K¥Òªúb‹ãøÏÝý$ÝÚÝÝýã©~ÀL”¦é•’úÌl]GGÇË%iÍš5ó …ÂM’ZÝý²7¦’ÔÓÓÓgfWjèÖU×­.‹§›Ùe’v655u EÑ$=êî,•JçHR[[[ÇñºôµI’l›Ê÷ ãEó ìG–ek$Ý-éƒ[·n}4ŽãûÝýIO¹û¹Ãÿ‰pøôööV$}ÞÝ__(¶Äq|g–e?’´ÄÌŠëÖ­ûùpíÆSw?_Òvw¯Æq¼9Žã‡%}LÒ½!„ szÀŒ³aÆûÝ}µ¤g™Ùã8¾³V«m‘t¦»ß¸téÒ+FÖÏ›7¾%é¼þþþmqßBøWI-îþ¶+¯¼ò™{@wuu=eÙ;$ ºûÍqÿ¼µµu«¤wIú÷B¡pÉÔ½S˜˜èÀ%ÀìõŠW¼" !l˲ìÛ›6mzpôúM›6ízík_{õÀÀÀÖBMÒ3»>Š¢••Jåá"3Þë^÷:=ýôÓ{ÌìŸï¸ãŽ½Ž ß}÷Ý~Çw|qÅŠ?v÷š™ý—»ÍÌJI’|ktý¦M›~ùêW¿úê,ËvHJÍì^wï,U«U®Þ Œ°bÅŠA3»cΜ9ß½ýöÛûG¯ß´iÓ—/_þ ]É>3³¸ûGº»»?þíoû×îÑ|Ûm·ÕN:é¤ëçÌ™soaPC÷vþr¡P¸¨R©ìõýåM›6=|ê©§^gf;5tq²ŸºûK—.ýÓË.»¬ot=˜z–wÀøÅqüYIg¨ÎÌ>P©T¾0‘Z{{û‚¦¦¦“*•ÊO†—Åqü}Ió“$ùÍ£Œ)ä0~î~Œ¤%Í—TØÏ¯iõï|¹\>µP(ü,˲7ŽZu‚†ÞÀ´TÈ;`âÜ}Uww÷Íyç8XY–½HÒñ£—›Ù¹îå à Ð<rW©T~˜w€ý¡y€ÇñïšÙeî¾!I’u£Öý¡™}ÈÝ/O’ä†ú²OJzUKKËÙýýý•ô6IK$mv÷«z{{ÿfãÆéÈqÊåòiY–½_Òé’Ž”ô€¤«ZZZ>{ÅWôwttü­¤s%ÉÌÞU*•Þbfï]¿~ý·K¥Ò—Üýˆ$I~T¶6Iï‘´\R$é>IWKúL’$ƒÃu¥Ré2wÿí–––³êyÛ$#i³¤«wìØñ‰‘y‹ÅâóB’ô{’ž#i»¤ïšÙ_ÓÈ€}™Vß…Lw_äîËÝ}¯S¦%-v÷åj6‡-“´b``àÿIº@Òw%Ý$éX3»´µµõ¯FP*•ÞšeÙw5t³oKú¬¤IŸ¸V’™Ùã’ž¨oò¤»oNÓtW=ß+%½zä˜õfû&I/r÷î~•¤¹’>)ékq7x'IZÞßßk=ï÷Üý õ÷ô±ÖÖÖK‡k/ºè¢£C?ôIßw÷ËÜý[’Îq÷ïvtt¼ü ~¨ ¡päf¶óâ8>u_+ÜýÆîîî{aì9î>gpp𔫯¾ú—’T,_BØ$©$éÿHÒÊ•+¹ûzIýföúá#·mmmQkkë7ÜýmåryÝúõëÿ&ŽãG%]_Ïöñ±^¸T*áî&éžB¡ðû]]]HÒ\pÄܹso”tޤ÷IºtÄf-’æ…^¸~ýú'$)Žã—JÚ$)–ôI^(Þ¡¡¦º#I’êðÆq_(©ÇÌV×ßÀ38ò 3˜™½]Rç¾~…N9ÔñÝýòáÆY’ªÕêO%=$©5Žãy’ÔÔÔt¶¤gIZ?ò”ç7¦föAIŸMÓt`œ/]”$3{ïpã,I×]wÝ®,Ë:$ j ®™]>Ü8KR’$wJú…¤EkÖ¬9¢^3·¾ú¥Ïì[ZZ>BxEKKËûÆ™4Ž<ÀÌöfvÛ¾V¸ûupw¿oô23Ûâî'eY¶@Òn3[Q_¾×ëU*•HúÁ^w…$Õjµ½Þ[µZ}<ŽãÍ’N)‹ÇT«ÕÇG¬Þ+¯¤-’N®Õj $=¦éßGQô%½gëÖ­Çñ×ÍìfIßZ¿~ý!ÿÌÀìDó 3˜»ÿ$I’oLÖøQýj¯Y“¤ææf«/Z,If¶í0¾ô"I»7lØðä¾VÖøSšššIz¦yβl¯¼’j’T«ÕL’6lØp±Xü½Â_Jz½¤’»—úûûÿ+Žã/eYöþQ 9§m@ƒiÚDz–CÐÝû%)˲E‡2Î({$Í>5|¯ytýqÇD¯V«·%Ir–†® ~¾¤/ièå £(úÊÄ"€ÙŒ#ÏÐvKRaÁ>Öp(›ÙÏëO—^W*•^ìî_r÷köw°}¸GÒÒ,Ë^$鎑+.¹ä’¹»ví:IRï±Ç»}¼y‹Åâò©;vì¸6I’§$Ý é†U«VEÑîþê5kÖÛÕÕõØxdzGž DQô„$¹û©’†O·VÇ %w(c»û?HÊ$/¸à‚#F­+J:%„°E’Ìl þ8ÿÃþ}=÷ÛÚÚ¢‘+víÚu‰¤#Ìì+Ùxó†bIÝ‹-úÑËwîÜù”†>dH%==ÞqÀìÆ‘ghÇ{ì[·n}HÒoÅqüwÿRáhw_«¡fqº»»ïãøÓ’.™;wîJ¥Ò'³,{\C÷|~—¤»úûûo’$w>š»*Žã¹’¾$É¿ïcØ«$½ÓÝÏ]´hÑ7K¥R"i·»Ÿ+éBI»ûŸO$¯™u¹ûfÖÝÑѱ,„ðCIóܽ]ÒÉ’®îêê¢y¿†#ÏÐ:;;kY–½EÒÏ$µ™ÙîþiI?•´êPÇ?þøãß+é/$=Ïݯ1³[ÍìÝ’6J:£§§§¯^w›¤[5tŸåKÌìŒ}—$É`­V;ÓÝ7˜ÙkÜýwÿФ?‘ô…Bá•I’Lèe•Jå'föVIO™Ù¥îþOõ±ß éÊ5Ìny€¨··÷üÖÖÖ {{{ûv›jµz‡¤wtt¼ØÌ– …û»ººikk‹/^|Ôž={ö × … ܽé˜cŽyjô8µZíÍ---…%K–<³®~úôGW®\yÙœ9s^–eYsSSÓ=W^yå¯]ýº³³³&é¬r¹¼4MÓ#–¤ç·¶¶ÚÈÚ«®ºê¿$×®]ûg}}}/1³088øó‘÷‘÷Bw/nß¾}ç>òžÛÒÒR8þøãŸÉ[©T¾ÖÙÙyâc=vB­V{ޤÁþþX¸ý IDATþ;¯»îº]ûó#üËÙ­>ׯ œIEND®B`‚aoflagger-v3.4.0/external/pybind11/docs/Doxyfile0000644000175000017500000000113714507760431020241 0ustar olesolesPROJECT_NAME = pybind11 INPUT = ../include/pybind11/ RECURSIVE = YES GENERATE_HTML = NO GENERATE_LATEX = NO GENERATE_XML = YES XML_OUTPUT = .build/doxygenxml XML_PROGRAMLISTING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES EXPAND_AS_DEFINED = PYBIND11_RUNTIME_EXCEPTION ALIASES = "rst=\verbatim embed:rst" ALIASES += "endrst=\endverbatim" QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = NO PREDEFINED = PYBIND11_NOINLINE aoflagger-v3.4.0/external/pybind11/docs/limitations.rst0000644000175000017500000000600714507760431021622 0ustar olesolesLimitations ########### Design choices ^^^^^^^^^^^^^^ pybind11 strives to be a general solution to binding generation, but it also has certain limitations: - pybind11 casts away ``const``-ness in function arguments and return values. This is in line with the Python language, which has no concept of ``const`` values. This means that some additional care is needed to avoid bugs that would be caught by the type checker in a traditional C++ program. - The NumPy interface ``pybind11::array`` greatly simplifies accessing numerical data from C++ (and vice versa), but it's not a full-blown array class like ``Eigen::Array`` or ``boost.multi_array``. ``Eigen`` objects are directly supported, however, with ``pybind11/eigen.h``. Large but useful features could be implemented in pybind11 but would lead to a significant increase in complexity. Pybind11 strives to be simple and compact. Users who require large new features are encouraged to write an extension to pybind11; see `pybind11_json `_ for an example. Known bugs ^^^^^^^^^^ These are issues that hopefully will one day be fixed, but currently are unsolved. If you know how to help with one of these issues, contributions are welcome! - Intel 20.2 is currently having an issue with the test suite. `#2573 `_ - Debug mode Python does not support 1-5 tests in the test suite currently. `#2422 `_ - PyPy3 7.3.1 and 7.3.2 have issues with several tests on 32-bit Windows. Known limitations ^^^^^^^^^^^^^^^^^ These are issues that are probably solvable, but have not been fixed yet. A clean, well written patch would likely be accepted to solve them. - Type casters are not kept alive recursively. `#2527 `_ One consequence is that containers of ``char *`` are currently not supported. `#2245 `_ - The ``cpptest`` does not run on Windows with Python 3.8 or newer, due to DLL loader changes. User code that is correctly installed should not be affected. `#2560 `_ Python 3.9.0 warning ^^^^^^^^^^^^^^^^^^^^ Combining older versions of pybind11 (< 2.6.0) with Python on exactly 3.9.0 will trigger undefined behavior that typically manifests as crashes during interpreter shutdown (but could also destroy your data. **You have been warned**). This issue was `fixed in Python `_. As a mitigation for this bug, pybind11 2.6.0 or newer includes a workaround specifically when Python 3.9.0 is detected at runtime, leaking about 50 bytes of memory when a callback function is garbage collected. For reference, the pybind11 test suite has about 2,000 such callbacks, but only 49 are garbage collected before the end-of-process. Wheels (even if built with Python 3.9.0) will correctly avoid the leak when run in Python 3.9.1, and this does not affect other 3.X versions. aoflagger-v3.4.0/external/pybind11/docs/reference.rst0000644000175000017500000000512714507760431021226 0ustar olesoles.. _reference: .. warning:: Please be advised that the reference documentation discussing pybind11 internals is currently incomplete. Please refer to the previous sections and the pybind11 header files for the nitty gritty details. Reference ######### .. _macros: Macros ====== .. doxygendefine:: PYBIND11_MODULE .. _core_types: Convenience classes for arbitrary Python types ============================================== Common member functions ----------------------- .. doxygenclass:: object_api :members: Without reference counting -------------------------- .. doxygenclass:: handle :members: With reference counting ----------------------- .. doxygenclass:: object :members: .. doxygenfunction:: reinterpret_borrow .. doxygenfunction:: reinterpret_steal Convenience classes for specific Python types ============================================= .. doxygenclass:: module_ :members: .. doxygengroup:: pytypes :members: Convenience functions converting to Python types ================================================ .. doxygenfunction:: make_tuple(Args&&...) .. doxygenfunction:: make_iterator(Iterator, Sentinel, Extra &&...) .. doxygenfunction:: make_iterator(Type &, Extra&&...) .. doxygenfunction:: make_key_iterator(Iterator, Sentinel, Extra &&...) .. doxygenfunction:: make_key_iterator(Type &, Extra&&...) .. doxygenfunction:: make_value_iterator(Iterator, Sentinel, Extra &&...) .. doxygenfunction:: make_value_iterator(Type &, Extra&&...) .. _extras: Passing extra arguments to ``def`` or ``class_`` ================================================ .. doxygengroup:: annotations :members: Embedding the interpreter ========================= .. doxygendefine:: PYBIND11_EMBEDDED_MODULE .. doxygenfunction:: initialize_interpreter .. doxygenfunction:: finalize_interpreter .. doxygenclass:: scoped_interpreter Redirecting C++ streams ======================= .. doxygenclass:: scoped_ostream_redirect .. doxygenclass:: scoped_estream_redirect .. doxygenfunction:: add_ostream_redirect Python built-in functions ========================= .. doxygengroup:: python_builtins :members: Inheritance =========== See :doc:`/classes` and :doc:`/advanced/classes` for more detail. .. doxygendefine:: PYBIND11_OVERRIDE .. doxygendefine:: PYBIND11_OVERRIDE_PURE .. doxygendefine:: PYBIND11_OVERRIDE_NAME .. doxygendefine:: PYBIND11_OVERRIDE_PURE_NAME .. doxygenfunction:: get_override Exceptions ========== .. doxygenclass:: error_already_set :members: .. doxygenclass:: builtin_exception :members: Literals ======== .. doxygennamespace:: literals aoflagger-v3.4.0/external/pybind11/docs/upgrade.rst0000644000175000017500000005570114507760431020722 0ustar olesolesUpgrade guide ############# This is a companion guide to the :doc:`changelog`. While the changelog briefly lists all of the new features, improvements and bug fixes, this upgrade guide focuses only the subset which directly impacts your experience when upgrading to a new version. But it goes into more detail. This includes things like deprecated APIs and their replacements, build system changes, general code modernization and other useful information. .. _upgrade-guide-2.9: v2.9 ==== * Any usage of the recently added ``py::make_simple_namespace`` should be converted to using ``py::module_::import("types").attr("SimpleNamespace")`` instead. * The use of ``_`` in custom type casters can now be replaced with the more readable ``const_name`` instead. The old ``_`` shortcut has been retained unless it is being used as a macro (like for gettext). .. _upgrade-guide-2.7: v2.7 ==== *Before* v2.7, ``py::str`` can hold ``PyUnicodeObject`` or ``PyBytesObject``, and ``py::isinstance()`` is ``true`` for both ``py::str`` and ``py::bytes``. Starting with v2.7, ``py::str`` exclusively holds ``PyUnicodeObject`` (`#2409 `_), and ``py::isinstance()`` is ``true`` only for ``py::str``. To help in the transition of user code, the ``PYBIND11_STR_LEGACY_PERMISSIVE`` macro is provided as an escape hatch to go back to the legacy behavior. This macro will be removed in future releases. Two types of required fixes are expected to be common: * Accidental use of ``py::str`` instead of ``py::bytes``, masked by the legacy behavior. These are probably very easy to fix, by changing from ``py::str`` to ``py::bytes``. * Reliance on py::isinstance(obj) being ``true`` for ``py::bytes``. This is likely to be easy to fix in most cases by adding ``|| py::isinstance(obj)``, but a fix may be more involved, e.g. if ``py::isinstance`` appears in a template. Such situations will require careful review and custom fixes. .. _upgrade-guide-2.6: v2.6 ==== Usage of the ``PYBIND11_OVERLOAD*`` macros and ``get_overload`` function should be replaced by ``PYBIND11_OVERRIDE*`` and ``get_override``. In the future, the old macros may be deprecated and removed. ``py::module`` has been renamed ``py::module_``, but a backward compatible typedef has been included. This change was to avoid a language change in C++20 that requires unqualified ``module`` not be placed at the start of a logical line. Qualified usage is unaffected and the typedef will remain unless the C++ language rules change again. The public constructors of ``py::module_`` have been deprecated. Use ``PYBIND11_MODULE`` or ``module_::create_extension_module`` instead. An error is now thrown when ``__init__`` is forgotten on subclasses. This was incorrect before, but was not checked. Add a call to ``__init__`` if it is missing. A ``py::type_error`` is now thrown when casting to a subclass (like ``py::bytes`` from ``py::object``) if the conversion is not valid. Make a valid conversion instead. The undocumented ``h.get_type()`` method has been deprecated and replaced by ``py::type::of(h)``. Enums now have a ``__str__`` method pre-defined; if you want to override it, the simplest fix is to add the new ``py::prepend()`` tag when defining ``"__str__"``. If ``__eq__`` defined but not ``__hash__``, ``__hash__`` is now set to ``None``, as in normal CPython. You should add ``__hash__`` if you intended the class to be hashable, possibly using the new ``py::hash`` shortcut. The constructors for ``py::array`` now always take signed integers for size, for consistency. This may lead to compiler warnings on some systems. Cast to ``py::ssize_t`` instead of ``std::size_t``. The ``tools/clang`` submodule and ``tools/mkdoc.py`` have been moved to a standalone package, `pybind11-mkdoc`_. If you were using those tools, please use them via a pip install from the new location. The ``pybind11`` package on PyPI no longer fills the wheel "headers" slot - if you were using the headers from this slot, they are available by requesting the ``global`` extra, that is, ``pip install "pybind11[global]"``. (Most users will be unaffected, as the ``pybind11/include`` location is reported by ``python -m pybind11 --includes`` and ``pybind11.get_include()`` is still correct and has not changed since 2.5). .. _pybind11-mkdoc: https://github.com/pybind/pybind11-mkdoc CMake support: -------------- The minimum required version of CMake is now 3.4. Several details of the CMake support have been deprecated; warnings will be shown if you need to change something. The changes are: * ``PYBIND11_CPP_STANDARD=`` is deprecated, please use ``CMAKE_CXX_STANDARD=`` instead, or any other valid CMake CXX or CUDA standard selection method, like ``target_compile_features``. * If you do not request a standard, pybind11 targets will compile with the compiler default, but not less than C++11, instead of forcing C++14 always. If you depend on the old behavior, please use ``set(CMAKE_CXX_STANDARD 14 CACHE STRING "")`` instead. * Direct ``pybind11::module`` usage should always be accompanied by at least ``set(CMAKE_CXX_VISIBILITY_PRESET hidden)`` or similar - it used to try to manually force this compiler flag (but not correctly on all compilers or with CUDA). * ``pybind11_add_module``'s ``SYSTEM`` argument is deprecated and does nothing; linking now behaves like other imported libraries consistently in both config and submodule mode, and behaves like a ``SYSTEM`` library by default. * If ``PYTHON_EXECUTABLE`` is not set, virtual environments (``venv``, ``virtualenv``, and ``conda``) are prioritized over the standard search (similar to the new FindPython mode). In addition, the following changes may be of interest: * ``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` will be respected by ``pybind11_add_module`` if set instead of linking to ``pybind11::lto`` or ``pybind11::thin_lto``. * Using ``find_package(Python COMPONENTS Interpreter Development)`` before pybind11 will cause pybind11 to use the new Python mechanisms instead of its own custom search, based on a patched version of classic ``FindPythonInterp`` / ``FindPythonLibs``. In the future, this may become the default. A recent (3.15+ or 3.18.2+) version of CMake is recommended. v2.5 ==== The Python package now includes the headers as data in the package itself, as well as in the "headers" wheel slot. ``pybind11 --includes`` and ``pybind11.get_include()`` report the new location, which is always correct regardless of how pybind11 was installed, making the old ``user=`` argument meaningless. If you are not using the function to get the location already, you are encouraged to switch to the package location. v2.2 ==== Deprecation of the ``PYBIND11_PLUGIN`` macro -------------------------------------------- ``PYBIND11_MODULE`` is now the preferred way to create module entry points. The old macro emits a compile-time deprecation warning. .. code-block:: cpp // old PYBIND11_PLUGIN(example) { py::module m("example", "documentation string"); m.def("add", [](int a, int b) { return a + b; }); return m.ptr(); } // new PYBIND11_MODULE(example, m) { m.doc() = "documentation string"; // optional m.def("add", [](int a, int b) { return a + b; }); } New API for defining custom constructors and pickling functions --------------------------------------------------------------- The old placement-new custom constructors have been deprecated. The new approach uses ``py::init()`` and factory functions to greatly improve type safety. Placement-new can be called accidentally with an incompatible type (without any compiler errors or warnings), or it can initialize the same object multiple times if not careful with the Python-side ``__init__`` calls. The new-style custom constructors prevent such mistakes. See :ref:`custom_constructors` for details. .. code-block:: cpp // old -- deprecated (runtime warning shown only in debug mode) py::class(m, "Foo") .def("__init__", [](Foo &self, ...) { new (&self) Foo(...); // uses placement-new }); // new py::class(m, "Foo") .def(py::init([](...) { // Note: no `self` argument return new Foo(...); // return by raw pointer // or: return std::make_unique(...); // return by holder // or: return Foo(...); // return by value (move constructor) })); Mirroring the custom constructor changes, ``py::pickle()`` is now the preferred way to get and set object state. See :ref:`pickling` for details. .. code-block:: cpp // old -- deprecated (runtime warning shown only in debug mode) py::class(m, "Foo") ... .def("__getstate__", [](const Foo &self) { return py::make_tuple(self.value1(), self.value2(), ...); }) .def("__setstate__", [](Foo &self, py::tuple t) { new (&self) Foo(t[0].cast(), ...); }); // new py::class(m, "Foo") ... .def(py::pickle( [](const Foo &self) { // __getstate__ return py::make_tuple(self.value1(), self.value2(), ...); // unchanged }, [](py::tuple t) { // __setstate__, note: no `self` argument return new Foo(t[0].cast(), ...); // or: return std::make_unique(...); // return by holder // or: return Foo(...); // return by value (move constructor) } )); For both the constructors and pickling, warnings are shown at module initialization time (on import, not when the functions are called). They're only visible when compiled in debug mode. Sample warning: .. code-block:: none pybind11-bound class 'mymodule.Foo' is using an old-style placement-new '__init__' which has been deprecated. See the upgrade guide in pybind11's docs. Stricter enforcement of hidden symbol visibility for pybind11 modules --------------------------------------------------------------------- pybind11 now tries to actively enforce hidden symbol visibility for modules. If you're using either one of pybind11's :doc:`CMake or Python build systems ` (the two example repositories) and you haven't been exporting any symbols, there's nothing to be concerned about. All the changes have been done transparently in the background. If you were building manually or relied on specific default visibility, read on. Setting default symbol visibility to *hidden* has always been recommended for pybind11 (see :ref:`faq:symhidden`). On Linux and macOS, hidden symbol visibility (in conjunction with the ``strip`` utility) yields much smaller module binaries. `CPython's extension docs`_ also recommend hiding symbols by default, with the goal of avoiding symbol name clashes between modules. Starting with v2.2, pybind11 enforces this more strictly: (1) by declaring all symbols inside the ``pybind11`` namespace as hidden and (2) by including the ``-fvisibility=hidden`` flag on Linux and macOS (only for extension modules, not for embedding the interpreter). .. _CPython's extension docs: https://docs.python.org/3/extending/extending.html#providing-a-c-api-for-an-extension-module The namespace-scope hidden visibility is done automatically in pybind11's headers and it's generally transparent to users. It ensures that: * Modules compiled with different pybind11 versions don't clash with each other. * Some new features, like ``py::module_local`` bindings, can work as intended. The ``-fvisibility=hidden`` flag applies the same visibility to user bindings outside of the ``pybind11`` namespace. It's now set automatic by pybind11's CMake and Python build systems, but this needs to be done manually by users of other build systems. Adding this flag: * Minimizes the chances of symbol conflicts between modules. E.g. if two unrelated modules were statically linked to different (ABI-incompatible) versions of the same third-party library, a symbol clash would be likely (and would end with unpredictable results). * Produces smaller binaries on Linux and macOS, as pointed out previously. Within pybind11's CMake build system, ``pybind11_add_module`` has always been setting the ``-fvisibility=hidden`` flag in release mode. From now on, it's being applied unconditionally, even in debug mode and it can no longer be opted out of with the ``NO_EXTRAS`` option. The ``pybind11::module`` target now also adds this flag to its interface. The ``pybind11::embed`` target is unchanged. The most significant change here is for the ``pybind11::module`` target. If you were previously relying on default visibility, i.e. if your Python module was doubling as a shared library with dependents, you'll need to either export symbols manually (recommended for cross-platform libraries) or factor out the shared library (and have the Python module link to it like the other dependents). As a temporary workaround, you can also restore default visibility using the CMake code below, but this is not recommended in the long run: .. code-block:: cmake target_link_libraries(mymodule PRIVATE pybind11::module) add_library(restore_default_visibility INTERFACE) target_compile_options(restore_default_visibility INTERFACE -fvisibility=default) target_link_libraries(mymodule PRIVATE restore_default_visibility) Local STL container bindings ---------------------------- Previous pybind11 versions could only bind types globally -- all pybind11 modules, even unrelated ones, would have access to the same exported types. However, this would also result in a conflict if two modules exported the same C++ type, which is especially problematic for very common types, e.g. ``std::vector``. :ref:`module_local` were added to resolve this (see that section for a complete usage guide). ``py::class_`` still defaults to global bindings (because these types are usually unique across modules), however in order to avoid clashes of opaque types, ``py::bind_vector`` and ``py::bind_map`` will now bind STL containers as ``py::module_local`` if their elements are: builtins (``int``, ``float``, etc.), not bound using ``py::class_``, or bound as ``py::module_local``. For example, this change allows multiple modules to bind ``std::vector`` without causing conflicts. See :ref:`stl_bind` for more details. When upgrading to this version, if you have multiple modules which depend on a single global binding of an STL container, note that all modules can still accept foreign ``py::module_local`` types in the direction of Python-to-C++. The locality only affects the C++-to-Python direction. If this is needed in multiple modules, you'll need to either: * Add a copy of the same STL binding to all of the modules which need it. * Restore the global status of that single binding by marking it ``py::module_local(false)``. The latter is an easy workaround, but in the long run it would be best to localize all common type bindings in order to avoid conflicts with third-party modules. Negative strides for Python buffer objects and numpy arrays ----------------------------------------------------------- Support for negative strides required changing the integer type from unsigned to signed in the interfaces of ``py::buffer_info`` and ``py::array``. If you have compiler warnings enabled, you may notice some new conversion warnings after upgrading. These can be resolved using ``static_cast``. Deprecation of some ``py::object`` APIs --------------------------------------- To compare ``py::object`` instances by pointer, you should now use ``obj1.is(obj2)`` which is equivalent to ``obj1 is obj2`` in Python. Previously, pybind11 used ``operator==`` for this (``obj1 == obj2``), but that could be confusing and is now deprecated (so that it can eventually be replaced with proper rich object comparison in a future release). For classes which inherit from ``py::object``, ``borrowed`` and ``stolen`` were previously available as protected constructor tags. Now the types should be used directly instead: ``borrowed_t{}`` and ``stolen_t{}`` (`#771 `_). Stricter compile-time error checking ------------------------------------ Some error checks have been moved from run time to compile time. Notably, automatic conversion of ``std::shared_ptr`` is not possible when ``T`` is not directly registered with ``py::class_`` (e.g. ``std::shared_ptr`` or ``std::shared_ptr>`` are not automatically convertible). Attempting to bind a function with such arguments now results in a compile-time error instead of waiting to fail at run time. ``py::init<...>()`` constructor definitions are also stricter and now prevent bindings which could cause unexpected behavior: .. code-block:: cpp struct Example { Example(int &); }; py::class_(m, "Example") .def(py::init()); // OK, exact match // .def(py::init()); // compile-time error, mismatch A non-``const`` lvalue reference is not allowed to bind to an rvalue. However, note that a constructor taking ``const T &`` can still be registered using ``py::init()`` because a ``const`` lvalue reference can bind to an rvalue. v2.1 ==== Minimum compiler versions are enforced at compile time ------------------------------------------------------ The minimums also apply to v2.0 but the check is now explicit and a compile-time error is raised if the compiler does not meet the requirements: * GCC >= 4.8 * clang >= 3.3 (appleclang >= 5.0) * MSVC >= 2015u3 * Intel C++ >= 15.0 The ``py::metaclass`` attribute is not required for static properties --------------------------------------------------------------------- Binding classes with static properties is now possible by default. The zero-parameter version of ``py::metaclass()`` is deprecated. However, a new one-parameter ``py::metaclass(python_type)`` version was added for rare cases when a custom metaclass is needed to override pybind11's default. .. code-block:: cpp // old -- emits a deprecation warning py::class_(m, "Foo", py::metaclass()) .def_property_readonly_static("foo", ...); // new -- static properties work without the attribute py::class_(m, "Foo") .def_property_readonly_static("foo", ...); // new -- advanced feature, override pybind11's default metaclass py::class_(m, "Bar", py::metaclass(custom_python_type)) ... v2.0 ==== Breaking changes in ``py::class_`` ---------------------------------- These changes were necessary to make type definitions in pybind11 future-proof, to support PyPy via its ``cpyext`` mechanism (`#527 `_), and to improve efficiency (`rev. 86d825 `_). 1. Declarations of types that provide access via the buffer protocol must now include the ``py::buffer_protocol()`` annotation as an argument to the ``py::class_`` constructor. .. code-block:: cpp py::class_("Matrix", py::buffer_protocol()) .def(py::init<...>()) .def_buffer(...); 2. Classes which include static properties (e.g. ``def_readwrite_static()``) must now include the ``py::metaclass()`` attribute. Note: this requirement has since been removed in v2.1. If you're upgrading from 1.x, it's recommended to skip directly to v2.1 or newer. 3. This version of pybind11 uses a redesigned mechanism for instantiating trampoline classes that are used to override virtual methods from within Python. This led to the following user-visible syntax change: .. code-block:: cpp // old v1.x syntax py::class_("MyClass") .alias() ... // new v2.x syntax py::class_("MyClass") ... Importantly, both the original and the trampoline class are now specified as arguments to the ``py::class_`` template, and the ``alias<..>()`` call is gone. The new scheme has zero overhead in cases when Python doesn't override any functions of the underlying C++ class. `rev. 86d825 `_. The class type must be the first template argument given to ``py::class_`` while the trampoline can be mixed in arbitrary order with other arguments (see the following section). Deprecation of the ``py::base()`` attribute ---------------------------------------------- ``py::base()`` was deprecated in favor of specifying ``T`` as a template argument to ``py::class_``. This new syntax also supports multiple inheritance. Note that, while the type being exported must be the first argument in the ``py::class_`` template, the order of the following types (bases, holder and/or trampoline) is not important. .. code-block:: cpp // old v1.x py::class_("Derived", py::base()); // new v2.x py::class_("Derived"); // new -- multiple inheritance py::class_("Derived"); // new -- apart from `Derived` the argument order can be arbitrary py::class_("Derived"); Out-of-the-box support for ``std::shared_ptr`` ---------------------------------------------- The relevant type caster is now built in, so it's no longer necessary to include a declaration of the form: .. code-block:: cpp PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) Continuing to do so won't cause an error or even a deprecation warning, but it's completely redundant. Deprecation of a few ``py::object`` APIs ---------------------------------------- All of the old-style calls emit deprecation warnings. +---------------------------------------+---------------------------------------------+ | Old syntax | New syntax | +=======================================+=============================================+ | ``obj.call(args...)`` | ``obj(args...)`` | +---------------------------------------+---------------------------------------------+ | ``obj.str()`` | ``py::str(obj)`` | +---------------------------------------+---------------------------------------------+ | ``auto l = py::list(obj); l.check()`` | ``py::isinstance(obj)`` | +---------------------------------------+---------------------------------------------+ | ``py::object(ptr, true)`` | ``py::reinterpret_borrow(ptr)`` | +---------------------------------------+---------------------------------------------+ | ``py::object(ptr, false)`` | ``py::reinterpret_steal(ptr)`` | +---------------------------------------+---------------------------------------------+ | ``if (obj.attr("foo"))`` | ``if (py::hasattr(obj, "foo"))`` | +---------------------------------------+---------------------------------------------+ | ``if (obj["bar"])`` | ``if (obj.contains("bar"))`` | +---------------------------------------+---------------------------------------------+ aoflagger-v3.4.0/external/pybind11/docs/release.rst0000644000175000017500000001047614507760431020713 0ustar olesolesOn version numbers ^^^^^^^^^^^^^^^^^^ The two version numbers (C++ and Python) must match when combined (checked when you build the PyPI package), and must be a valid `PEP 440 `_ version when combined. For example: .. code-block:: C++ #define PYBIND11_VERSION_MAJOR X #define PYBIND11_VERSION_MINOR Y #define PYBIND11_VERSION_PATCH Z.dev1 For beta, ``PYBIND11_VERSION_PATCH`` should be ``Z.b1``. RC's can be ``Z.rc1``. Always include the dot (even though PEP 440 allows it to be dropped). For a final release, this must be a simple integer. There is also a HEX version of the version just below. To release a new version of pybind11: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you don't have nox, you should either use ``pipx run nox`` instead, or use ``pipx install nox`` or ``brew install nox`` (Unix). - Update the version number - Update ``PYBIND11_VERSION_MAJOR`` etc. in ``include/pybind11/detail/common.h``. PATCH should be a simple integer. - Update the version HEX just below, as well. - Update ``pybind11/_version.py`` (match above) - Run ``nox -s tests_packaging`` to ensure this was done correctly. - Ensure that all the information in ``setup.cfg`` is up-to-date, like supported Python versions. - Add release date in ``docs/changelog.rst``. - Check to make sure `needs-changelog `_ issues are entered in the changelog (clear the label when done). - ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it fails due to a known flake issue, either ignore or restart CI.) - Add a release branch if this is a new minor version, or update the existing release branch if it is a patch version - New branch: ``git checkout -b vX.Y``, ``git push -u origin vX.Y`` - Update branch: ``git checkout vX.Y``, ``git merge ``, ``git push`` - Update tags (optional; if you skip this, the GitHub release makes a non-annotated tag for you) - ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``. - ``git push --tags``. - Update stable - ``git checkout stable`` - ``git merge master`` - ``git push`` - Make a GitHub release (this shows up in the UI, sends new release notifications to users watching releases, and also uploads PyPI packages). (Note: if you do not use an existing tag, this creates a new lightweight tag for you, so you could skip the above step.) - GUI method: Under `releases `_ click "Draft a new release" on the far right, fill in the tag name (if you didn't tag above, it will be made here), fill in a release name like "Version X.Y.Z", and copy-and-paste the markdown-formatted (!) changelog into the description (usually ``cat docs/changelog.rst | pandoc -f rst -t gfm``). Check "pre-release" if this is a beta/RC. - CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"`` If this is a pre-release, add ``-p``. - Get back to work - Make sure you are on master, not somewhere else: ``git checkout master`` - Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to ``0.dev1`` and increment MINOR). - Update ``_version.py`` to match - Run ``nox -s tests_packaging`` to ensure this was done correctly. - Add a spot for in-development updates in ``docs/changelog.rst``. - ``git add``, ``git commit``, ``git push`` If a version branch is updated, remember to set PATCH to ``1.dev1``. If you'd like to bump homebrew, run: .. code-block:: console brew bump-formula-pr --url https://github.com/pybind/pybind11/archive/vX.Y.Z.tar.gz Conda-forge should automatically make a PR in a few hours, and automatically merge it if there are no issues. Manual packaging ^^^^^^^^^^^^^^^^ If you need to manually upload releases, you can download the releases from the job artifacts and upload them with twine. You can also make the files locally (not recommended in general, as your local directory is more likely to be "dirty" and SDists love picking up random unrelated/hidden files); this is the procedure: .. code-block:: bash nox -s build twine upload dist/* This makes SDists and wheels, and the final line uploads them. aoflagger-v3.4.0/external/pybind11/docs/classes.rst0000644000175000017500000003777414507760431020742 0ustar olesoles.. _classes: Object-oriented code #################### Creating bindings for a custom type =================================== Let's now look at a more complex example where we'll create bindings for a custom C++ data structure named ``Pet``. Its definition is given below: .. code-block:: cpp struct Pet { Pet(const std::string &name) : name(name) { } void setName(const std::string &name_) { name = name_; } const std::string &getName() const { return name; } std::string name; }; The binding code for ``Pet`` looks as follows: .. code-block:: cpp #include namespace py = pybind11; PYBIND11_MODULE(example, m) { py::class_(m, "Pet") .def(py::init()) .def("setName", &Pet::setName) .def("getName", &Pet::getName); } :class:`class_` creates bindings for a C++ *class* or *struct*-style data structure. :func:`init` is a convenience function that takes the types of a constructor's parameters as template arguments and wraps the corresponding constructor (see the :ref:`custom_constructors` section for details). An interactive Python session demonstrating this example is shown below: .. code-block:: pycon % python >>> import example >>> p = example.Pet("Molly") >>> print(p) >>> p.getName() 'Molly' >>> p.setName("Charly") >>> p.getName() 'Charly' .. seealso:: Static member functions can be bound in the same way using :func:`class_::def_static`. Keyword and default arguments ============================= It is possible to specify keyword and default arguments using the syntax discussed in the previous chapter. Refer to the sections :ref:`keyword_args` and :ref:`default_args` for details. Binding lambda functions ======================== Note how ``print(p)`` produced a rather useless summary of our data structure in the example above: .. code-block:: pycon >>> print(p) To address this, we could bind a utility function that returns a human-readable summary to the special method slot named ``__repr__``. Unfortunately, there is no suitable functionality in the ``Pet`` data structure, and it would be nice if we did not have to change it. This can easily be accomplished by binding a Lambda function instead: .. code-block:: cpp py::class_(m, "Pet") .def(py::init()) .def("setName", &Pet::setName) .def("getName", &Pet::getName) .def("__repr__", [](const Pet &a) { return ""; } ); Both stateless [#f1]_ and stateful lambda closures are supported by pybind11. With the above change, the same Python code now produces the following output: .. code-block:: pycon >>> print(p) .. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object. .. _properties: Instance and static fields ========================== We can also directly expose the ``name`` field using the :func:`class_::def_readwrite` method. A similar :func:`class_::def_readonly` method also exists for ``const`` fields. .. code-block:: cpp py::class_(m, "Pet") .def(py::init()) .def_readwrite("name", &Pet::name) // ... remainder ... This makes it possible to write .. code-block:: pycon >>> p = example.Pet("Molly") >>> p.name 'Molly' >>> p.name = "Charly" >>> p.name 'Charly' Now suppose that ``Pet::name`` was a private internal variable that can only be accessed via setters and getters. .. code-block:: cpp class Pet { public: Pet(const std::string &name) : name(name) { } void setName(const std::string &name_) { name = name_; } const std::string &getName() const { return name; } private: std::string name; }; In this case, the method :func:`class_::def_property` (:func:`class_::def_property_readonly` for read-only data) can be used to provide a field-like interface within Python that will transparently call the setter and getter functions: .. code-block:: cpp py::class_(m, "Pet") .def(py::init()) .def_property("name", &Pet::getName, &Pet::setName) // ... remainder ... Write only properties can be defined by passing ``nullptr`` as the input for the read function. .. seealso:: Similar functions :func:`class_::def_readwrite_static`, :func:`class_::def_readonly_static` :func:`class_::def_property_static`, and :func:`class_::def_property_readonly_static` are provided for binding static variables and properties. Please also see the section on :ref:`static_properties` in the advanced part of the documentation. Dynamic attributes ================== Native Python classes can pick up new attributes dynamically: .. code-block:: pycon >>> class Pet: ... name = "Molly" ... >>> p = Pet() >>> p.name = "Charly" # overwrite existing >>> p.age = 2 # dynamically add a new attribute By default, classes exported from C++ do not support this and the only writable attributes are the ones explicitly defined using :func:`class_::def_readwrite` or :func:`class_::def_property`. .. code-block:: cpp py::class_(m, "Pet") .def(py::init<>()) .def_readwrite("name", &Pet::name); Trying to set any other attribute results in an error: .. code-block:: pycon >>> p = example.Pet() >>> p.name = "Charly" # OK, attribute defined in C++ >>> p.age = 2 # fail AttributeError: 'Pet' object has no attribute 'age' To enable dynamic attributes for C++ classes, the :class:`py::dynamic_attr` tag must be added to the :class:`py::class_` constructor: .. code-block:: cpp py::class_(m, "Pet", py::dynamic_attr()) .def(py::init<>()) .def_readwrite("name", &Pet::name); Now everything works as expected: .. code-block:: pycon >>> p = example.Pet() >>> p.name = "Charly" # OK, overwrite value in C++ >>> p.age = 2 # OK, dynamically add a new attribute >>> p.__dict__ # just like a native Python class {'age': 2} Note that there is a small runtime cost for a class with dynamic attributes. Not only because of the addition of a ``__dict__``, but also because of more expensive garbage collection tracking which must be activated to resolve possible circular references. Native Python classes incur this same cost by default, so this is not anything to worry about. By default, pybind11 classes are more efficient than native Python classes. Enabling dynamic attributes just brings them on par. .. _inheritance: Inheritance and automatic downcasting ===================================== Suppose now that the example consists of two data structures with an inheritance relationship: .. code-block:: cpp struct Pet { Pet(const std::string &name) : name(name) { } std::string name; }; struct Dog : Pet { Dog(const std::string &name) : Pet(name) { } std::string bark() const { return "woof!"; } }; There are two different ways of indicating a hierarchical relationship to pybind11: the first specifies the C++ base class as an extra template parameter of the :class:`class_`: .. code-block:: cpp py::class_(m, "Pet") .def(py::init()) .def_readwrite("name", &Pet::name); // Method 1: template parameter: py::class_(m, "Dog") .def(py::init()) .def("bark", &Dog::bark); Alternatively, we can also assign a name to the previously bound ``Pet`` :class:`class_` object and reference it when binding the ``Dog`` class: .. code-block:: cpp py::class_ pet(m, "Pet"); pet.def(py::init()) .def_readwrite("name", &Pet::name); // Method 2: pass parent class_ object: py::class_(m, "Dog", pet /* <- specify Python parent type */) .def(py::init()) .def("bark", &Dog::bark); Functionality-wise, both approaches are equivalent. Afterwards, instances will expose fields and methods of both types: .. code-block:: pycon >>> p = example.Dog("Molly") >>> p.name 'Molly' >>> p.bark() 'woof!' The C++ classes defined above are regular non-polymorphic types with an inheritance relationship. This is reflected in Python: .. code-block:: cpp // Return a base pointer to a derived instance m.def("pet_store", []() { return std::unique_ptr(new Dog("Molly")); }); .. code-block:: pycon >>> p = example.pet_store() >>> type(p) # `Dog` instance behind `Pet` pointer Pet # no pointer downcasting for regular non-polymorphic types >>> p.bark() AttributeError: 'Pet' object has no attribute 'bark' The function returned a ``Dog`` instance, but because it's a non-polymorphic type behind a base pointer, Python only sees a ``Pet``. In C++, a type is only considered polymorphic if it has at least one virtual function and pybind11 will automatically recognize this: .. code-block:: cpp struct PolymorphicPet { virtual ~PolymorphicPet() = default; }; struct PolymorphicDog : PolymorphicPet { std::string bark() const { return "woof!"; } }; // Same binding code py::class_(m, "PolymorphicPet"); py::class_(m, "PolymorphicDog") .def(py::init<>()) .def("bark", &PolymorphicDog::bark); // Again, return a base pointer to a derived instance m.def("pet_store2", []() { return std::unique_ptr(new PolymorphicDog); }); .. code-block:: pycon >>> p = example.pet_store2() >>> type(p) PolymorphicDog # automatically downcast >>> p.bark() 'woof!' Given a pointer to a polymorphic base, pybind11 performs automatic downcasting to the actual derived type. Note that this goes beyond the usual situation in C++: we don't just get access to the virtual functions of the base, we get the concrete derived type including functions and attributes that the base type may not even be aware of. .. seealso:: For more information about polymorphic behavior see :ref:`overriding_virtuals`. Overloaded methods ================== Sometimes there are several overloaded C++ methods with the same name taking different kinds of input arguments: .. code-block:: cpp struct Pet { Pet(const std::string &name, int age) : name(name), age(age) { } void set(int age_) { age = age_; } void set(const std::string &name_) { name = name_; } std::string name; int age; }; Attempting to bind ``Pet::set`` will cause an error since the compiler does not know which method the user intended to select. We can disambiguate by casting them to function pointers. Binding multiple functions to the same Python name automatically creates a chain of function overloads that will be tried in sequence. .. code-block:: cpp py::class_(m, "Pet") .def(py::init()) .def("set", static_cast(&Pet::set), "Set the pet's age") .def("set", static_cast(&Pet::set), "Set the pet's name"); The overload signatures are also visible in the method's docstring: .. code-block:: pycon >>> help(example.Pet) class Pet(__builtin__.object) | Methods defined here: | | __init__(...) | Signature : (Pet, str, int) -> NoneType | | set(...) | 1. Signature : (Pet, int) -> NoneType | | Set the pet's age | | 2. Signature : (Pet, str) -> NoneType | | Set the pet's name If you have a C++14 compatible compiler [#cpp14]_, you can use an alternative syntax to cast the overloaded function: .. code-block:: cpp py::class_(m, "Pet") .def("set", py::overload_cast(&Pet::set), "Set the pet's age") .def("set", py::overload_cast(&Pet::set), "Set the pet's name"); Here, ``py::overload_cast`` only requires the parameter types to be specified. The return type and class are deduced. This avoids the additional noise of ``void (Pet::*)()`` as seen in the raw cast. If a function is overloaded based on constness, the ``py::const_`` tag should be used: .. code-block:: cpp struct Widget { int foo(int x, float y); int foo(int x, float y) const; }; py::class_(m, "Widget") .def("foo_mutable", py::overload_cast(&Widget::foo)) .def("foo_const", py::overload_cast(&Widget::foo, py::const_)); If you prefer the ``py::overload_cast`` syntax but have a C++11 compatible compiler only, you can use ``py::detail::overload_cast_impl`` with an additional set of parentheses: .. code-block:: cpp template using overload_cast_ = pybind11::detail::overload_cast_impl; py::class_(m, "Pet") .def("set", overload_cast_()(&Pet::set), "Set the pet's age") .def("set", overload_cast_()(&Pet::set), "Set the pet's name"); .. [#cpp14] A compiler which supports the ``-std=c++14`` flag. .. note:: To define multiple overloaded constructors, simply declare one after the other using the ``.def(py::init<...>())`` syntax. The existing machinery for specifying keyword and default arguments also works. Enumerations and internal types =============================== Let's now suppose that the example class contains internal types like enumerations, e.g.: .. code-block:: cpp struct Pet { enum Kind { Dog = 0, Cat }; struct Attributes { float age = 0; }; Pet(const std::string &name, Kind type) : name(name), type(type) { } std::string name; Kind type; Attributes attr; }; The binding code for this example looks as follows: .. code-block:: cpp py::class_ pet(m, "Pet"); pet.def(py::init()) .def_readwrite("name", &Pet::name) .def_readwrite("type", &Pet::type) .def_readwrite("attr", &Pet::attr); py::enum_(pet, "Kind") .value("Dog", Pet::Kind::Dog) .value("Cat", Pet::Kind::Cat) .export_values(); py::class_(pet, "Attributes") .def(py::init<>()) .def_readwrite("age", &Pet::Attributes::age); To ensure that the nested types ``Kind`` and ``Attributes`` are created within the scope of ``Pet``, the ``pet`` :class:`class_` instance must be supplied to the :class:`enum_` and :class:`class_` constructor. The :func:`enum_::export_values` function exports the enum entries into the parent scope, which should be skipped for newer C++11-style strongly typed enums. .. code-block:: pycon >>> p = Pet("Lucy", Pet.Cat) >>> p.type Kind.Cat >>> int(p.type) 1L The entries defined by the enumeration type are exposed in the ``__members__`` property: .. code-block:: pycon >>> Pet.Kind.__members__ {'Dog': Kind.Dog, 'Cat': Kind.Cat} The ``name`` property returns the name of the enum value as a unicode string. .. note:: It is also possible to use ``str(enum)``, however these accomplish different goals. The following shows how these two approaches differ. .. code-block:: pycon >>> p = Pet("Lucy", Pet.Cat) >>> pet_type = p.type >>> pet_type Pet.Cat >>> str(pet_type) 'Pet.Cat' >>> pet_type.name 'Cat' .. note:: When the special tag ``py::arithmetic()`` is specified to the ``enum_`` constructor, pybind11 creates an enumeration that also supports rudimentary arithmetic and bit-level operations like comparisons, and, or, xor, negation, etc. .. code-block:: cpp py::enum_(pet, "Kind", py::arithmetic()) ... By default, these are omitted to conserve space. aoflagger-v3.4.0/external/pybind11/docs/requirements.txt0000644000175000017500000000022514507760431022014 0ustar olesolesbreathe==4.34.0 furo==2022.6.21 sphinx==5.0.2 sphinx-copybutton==0.5.0 sphinxcontrib-moderncmakedomain==3.21.4 sphinxcontrib-svg2pdfconverter==1.2.0 aoflagger-v3.4.0/external/pybind11/docs/_static/0000755000175000017500000000000014516225226020155 5ustar olesolesaoflagger-v3.4.0/external/pybind11/docs/_static/css/0000755000175000017500000000000014516225226020745 5ustar olesolesaoflagger-v3.4.0/external/pybind11/docs/_static/css/custom.css0000644000175000017500000000004514507760431022772 0ustar olesoles.highlight .go { color: #707070; } aoflagger-v3.4.0/external/pybind11/docs/pybind11_vs_boost_python1.svg0000644000175000017500000025323414507760431024312 0ustar olesoles aoflagger-v3.4.0/external/pybind11/docs/compiling.rst0000644000175000017500000006226114507760431021253 0ustar olesoles.. _compiling: Build systems ############# .. _build-setuptools: Building with setuptools ======================== For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay has kindly provided an example project which shows how to set up everything, including automatic generation of documentation using Sphinx. Please refer to the [python_example]_ repository. .. [python_example] https://github.com/pybind/python_example A helper file is provided with pybind11 that can simplify usage with setuptools. To use pybind11 inside your ``setup.py``, you have to have some system to ensure that ``pybind11`` is installed when you build your package. There are four possible ways to do this, and pybind11 supports all four: You can ask all users to install pybind11 beforehand (bad), you can use :ref:`setup_helpers-pep518` (good, but very new and requires Pip 10), :ref:`setup_helpers-setup_requires` (discouraged by Python packagers now that PEP 518 is available, but it still works everywhere), or you can :ref:`setup_helpers-copy-manually` (always works but you have to manually sync your copy to get updates). An example of a ``setup.py`` using pybind11's helpers: .. code-block:: python from glob import glob from setuptools import setup from pybind11.setup_helpers import Pybind11Extension ext_modules = [ Pybind11Extension( "python_example", sorted(glob("src/*.cpp")), # Sort source files for reproducibility ), ] setup(..., ext_modules=ext_modules) If you want to do an automatic search for the highest supported C++ standard, that is supported via a ``build_ext`` command override; it will only affect ``Pybind11Extensions``: .. code-block:: python from glob import glob from setuptools import setup from pybind11.setup_helpers import Pybind11Extension, build_ext ext_modules = [ Pybind11Extension( "python_example", sorted(glob("src/*.cpp")), ), ] setup(..., cmdclass={"build_ext": build_ext}, ext_modules=ext_modules) If you have single-file extension modules that are directly stored in the Python source tree (``foo.cpp`` in the same directory as where a ``foo.py`` would be located), you can also generate ``Pybind11Extensions`` using ``setup_helpers.intree_extensions``: ``intree_extensions(["path/to/foo.cpp", ...])`` returns a list of ``Pybind11Extensions`` which can be passed to ``ext_modules``, possibly after further customizing their attributes (``libraries``, ``include_dirs``, etc.). By doing so, a ``foo.*.so`` extension module will be generated and made available upon installation. ``intree_extension`` will automatically detect if you are using a ``src``-style layout (as long as no namespace packages are involved), but you can also explicitly pass ``package_dir`` to it (as in ``setuptools.setup``). Since pybind11 does not require NumPy when building, a light-weight replacement for NumPy's parallel compilation distutils tool is included. Use it like this: .. code-block:: python from pybind11.setup_helpers import ParallelCompile # Optional multithreaded build ParallelCompile("NPY_NUM_BUILD_JOBS").install() setup(...) The argument is the name of an environment variable to control the number of threads, such as ``NPY_NUM_BUILD_JOBS`` (as used by NumPy), though you can set something different if you want; ``CMAKE_BUILD_PARALLEL_LEVEL`` is another choice a user might expect. You can also pass ``default=N`` to set the default number of threads (0 will take the number of threads available) and ``max=N``, the maximum number of threads; if you have a large extension you may want set this to a memory dependent number. If you are developing rapidly and have a lot of C++ files, you may want to avoid rebuilding files that have not changed. For simple cases were you are using ``pip install -e .`` and do not have local headers, you can skip the rebuild if an object file is newer than its source (headers are not checked!) with the following: .. code-block:: python from pybind11.setup_helpers import ParallelCompile, naive_recompile ParallelCompile("NPY_NUM_BUILD_JOBS", needs_recompile=naive_recompile).install() If you have a more complex build, you can implement a smarter function and pass it to ``needs_recompile``, or you can use [Ccache]_ instead. ``CXX="cache g++" pip install -e .`` would be the way to use it with GCC, for example. Unlike the simple solution, this even works even when not compiling in editable mode, but it does require Ccache to be installed. Keep in mind that Pip will not even attempt to rebuild if it thinks it has already built a copy of your code, which it deduces from the version number. One way to avoid this is to use [setuptools_scm]_, which will generate a version number that includes the number of commits since your last tag and a hash for a dirty directory. Another way to force a rebuild is purge your cache or use Pip's ``--no-cache-dir`` option. .. [Ccache] https://ccache.dev .. [setuptools_scm] https://github.com/pypa/setuptools_scm .. _setup_helpers-pep518: PEP 518 requirements (Pip 10+ required) --------------------------------------- If you use `PEP 518's `_ ``pyproject.toml`` file, you can ensure that ``pybind11`` is available during the compilation of your project. When this file exists, Pip will make a new virtual environment, download just the packages listed here in ``requires=``, and build a wheel (binary Python package). It will then throw away the environment, and install your wheel. Your ``pyproject.toml`` file will likely look something like this: .. code-block:: toml [build-system] requires = ["setuptools>=42", "wheel", "pybind11~=2.6.1"] build-backend = "setuptools.build_meta" .. note:: The main drawback to this method is that a `PEP 517`_ compliant build tool, such as Pip 10+, is required for this approach to work; older versions of Pip completely ignore this file. If you distribute binaries (called wheels in Python) using something like `cibuildwheel`_, remember that ``setup.py`` and ``pyproject.toml`` are not even contained in the wheel, so this high Pip requirement is only for source builds, and will not affect users of your binary wheels. If you are building SDists and wheels, then `pypa-build`_ is the recommended official tool. .. _PEP 517: https://www.python.org/dev/peps/pep-0517/ .. _cibuildwheel: https://cibuildwheel.readthedocs.io .. _pypa-build: https://pypa-build.readthedocs.io/en/latest/ .. _setup_helpers-setup_requires: Classic ``setup_requires`` -------------------------- If you want to support old versions of Pip with the classic ``setup_requires=["pybind11"]`` keyword argument to setup, which triggers a two-phase ``setup.py`` run, then you will need to use something like this to ensure the first pass works (which has not yet installed the ``setup_requires`` packages, since it can't install something it does not know about): .. code-block:: python try: from pybind11.setup_helpers import Pybind11Extension except ImportError: from setuptools import Extension as Pybind11Extension It doesn't matter that the Extension class is not the enhanced subclass for the first pass run; and the second pass will have the ``setup_requires`` requirements. This is obviously more of a hack than the PEP 518 method, but it supports ancient versions of Pip. .. _setup_helpers-copy-manually: Copy manually ------------- You can also copy ``setup_helpers.py`` directly to your project; it was designed to be usable standalone, like the old example ``setup.py``. You can set ``include_pybind11=False`` to skip including the pybind11 package headers, so you can use it with git submodules and a specific git version. If you use this, you will need to import from a local file in ``setup.py`` and ensure the helper file is part of your MANIFEST. Closely related, if you include pybind11 as a subproject, you can run the ``setup_helpers.py`` inplace. If loaded correctly, this should even pick up the correct include for pybind11, though you can turn it off as shown above if you want to input it manually. Suggested usage if you have pybind11 as a submodule in ``extern/pybind11``: .. code-block:: python DIR = os.path.abspath(os.path.dirname(__file__)) sys.path.append(os.path.join(DIR, "extern", "pybind11")) from pybind11.setup_helpers import Pybind11Extension # noqa: E402 del sys.path[-1] .. versionchanged:: 2.6 Added ``setup_helpers`` file. Building with cppimport ======================== [cppimport]_ is a small Python import hook that determines whether there is a C++ source file whose name matches the requested module. If there is, the file is compiled as a Python extension using pybind11 and placed in the same folder as the C++ source file. Python is then able to find the module and load it. .. [cppimport] https://github.com/tbenthompson/cppimport .. _cmake: Building with CMake =================== For C++ codebases that have an existing CMake-based build system, a Python extension module can be created with just a few lines of code: .. code-block:: cmake cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp) This assumes that the pybind11 repository is located in a subdirectory named :file:`pybind11` and that the code is located in a file named :file:`example.cpp`. The CMake command ``add_subdirectory`` will import the pybind11 project which provides the ``pybind11_add_module`` function. It will take care of all the details needed to build a Python extension module on any platform. A working sample project, including a way to invoke CMake from :file:`setup.py` for PyPI integration, can be found in the [cmake_example]_ repository. .. [cmake_example] https://github.com/pybind/cmake_example .. versionchanged:: 2.6 CMake 3.4+ is required. Further information can be found at :doc:`cmake/index`. pybind11_add_module ------------------- To ease the creation of Python extension modules, pybind11 provides a CMake function with the following signature: .. code-block:: cmake pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] [NO_EXTRAS] [THIN_LTO] [OPT_SIZE] source1 [source2 ...]) This function behaves very much like CMake's builtin ``add_library`` (in fact, it's a wrapper function around that command). It will add a library target called ```` to be built from the listed source files. In addition, it will take care of all the Python-specific compiler and linker flags as well as the OS- and Python-version-specific file extension. The produced target ```` can be further manipulated with regular CMake commands. ``MODULE`` or ``SHARED`` may be given to specify the type of library. If no type is given, ``MODULE`` is used by default which ensures the creation of a Python-exclusive module. Specifying ``SHARED`` will create a more traditional dynamic library which can also be linked from elsewhere. ``EXCLUDE_FROM_ALL`` removes this target from the default build (see CMake docs for details). Since pybind11 is a template library, ``pybind11_add_module`` adds compiler flags to ensure high quality code generation without bloat arising from long symbol names and duplication of code in different translation units. It sets default visibility to *hidden*, which is required for some pybind11 features and functionality when attempting to load multiple pybind11 modules compiled under different pybind11 versions. It also adds additional flags enabling LTO (Link Time Optimization) and strip unneeded symbols. See the :ref:`FAQ entry ` for a more detailed explanation. These latter optimizations are never applied in ``Debug`` mode. If ``NO_EXTRAS`` is given, they will always be disabled, even in ``Release`` mode. However, this will result in code bloat and is generally not recommended. As stated above, LTO is enabled by default. Some newer compilers also support different flavors of LTO such as `ThinLTO`_. Setting ``THIN_LTO`` will cause the function to prefer this flavor if available. The function falls back to regular LTO if ``-flto=thin`` is not available. If ``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` is set (either ``ON`` or ``OFF``), then that will be respected instead of the built-in flag search. .. note:: If you want to set the property form on targets or the ``CMAKE_INTERPROCEDURAL_OPTIMIZATION_`` versions of this, you should still use ``set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF)`` (otherwise a no-op) to disable pybind11's ipo flags. The ``OPT_SIZE`` flag enables size-based optimization equivalent to the standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type, which avoid optimizations that that can substantially increase the size of the resulting binary. This flag is particularly useful in projects that are split into performance-critical parts and associated bindings. In this case, we can compile the project in release mode (and hence, optimize performance globally), and specify ``OPT_SIZE`` for the binding target, where size might be the main concern as performance is often less critical here. A ~25% size reduction has been observed in practice. This flag only changes the optimization behavior at a per-target level and takes precedence over the global CMake build type (``Release``, ``RelWithDebInfo``) except for ``Debug`` builds, where optimizations remain disabled. .. _ThinLTO: http://clang.llvm.org/docs/ThinLTO.html Configuration variables ----------------------- By default, pybind11 will compile modules with the compiler default or the minimum standard required by pybind11, whichever is higher. You can set the standard explicitly with `CMAKE_CXX_STANDARD `_: .. code-block:: cmake set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ version selection") # or 11, 14, 17, 20 set(CMAKE_CXX_STANDARD_REQUIRED ON) # optional, ensure standard is supported set(CMAKE_CXX_EXTENSIONS OFF) # optional, keep compiler extensions off The variables can also be set when calling CMake from the command line using the ``-D=`` flag. You can also manually set ``CXX_STANDARD`` on a target or use ``target_compile_features`` on your targets - anything that CMake supports. Classic Python support: The target Python version can be selected by setting ``PYBIND11_PYTHON_VERSION`` or an exact Python installation can be specified with ``PYTHON_EXECUTABLE``. For example: .. code-block:: bash cmake -DPYBIND11_PYTHON_VERSION=3.6 .. # Another method: cmake -DPYTHON_EXECUTABLE=/path/to/python .. # This often is a good way to get the current Python, works in environments: cmake -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") .. find_package vs. add_subdirectory --------------------------------- For CMake-based projects that don't include the pybind11 repository internally, an external installation can be detected through ``find_package(pybind11)``. See the `Config file`_ docstring for details of relevant CMake variables. .. code-block:: cmake cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) pybind11_add_module(example example.cpp) Note that ``find_package(pybind11)`` will only work correctly if pybind11 has been correctly installed on the system, e. g. after downloading or cloning the pybind11 repository : .. code-block:: bash # Classic CMake cd pybind11 mkdir build cd build cmake .. make install # CMake 3.15+ cd pybind11 cmake -S . -B build cmake --build build -j 2 # Build on 2 cores cmake --install build Once detected, the aforementioned ``pybind11_add_module`` can be employed as before. The function usage and configuration variables are identical no matter if pybind11 is added as a subdirectory or found as an installed package. You can refer to the same [cmake_example]_ repository for a full sample project -- just swap out ``add_subdirectory`` for ``find_package``. .. _Config file: https://github.com/pybind/pybind11/blob/master/tools/pybind11Config.cmake.in .. _find-python-mode: FindPython mode --------------- CMake 3.12+ (3.15+ recommended, 3.18.2+ ideal) added a new module called FindPython that had a highly improved search algorithm and modern targets and tools. If you use FindPython, pybind11 will detect this and use the existing targets instead: .. code-block:: cmake cmake_minimum_required(VERSION 3.15...3.22) project(example LANGUAGES CXX) find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED) find_package(pybind11 CONFIG REQUIRED) # or add_subdirectory(pybind11) pybind11_add_module(example example.cpp) You can also use the targets (as listed below) with FindPython. If you define ``PYBIND11_FINDPYTHON``, pybind11 will perform the FindPython step for you (mostly useful when building pybind11's own tests, or as a way to change search algorithms from the CMake invocation, with ``-DPYBIND11_FINDPYTHON=ON``. .. warning:: If you use FindPython to multi-target Python versions, use the individual targets listed below, and avoid targets that directly include Python parts. There are `many ways to hint or force a discovery of a specific Python installation `_), setting ``Python_ROOT_DIR`` may be the most common one (though with virtualenv/venv support, and Conda support, this tends to find the correct Python version more often than the old system did). .. warning:: When the Python libraries (i.e. ``libpythonXX.a`` and ``libpythonXX.so`` on Unix) are not available, as is the case on a manylinux image, the ``Development`` component will not be resolved by ``FindPython``. When not using the embedding functionality, CMake 3.18+ allows you to specify ``Development.Module`` instead of ``Development`` to resolve this issue. .. versionadded:: 2.6 Advanced: interface library targets ----------------------------------- Pybind11 supports modern CMake usage patterns with a set of interface targets, available in all modes. The targets provided are: ``pybind11::headers`` Just the pybind11 headers and minimum compile requirements ``pybind11::pybind11`` Python headers + ``pybind11::headers`` ``pybind11::python_link_helper`` Just the "linking" part of pybind11:module ``pybind11::module`` Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper`` ``pybind11::embed`` Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Python`` (FindPython) or Python libs ``pybind11::lto`` / ``pybind11::thin_lto`` An alternative to `INTERPROCEDURAL_OPTIMIZATION` for adding link-time optimization. ``pybind11::windows_extras`` ``/bigobj`` and ``/mp`` for MSVC. ``pybind11::opt_size`` ``/Os`` for MSVC, ``-Os`` for other compilers. Does nothing for debug builds. Two helper functions are also provided: ``pybind11_strip(target)`` Strips a target (uses ``CMAKE_STRIP`` after the target is built) ``pybind11_extension(target)`` Sets the correct extension (with SOABI) for a target. You can use these targets to build complex applications. For example, the ``add_python_module`` function is identical to: .. code-block:: cmake cmake_minimum_required(VERSION 3.4) project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) add_library(example MODULE main.cpp) target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras) pybind11_extension(example) if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo) # Strip unnecessary sections of the binary on Linux/macOS pybind11_strip(example) endif() set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden" CUDA_VISIBILITY_PRESET "hidden") Instead of setting properties, you can set ``CMAKE_*`` variables to initialize these correctly. .. warning:: Since pybind11 is a metatemplate library, it is crucial that certain compiler flags are provided to ensure high quality code generation. In contrast to the ``pybind11_add_module()`` command, the CMake interface provides a *composable* set of targets to ensure that you retain flexibility. It can be especially important to provide or set these properties; the :ref:`FAQ ` contains an explanation on why these are needed. .. versionadded:: 2.6 .. _nopython-mode: Advanced: NOPYTHON mode ----------------------- If you want complete control, you can set ``PYBIND11_NOPYTHON`` to completely disable Python integration (this also happens if you run ``FindPython2`` and ``FindPython3`` without running ``FindPython``). This gives you complete freedom to integrate into an existing system (like `Scikit-Build's `_ ``PythonExtensions``). ``pybind11_add_module`` and ``pybind11_extension`` will be unavailable, and the targets will be missing any Python specific behavior. .. versionadded:: 2.6 Embedding the Python interpreter -------------------------------- In addition to extension modules, pybind11 also supports embedding Python into a C++ executable or library. In CMake, simply link with the ``pybind11::embed`` target. It provides everything needed to get the interpreter running. The Python headers and libraries are attached to the target. Unlike ``pybind11::module``, there is no need to manually set any additional properties here. For more information about usage in C++, see :doc:`/advanced/embedding`. .. code-block:: cmake cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) add_executable(example main.cpp) target_link_libraries(example PRIVATE pybind11::embed) .. _building_manually: Building manually ================= pybind11 is a header-only library, hence it is not necessary to link against any special libraries and there are no intermediate (magic) translation steps. On Linux, you can compile an example such as the one given in :ref:`simple_example` using the following command: .. code-block:: bash $ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix) The ``python3 -m pybind11 --includes`` command fetches the include paths for both pybind11 and Python headers. This assumes that pybind11 has been installed using ``pip`` or ``conda``. If it hasn't, you can also manually specify ``-I /include`` together with the Python includes path ``python3-config --includes``. On macOS: the build command is almost the same but it also requires passing the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when building the module: .. code-block:: bash $ c++ -O3 -Wall -shared -std=c++11 -undefined dynamic_lookup $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix) In general, it is advisable to include several additional build parameters that can considerably reduce the size of the created binary. Refer to section :ref:`cmake` for a detailed example of a suitable cross-platform CMake-based build system that works on all platforms including Windows. .. note:: On Linux and macOS, it's better to (intentionally) not link against ``libpython``. The symbols will be resolved when the extension library is loaded into a Python binary. This is preferable because you might have several different installations of a given Python version (e.g. the system-provided Python, and one that ships with a piece of commercial software). In this way, the plugin will work with both versions, instead of possibly importing a second Python library into a process that already contains one (which will lead to a segfault). Building with Bazel =================== You can build with the Bazel build system using the `pybind11_bazel `_ repository. Generating binding code automatically ===================================== The ``Binder`` project is a tool for automatic generation of pybind11 binding code by introspecting existing C++ codebases using LLVM/Clang. See the [binder]_ documentation for details. .. [binder] http://cppbinder.readthedocs.io/en/latest/about.html [AutoWIG]_ is a Python library that wraps automatically compiled libraries into high-level languages. It parses C++ code using LLVM/Clang technologies and generates the wrappers using the Mako templating engine. The approach is automatic, extensible, and applies to very complex C++ libraries, composed of thousands of classes or incorporating modern meta-programming constructs. .. [AutoWIG] https://github.com/StatisKit/AutoWIG [robotpy-build]_ is a is a pure python, cross platform build tool that aims to simplify creation of python wheels for pybind11 projects, and provide cross-project dependency management. Additionally, it is able to autogenerate customizable pybind11-based wrappers by parsing C++ header files. .. [robotpy-build] https://robotpy-build.readthedocs.io aoflagger-v3.4.0/external/pybind11/docs/pybind11_vs_boost_python2.svg0000644000175000017500000024753514507760431024322 0ustar olesoles aoflagger-v3.4.0/external/pybind11/docs/Makefile0000644000175000017500000001637114507760431020201 0ustar olesoles# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = .build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pybind11.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pybind11.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/pybind11" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pybind11" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." aoflagger-v3.4.0/external/pybind11/docs/advanced/0000755000175000017500000000000014516225226020274 5ustar olesolesaoflagger-v3.4.0/external/pybind11/docs/advanced/smart_ptrs.rst0000644000175000017500000001435114507760431023232 0ustar olesolesSmart pointers ############## std::unique_ptr =============== Given a class ``Example`` with Python bindings, it's possible to return instances wrapped in C++11 unique pointers, like so .. code-block:: cpp std::unique_ptr create_example() { return std::unique_ptr(new Example()); } .. code-block:: cpp m.def("create_example", &create_example); In other words, there is nothing special that needs to be done. While returning unique pointers in this way is allowed, it is *illegal* to use them as function arguments. For instance, the following function signature cannot be processed by pybind11. .. code-block:: cpp void do_something_with_example(std::unique_ptr ex) { ... } The above signature would imply that Python needs to give up ownership of an object that is passed to this function, which is generally not possible (for instance, the object might be referenced elsewhere). std::shared_ptr =============== The binding generator for classes, :class:`class_`, can be passed a template type that denotes a special *holder* type that is used to manage references to the object. If no such holder type template argument is given, the default for a type named ``Type`` is ``std::unique_ptr``, which means that the object is deallocated when Python's reference count goes to zero. It is possible to switch to other types of reference counting wrappers or smart pointers, which is useful in codebases that rely on them. For instance, the following snippet causes ``std::shared_ptr`` to be used instead. .. code-block:: cpp py::class_ /* <- holder type */> obj(m, "Example"); Note that any particular class can only be associated with a single holder type. One potential stumbling block when using holder types is that they need to be applied consistently. Can you guess what's broken about the following binding code? .. code-block:: cpp class Child { }; class Parent { public: Parent() : child(std::make_shared()) { } Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */ private: std::shared_ptr child; }; PYBIND11_MODULE(example, m) { py::class_>(m, "Child"); py::class_>(m, "Parent") .def(py::init<>()) .def("get_child", &Parent::get_child); } The following Python code will cause undefined behavior (and likely a segmentation fault). .. code-block:: python from example import Parent print(Parent().get_child()) The problem is that ``Parent::get_child()`` returns a pointer to an instance of ``Child``, but the fact that this instance is already managed by ``std::shared_ptr<...>`` is lost when passing raw pointers. In this case, pybind11 will create a second independent ``std::shared_ptr<...>`` that also claims ownership of the pointer. In the end, the object will be freed **twice** since these shared pointers have no way of knowing about each other. There are two ways to resolve this issue: 1. For types that are managed by a smart pointer class, never use raw pointers in function arguments or return values. In other words: always consistently wrap pointers into their designated holder types (such as ``std::shared_ptr<...>``). In this case, the signature of ``get_child()`` should be modified as follows: .. code-block:: cpp std::shared_ptr get_child() { return child; } 2. Adjust the definition of ``Child`` by specifying ``std::enable_shared_from_this`` (see cppreference_ for details) as a base class. This adds a small bit of information to ``Child`` that allows pybind11 to realize that there is already an existing ``std::shared_ptr<...>`` and communicate with it. In this case, the declaration of ``Child`` should look as follows: .. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this .. code-block:: cpp class Child : public std::enable_shared_from_this { }; .. _smart_pointers: Custom smart pointers ===================== pybind11 supports ``std::unique_ptr`` and ``std::shared_ptr`` right out of the box. For any other custom smart pointer, transparent conversions can be enabled using a macro invocation similar to the following. It must be declared at the top namespace level before any binding code: .. code-block:: cpp PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a placeholder name that is used as a template parameter of the second argument. Thus, feel free to use any identifier, but use it consistently on both sides; also, don't use the name of a type that already exists in your codebase. The macro also accepts a third optional boolean parameter that is set to false by default. Specify .. code-block:: cpp PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr, true); if ``SmartPtr`` can always be initialized from a ``T*`` pointer without the risk of inconsistencies (such as multiple independent ``SmartPtr`` instances believing that they are the sole owner of the ``T*`` pointer). A common situation where ``true`` should be passed is when the ``T`` instances use *intrusive* reference counting. Please take a look at the :ref:`macro_notes` before using this feature. By default, pybind11 assumes that your custom smart pointer has a standard interface, i.e. provides a ``.get()`` member function to access the underlying raw pointer. If this is not the case, pybind11's ``holder_helper`` must be specialized: .. code-block:: cpp // Always needed for custom holder types PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); // Only needed if the type's `.get()` goes by another name namespace PYBIND11_NAMESPACE { namespace detail { template struct holder_helper> { // <-- specialization static const T *get(const SmartPtr &p) { return p.getPointer(); } }; }} The above specialization informs pybind11 that the custom ``SmartPtr`` class provides ``.get()`` functionality via ``.getPointer()``. .. seealso:: The file :file:`tests/test_smart_ptr.cpp` contains a complete example that demonstrates how to work with custom reference-counting holder types in more detail. aoflagger-v3.4.0/external/pybind11/docs/advanced/embedding.rst0000644000175000017500000002040514507760431022747 0ustar olesoles.. _embedding: Embedding the interpreter ######################### While pybind11 is mainly focused on extending Python using C++, it's also possible to do the reverse: embed the Python interpreter into a C++ program. All of the other documentation pages still apply here, so refer to them for general pybind11 usage. This section will cover a few extra things required for embedding. Getting started =============== A basic executable with an embedded interpreter can be created with just a few lines of CMake and the ``pybind11::embed`` target, as shown below. For more information, see :doc:`/compiling`. .. code-block:: cmake cmake_minimum_required(VERSION 3.4) project(example) find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)` add_executable(example main.cpp) target_link_libraries(example PRIVATE pybind11::embed) The essential structure of the ``main.cpp`` file looks like this: .. code-block:: cpp #include // everything needed for embedding namespace py = pybind11; int main() { py::scoped_interpreter guard{}; // start the interpreter and keep it alive py::print("Hello, World!"); // use the Python API } The interpreter must be initialized before using any Python API, which includes all the functions and classes in pybind11. The RAII guard class ``scoped_interpreter`` takes care of the interpreter lifetime. After the guard is destroyed, the interpreter shuts down and clears its memory. No Python functions can be called after this. Executing Python code ===================== There are a few different ways to run Python code. One option is to use ``eval``, ``exec`` or ``eval_file``, as explained in :ref:`eval`. Here is a quick example in the context of an executable with an embedded interpreter: .. code-block:: cpp #include namespace py = pybind11; int main() { py::scoped_interpreter guard{}; py::exec(R"( kwargs = dict(name="World", number=42) message = "Hello, {name}! The answer is {number}".format(**kwargs) print(message) )"); } Alternatively, similar results can be achieved using pybind11's API (see :doc:`/advanced/pycpp/index` for more details). .. code-block:: cpp #include namespace py = pybind11; using namespace py::literals; int main() { py::scoped_interpreter guard{}; auto kwargs = py::dict("name"_a="World", "number"_a=42); auto message = "Hello, {name}! The answer is {number}"_s.format(**kwargs); py::print(message); } The two approaches can also be combined: .. code-block:: cpp #include #include namespace py = pybind11; using namespace py::literals; int main() { py::scoped_interpreter guard{}; auto locals = py::dict("name"_a="World", "number"_a=42); py::exec(R"( message = "Hello, {name}! The answer is {number}".format(**locals()) )", py::globals(), locals); auto message = locals["message"].cast(); std::cout << message; } Importing modules ================= Python modules can be imported using ``module_::import()``: .. code-block:: cpp py::module_ sys = py::module_::import("sys"); py::print(sys.attr("path")); For convenience, the current working directory is included in ``sys.path`` when embedding the interpreter. This makes it easy to import local Python files: .. code-block:: python """calc.py located in the working directory""" def add(i, j): return i + j .. code-block:: cpp py::module_ calc = py::module_::import("calc"); py::object result = calc.attr("add")(1, 2); int n = result.cast(); assert(n == 3); Modules can be reloaded using ``module_::reload()`` if the source is modified e.g. by an external process. This can be useful in scenarios where the application imports a user defined data processing script which needs to be updated after changes by the user. Note that this function does not reload modules recursively. .. _embedding_modules: Adding embedded modules ======================= Embedded binary modules can be added using the ``PYBIND11_EMBEDDED_MODULE`` macro. Note that the definition must be placed at global scope. They can be imported like any other module. .. code-block:: cpp #include namespace py = pybind11; PYBIND11_EMBEDDED_MODULE(fast_calc, m) { // `m` is a `py::module_` which is used to bind functions and classes m.def("add", [](int i, int j) { return i + j; }); } int main() { py::scoped_interpreter guard{}; auto fast_calc = py::module_::import("fast_calc"); auto result = fast_calc.attr("add")(1, 2).cast(); assert(result == 3); } Unlike extension modules where only a single binary module can be created, on the embedded side an unlimited number of modules can be added using multiple ``PYBIND11_EMBEDDED_MODULE`` definitions (as long as they have unique names). These modules are added to Python's list of builtins, so they can also be imported in pure Python files loaded by the interpreter. Everything interacts naturally: .. code-block:: python """py_module.py located in the working directory""" import cpp_module a = cpp_module.a b = a + 1 .. code-block:: cpp #include namespace py = pybind11; PYBIND11_EMBEDDED_MODULE(cpp_module, m) { m.attr("a") = 1; } int main() { py::scoped_interpreter guard{}; auto py_module = py::module_::import("py_module"); auto locals = py::dict("fmt"_a="{} + {} = {}", **py_module.attr("__dict__")); assert(locals["a"].cast() == 1); assert(locals["b"].cast() == 2); py::exec(R"( c = a + b message = fmt.format(a, b, c) )", py::globals(), locals); assert(locals["c"].cast() == 3); assert(locals["message"].cast() == "1 + 2 = 3"); } Interpreter lifetime ==================== The Python interpreter shuts down when ``scoped_interpreter`` is destroyed. After this, creating a new instance will restart the interpreter. Alternatively, the ``initialize_interpreter`` / ``finalize_interpreter`` pair of functions can be used to directly set the state at any time. Modules created with pybind11 can be safely re-initialized after the interpreter has been restarted. However, this may not apply to third-party extension modules. The issue is that Python itself cannot completely unload extension modules and there are several caveats with regard to interpreter restarting. In short, not all memory may be freed, either due to Python reference cycles or user-created global data. All the details can be found in the CPython documentation. .. warning:: Creating two concurrent ``scoped_interpreter`` guards is a fatal error. So is calling ``initialize_interpreter`` for a second time after the interpreter has already been initialized. Do not use the raw CPython API functions ``Py_Initialize`` and ``Py_Finalize`` as these do not properly handle the lifetime of pybind11's internal data. Sub-interpreter support ======================= Creating multiple copies of ``scoped_interpreter`` is not possible because it represents the main Python interpreter. Sub-interpreters are something different and they do permit the existence of multiple interpreters. This is an advanced feature of the CPython API and should be handled with care. pybind11 does not currently offer a C++ interface for sub-interpreters, so refer to the CPython documentation for all the details regarding this feature. We'll just mention a couple of caveats the sub-interpreters support in pybind11: 1. Sub-interpreters will not receive independent copies of embedded modules. Instead, these are shared and modifications in one interpreter may be reflected in another. 2. Managing multiple threads, multiple interpreters and the GIL can be challenging and there are several caveats here, even within the pure CPython API (please refer to the Python docs for details). As for pybind11, keep in mind that ``gil_scoped_release`` and ``gil_scoped_acquire`` do not take sub-interpreters into account. aoflagger-v3.4.0/external/pybind11/docs/advanced/functions.rst0000644000175000017500000006415114507760431023047 0ustar olesolesFunctions ######### Before proceeding with this section, make sure that you are already familiar with the basics of binding functions and classes, as explained in :doc:`/basics` and :doc:`/classes`. The following guide is applicable to both free and member functions, i.e. *methods* in Python. .. _return_value_policies: Return value policies ===================== Python and C++ use fundamentally different ways of managing the memory and lifetime of objects managed by them. This can lead to issues when creating bindings for functions that return a non-trivial type. Just by looking at the type information, it is not clear whether Python should take charge of the returned value and eventually free its resources, or if this is handled on the C++ side. For this reason, pybind11 provides a several *return value policy* annotations that can be passed to the :func:`module_::def` and :func:`class_::def` functions. The default policy is :enum:`return_value_policy::automatic`. Return value policies are tricky, and it's very important to get them right. Just to illustrate what can go wrong, consider the following simple example: .. code-block:: cpp /* Function declaration */ Data *get_data() { return _data; /* (pointer to a static data structure) */ } ... /* Binding code */ m.def("get_data", &get_data); // <-- KABOOM, will cause crash when called from Python What's going on here? When ``get_data()`` is called from Python, the return value (a native C++ type) must be wrapped to turn it into a usable Python type. In this case, the default return value policy (:enum:`return_value_policy::automatic`) causes pybind11 to assume ownership of the static ``_data`` instance. When Python's garbage collector eventually deletes the Python wrapper, pybind11 will also attempt to delete the C++ instance (via ``operator delete()``) due to the implied ownership. At this point, the entire application will come crashing down, though errors could also be more subtle and involve silent data corruption. In the above example, the policy :enum:`return_value_policy::reference` should have been specified so that the global data instance is only *referenced* without any implied transfer of ownership, i.e.: .. code-block:: cpp m.def("get_data", &get_data, py::return_value_policy::reference); On the other hand, this is not the right policy for many other situations, where ignoring ownership could lead to resource leaks. As a developer using pybind11, it's important to be familiar with the different return value policies, including which situation calls for which one of them. The following table provides an overview of available policies: .. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| +--------------------------------------------------+----------------------------------------------------------------------------+ | Return value policy | Description | +==================================================+============================================================================+ | :enum:`return_value_policy::take_ownership` | Reference an existing object (i.e. do not create a new copy) and take | | | ownership. Python will call the destructor and delete operator when the | | | object's reference count reaches zero. Undefined behavior ensues when the | | | C++ side does the same, or when the data was not dynamically allocated. | +--------------------------------------------------+----------------------------------------------------------------------------+ | :enum:`return_value_policy::copy` | Create a new copy of the returned object, which will be owned by Python. | | | This policy is comparably safe because the lifetimes of the two instances | | | are decoupled. | +--------------------------------------------------+----------------------------------------------------------------------------+ | :enum:`return_value_policy::move` | Use ``std::move`` to move the return value contents into a new instance | | | that will be owned by Python. This policy is comparably safe because the | | | lifetimes of the two instances (move source and destination) are decoupled.| +--------------------------------------------------+----------------------------------------------------------------------------+ | :enum:`return_value_policy::reference` | Reference an existing object, but do not take ownership. The C++ side is | | | responsible for managing the object's lifetime and deallocating it when | | | it is no longer used. Warning: undefined behavior will ensue when the C++ | | | side deletes an object that is still referenced and used by Python. | +--------------------------------------------------+----------------------------------------------------------------------------+ | :enum:`return_value_policy::reference_internal` | Indicates that the lifetime of the return value is tied to the lifetime | | | of a parent object, namely the implicit ``this``, or ``self`` argument of | | | the called method or property. Internally, this policy works just like | | | :enum:`return_value_policy::reference` but additionally applies a | | | ``keep_alive<0, 1>`` *call policy* (described in the next section) that | | | prevents the parent object from being garbage collected as long as the | | | return value is referenced by Python. This is the default policy for | | | property getters created via ``def_property``, ``def_readwrite``, etc. | +--------------------------------------------------+----------------------------------------------------------------------------+ | :enum:`return_value_policy::automatic` | This policy falls back to the policy | | | :enum:`return_value_policy::take_ownership` when the return value is a | | | pointer. Otherwise, it uses :enum:`return_value_policy::move` or | | | :enum:`return_value_policy::copy` for rvalue and lvalue references, | | | respectively. See above for a description of what all of these different | | | policies do. This is the default policy for ``py::class_``-wrapped types. | +--------------------------------------------------+----------------------------------------------------------------------------+ | :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the | | | return value is a pointer. This is the default conversion policy for | | | function arguments when calling Python functions manually from C++ code | | | (i.e. via ``handle::operator()``) and the casters in ``pybind11/stl.h``. | | | You probably won't need to use this explicitly. | +--------------------------------------------------+----------------------------------------------------------------------------+ Return value policies can also be applied to properties: .. code-block:: cpp class_(m, "MyClass") .def_property("data", &MyClass::getData, &MyClass::setData, py::return_value_policy::copy); Technically, the code above applies the policy to both the getter and the setter function, however, the setter doesn't really care about *return* value policies which makes this a convenient terse syntax. Alternatively, targeted arguments can be passed through the :class:`cpp_function` constructor: .. code-block:: cpp class_(m, "MyClass") .def_property("data", py::cpp_function(&MyClass::getData, py::return_value_policy::copy), py::cpp_function(&MyClass::setData) ); .. warning:: Code with invalid return value policies might access uninitialized memory or free data structures multiple times, which can lead to hard-to-debug non-determinism and segmentation faults, hence it is worth spending the time to understand all the different options in the table above. .. note:: One important aspect of the above policies is that they only apply to instances which pybind11 has *not* seen before, in which case the policy clarifies essential questions about the return value's lifetime and ownership. When pybind11 knows the instance already (as identified by its type and address in memory), it will return the existing Python object wrapper rather than creating a new copy. .. note:: The next section on :ref:`call_policies` discusses *call policies* that can be specified *in addition* to a return value policy from the list above. Call policies indicate reference relationships that can involve both return values and parameters of functions. .. note:: As an alternative to elaborate call policies and lifetime management logic, consider using smart pointers (see the section on :ref:`smart_pointers` for details). Smart pointers can tell whether an object is still referenced from C++ or Python, which generally eliminates the kinds of inconsistencies that can lead to crashes or undefined behavior. For functions returning smart pointers, it is not necessary to specify a return value policy. .. _call_policies: Additional call policies ======================== In addition to the above return value policies, further *call policies* can be specified to indicate dependencies between parameters or ensure a certain state for the function call. Keep alive ---------- In general, this policy is required when the C++ object is any kind of container and another object is being added to the container. ``keep_alive`` indicates that the argument with index ``Patient`` should be kept alive at least until the argument with index ``Nurse`` is freed by the garbage collector. Argument indices start at one, while zero refers to the return value. For methods, index ``1`` refers to the implicit ``this`` pointer, while regular arguments begin at index ``2``. Arbitrarily many call policies can be specified. When a ``Nurse`` with value ``None`` is detected at runtime, the call policy does nothing. When the nurse is not a pybind11-registered type, the implementation internally relies on the ability to create a *weak reference* to the nurse object. When the nurse object is not a pybind11-registered type and does not support weak references, an exception will be thrown. If you use an incorrect argument index, you will get a ``RuntimeError`` saying ``Could not activate keep_alive!``. You should review the indices you're using. Consider the following example: here, the binding code for a list append operation ties the lifetime of the newly added element to the underlying container: .. code-block:: cpp py::class_(m, "List") .def("append", &List::append, py::keep_alive<1, 2>()); For consistency, the argument indexing is identical for constructors. Index ``1`` still refers to the implicit ``this`` pointer, i.e. the object which is being constructed. Index ``0`` refers to the return type which is presumed to be ``void`` when a constructor is viewed like a function. The following example ties the lifetime of the constructor element to the constructed object: .. code-block:: cpp py::class_(m, "Nurse") .def(py::init(), py::keep_alive<1, 2>()); .. note:: ``keep_alive`` is analogous to the ``with_custodian_and_ward`` (if Nurse, Patient != 0) and ``with_custodian_and_ward_postcall`` (if Nurse/Patient == 0) policies from Boost.Python. Call guard ---------- The ``call_guard`` policy allows any scope guard type ``T`` to be placed around the function call. For example, this definition: .. code-block:: cpp m.def("foo", foo, py::call_guard()); is equivalent to the following pseudocode: .. code-block:: cpp m.def("foo", [](args...) { T scope_guard; return foo(args...); // forwarded arguments }); The only requirement is that ``T`` is default-constructible, but otherwise any scope guard will work. This is very useful in combination with ``gil_scoped_release``. See :ref:`gil`. Multiple guards can also be specified as ``py::call_guard``. The constructor order is left to right and destruction happens in reverse. .. seealso:: The file :file:`tests/test_call_policies.cpp` contains a complete example that demonstrates using `keep_alive` and `call_guard` in more detail. .. _python_objects_as_args: Python objects as arguments =========================== pybind11 exposes all major Python types using thin C++ wrapper classes. These wrapper classes can also be used as parameters of functions in bindings, which makes it possible to directly work with native Python types on the C++ side. For instance, the following statement iterates over a Python ``dict``: .. code-block:: cpp void print_dict(const py::dict& dict) { /* Easily interact with Python types */ for (auto item : dict) std::cout << "key=" << std::string(py::str(item.first)) << ", " << "value=" << std::string(py::str(item.second)) << std::endl; } It can be exported: .. code-block:: cpp m.def("print_dict", &print_dict); And used in Python as usual: .. code-block:: pycon >>> print_dict({"foo": 123, "bar": "hello"}) key=foo, value=123 key=bar, value=hello For more information on using Python objects in C++, see :doc:`/advanced/pycpp/index`. Accepting \*args and \*\*kwargs =============================== Python provides a useful mechanism to define functions that accept arbitrary numbers of arguments and keyword arguments: .. code-block:: python def generic(*args, **kwargs): ... # do something with args and kwargs Such functions can also be created using pybind11: .. code-block:: cpp void generic(py::args args, const py::kwargs& kwargs) { /// .. do something with args if (kwargs) /// .. do something with kwargs } /// Binding code m.def("generic", &generic); The class ``py::args`` derives from ``py::tuple`` and ``py::kwargs`` derives from ``py::dict``. You may also use just one or the other, and may combine these with other arguments. Note, however, that ``py::kwargs`` must always be the last argument of the function, and ``py::args`` implies that any further arguments are keyword-only (see :ref:`keyword_only_arguments`). Please refer to the other examples for details on how to iterate over these, and on how to cast their entries into C++ objects. A demonstration is also available in ``tests/test_kwargs_and_defaults.cpp``. .. note:: When combining \*args or \*\*kwargs with :ref:`keyword_args` you should *not* include ``py::arg`` tags for the ``py::args`` and ``py::kwargs`` arguments. Default arguments revisited =========================== The section on :ref:`default_args` previously discussed basic usage of default arguments using pybind11. One noteworthy aspect of their implementation is that default arguments are converted to Python objects right at declaration time. Consider the following example: .. code-block:: cpp py::class_("MyClass") .def("myFunction", py::arg("arg") = SomeType(123)); In this case, pybind11 must already be set up to deal with values of the type ``SomeType`` (via a prior instantiation of ``py::class_``), or an exception will be thrown. Another aspect worth highlighting is that the "preview" of the default argument in the function signature is generated using the object's ``__repr__`` method. If not available, the signature may not be very helpful, e.g.: .. code-block:: pycon FUNCTIONS ... | myFunction(...) | Signature : (MyClass, arg : SomeType = ) -> NoneType ... The first way of addressing this is by defining ``SomeType.__repr__``. Alternatively, it is possible to specify the human-readable preview of the default argument manually using the ``arg_v`` notation: .. code-block:: cpp py::class_("MyClass") .def("myFunction", py::arg_v("arg", SomeType(123), "SomeType(123)")); Sometimes it may be necessary to pass a null pointer value as a default argument. In this case, remember to cast it to the underlying type in question, like so: .. code-block:: cpp py::class_("MyClass") .def("myFunction", py::arg("arg") = static_cast(nullptr)); .. _keyword_only_arguments: Keyword-only arguments ====================== Python implements keyword-only arguments by specifying an unnamed ``*`` argument in a function definition: .. code-block:: python def f(a, *, b): # a can be positional or via keyword; b must be via keyword pass f(a=1, b=2) # good f(b=2, a=1) # good f(1, b=2) # good f(1, 2) # TypeError: f() takes 1 positional argument but 2 were given Pybind11 provides a ``py::kw_only`` object that allows you to implement the same behaviour by specifying the object between positional and keyword-only argument annotations when registering the function: .. code-block:: cpp m.def("f", [](int a, int b) { /* ... */ }, py::arg("a"), py::kw_only(), py::arg("b")); .. versionadded:: 2.6 A ``py::args`` argument implies that any following arguments are keyword-only, as if ``py::kw_only()`` had been specified in the same relative location of the argument list as the ``py::args`` argument. The ``py::kw_only()`` may be included to be explicit about this, but is not required. .. versionchanged:: 2.9 This can now be combined with ``py::args``. Before, ``py::args`` could only occur at the end of the argument list, or immediately before a ``py::kwargs`` argument at the end. Positional-only arguments ========================= Python 3.8 introduced a new positional-only argument syntax, using ``/`` in the function definition (note that this has been a convention for CPython positional arguments, such as in ``pow()``, since Python 2). You can do the same thing in any version of Python using ``py::pos_only()``: .. code-block:: cpp m.def("f", [](int a, int b) { /* ... */ }, py::arg("a"), py::pos_only(), py::arg("b")); You now cannot give argument ``a`` by keyword. This can be combined with keyword-only arguments, as well. .. versionadded:: 2.6 .. _nonconverting_arguments: Non-converting arguments ======================== Certain argument types may support conversion from one type to another. Some examples of conversions are: * :ref:`implicit_conversions` declared using ``py::implicitly_convertible()`` * Calling a method accepting a double with an integer argument * Calling a ``std::complex`` argument with a non-complex python type (for example, with a float). (Requires the optional ``pybind11/complex.h`` header). * Calling a function taking an Eigen matrix reference with a numpy array of the wrong type or of an incompatible data layout. (Requires the optional ``pybind11/eigen.h`` header). This behaviour is sometimes undesirable: the binding code may prefer to raise an error rather than convert the argument. This behaviour can be obtained through ``py::arg`` by calling the ``.noconvert()`` method of the ``py::arg`` object, such as: .. code-block:: cpp m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); Attempting the call the second function (the one without ``.noconvert()``) with an integer will succeed, but attempting to call the ``.noconvert()`` version will fail with a ``TypeError``: .. code-block:: pycon >>> floats_preferred(4) 2.0 >>> floats_only(4) Traceback (most recent call last): File "", line 1, in TypeError: floats_only(): incompatible function arguments. The following argument types are supported: 1. (f: float) -> float Invoked with: 4 You may, of course, combine this with the :var:`_a` shorthand notation (see :ref:`keyword_args`) and/or :ref:`default_args`. It is also permitted to omit the argument name by using the ``py::arg()`` constructor without an argument name, i.e. by specifying ``py::arg().noconvert()``. .. note:: When specifying ``py::arg`` options it is necessary to provide the same number of options as the bound function has arguments. Thus if you want to enable no-convert behaviour for just one of several arguments, you will need to specify a ``py::arg()`` annotation for each argument with the no-convert argument modified to ``py::arg().noconvert()``. .. _none_arguments: Allow/Prohibiting None arguments ================================ When a C++ type registered with :class:`py::class_` is passed as an argument to a function taking the instance as pointer or shared holder (e.g. ``shared_ptr`` or a custom, copyable holder as described in :ref:`smart_pointers`), pybind allows ``None`` to be passed from Python which results in calling the C++ function with ``nullptr`` (or an empty holder) for the argument. To explicitly enable or disable this behaviour, using the ``.none`` method of the :class:`py::arg` object: .. code-block:: cpp py::class_(m, "Dog").def(py::init<>()); py::class_(m, "Cat").def(py::init<>()); m.def("bark", [](Dog *dog) -> std::string { if (dog) return "woof!"; /* Called with a Dog instance */ else return "(no dog)"; /* Called with None, dog == nullptr */ }, py::arg("dog").none(true)); m.def("meow", [](Cat *cat) -> std::string { // Can't be called with None argument return "meow"; }, py::arg("cat").none(false)); With the above, the Python call ``bark(None)`` will return the string ``"(no dog)"``, while attempting to call ``meow(None)`` will raise a ``TypeError``: .. code-block:: pycon >>> from animals import Dog, Cat, bark, meow >>> bark(Dog()) 'woof!' >>> meow(Cat()) 'meow' >>> bark(None) '(no dog)' >>> meow(None) Traceback (most recent call last): File "", line 1, in TypeError: meow(): incompatible function arguments. The following argument types are supported: 1. (cat: animals.Cat) -> str Invoked with: None The default behaviour when the tag is unspecified is to allow ``None``. .. note:: Even when ``.none(true)`` is specified for an argument, ``None`` will be converted to a ``nullptr`` *only* for custom and :ref:`opaque ` types. Pointers to built-in types (``double *``, ``int *``, ...) and STL types (``std::vector *``, ...; if ``pybind11/stl.h`` is included) are copied when converted to C++ (see :doc:`/advanced/cast/overview`) and will not allow ``None`` as argument. To pass optional argument of these copied types consider using ``std::optional`` .. _overload_resolution: Overload resolution order ========================= When a function or method with multiple overloads is called from Python, pybind11 determines which overload to call in two passes. The first pass attempts to call each overload without allowing argument conversion (as if every argument had been specified as ``py::arg().noconvert()`` as described above). If no overload succeeds in the no-conversion first pass, a second pass is attempted in which argument conversion is allowed (except where prohibited via an explicit ``py::arg().noconvert()`` attribute in the function definition). If the second pass also fails a ``TypeError`` is raised. Within each pass, overloads are tried in the order they were registered with pybind11. If the ``py::prepend()`` tag is added to the definition, a function can be placed at the beginning of the overload sequence instead, allowing user overloads to proceed built in functions. What this means in practice is that pybind11 will prefer any overload that does not require conversion of arguments to an overload that does, but otherwise prefers earlier-defined overloads to later-defined ones. .. note:: pybind11 does *not* further prioritize based on the number/pattern of overloaded arguments. That is, pybind11 does not prioritize a function requiring one conversion over one requiring three, but only prioritizes overloads requiring no conversion at all to overloads that require conversion of at least one argument. .. versionadded:: 2.6 The ``py::prepend()`` tag. Binding functions with template parameters ========================================== You can bind functions that have template parameters. Here's a function: .. code-block:: cpp template void set(T t); C++ templates cannot be instantiated at runtime, so you cannot bind the non-instantiated function: .. code-block:: cpp // BROKEN (this will not compile) m.def("set", &set); You must bind each instantiated function template separately. You may bind each instantiation with the same name, which will be treated the same as an overloaded function: .. code-block:: cpp m.def("set", &set); m.def("set", &set); Sometimes it's more clear to bind them with separate names, which is also an option: .. code-block:: cpp m.def("setInt", &set); m.def("setString", &set); aoflagger-v3.4.0/external/pybind11/docs/advanced/pycpp/0000755000175000017500000000000014516225226021427 5ustar olesolesaoflagger-v3.4.0/external/pybind11/docs/advanced/pycpp/utilities.rst0000644000175000017500000001311614507760431024200 0ustar olesolesUtilities ######### Using Python's print function in C++ ==================================== The usual way to write output in C++ is using ``std::cout`` while in Python one would use ``print``. Since these methods use different buffers, mixing them can lead to output order issues. To resolve this, pybind11 modules can use the :func:`py::print` function which writes to Python's ``sys.stdout`` for consistency. Python's ``print`` function is replicated in the C++ API including optional keyword arguments ``sep``, ``end``, ``file``, ``flush``. Everything works as expected in Python: .. code-block:: cpp py::print(1, 2.0, "three"); // 1 2.0 three py::print(1, 2.0, "three", "sep"_a="-"); // 1-2.0-three auto args = py::make_tuple("unpacked", true); py::print("->", *args, "end"_a="<-"); // -> unpacked True <- .. _ostream_redirect: Capturing standard output from ostream ====================================== Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print, but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr`` redirection. Replacing a library's printing with ``py::print `` may not be feasible. This can be fixed using a guard around the library function that redirects output to the corresponding Python streams: .. code-block:: cpp #include ... // Add a scoped redirect for your noisy code m.def("noisy_func", []() { py::scoped_ostream_redirect stream( std::cout, // std::ostream& py::module_::import("sys").attr("stdout") // Python output ); call_noisy_func(); }); .. warning:: The implementation in ``pybind11/iostream.h`` is NOT thread safe. Multiple threads writing to a redirected ostream concurrently cause data races and potentially buffer overflows. Therefore it is currently a requirement that all (possibly) concurrent redirected ostream writes are protected by a mutex. #HelpAppreciated: Work on iostream.h thread safety. For more background see the discussions under `PR #2982 `_ and `PR #2995 `_. This method respects flushes on the output streams and will flush if needed when the scoped guard is destroyed. This allows the output to be redirected in real time, such as to a Jupyter notebook. The two arguments, the C++ stream and the Python output, are optional, and default to standard output if not given. An extra type, ``py::scoped_estream_redirect ``, is identical except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with ``py::call_guard``, which allows multiple items, but uses the default constructor: .. code-block:: cpp // Alternative: Call single function using call guard m.def("noisy_func", &call_noisy_function, py::call_guard()); The redirection can also be done in Python with the addition of a context manager, using the ``py::add_ostream_redirect() `` function: .. code-block:: cpp py::add_ostream_redirect(m, "ostream_redirect"); The name in Python defaults to ``ostream_redirect`` if no name is passed. This creates the following context manager in Python: .. code-block:: python with ostream_redirect(stdout=True, stderr=True): noisy_function() It defaults to redirecting both streams, though you can use the keyword arguments to disable one of the streams if needed. .. note:: The above methods will not redirect C-level output to file descriptors, such as ``fprintf``. For those cases, you'll need to redirect the file descriptors either directly in C or with Python's ``os.dup2`` function in an operating-system dependent way. .. _eval: Evaluating Python expressions from strings and files ==================================================== pybind11 provides the ``eval``, ``exec`` and ``eval_file`` functions to evaluate Python expressions and statements. The following example illustrates how they can be used. .. code-block:: cpp // At beginning of file #include ... // Evaluate in scope of main module py::object scope = py::module_::import("__main__").attr("__dict__"); // Evaluate an isolated expression int result = py::eval("my_variable + 10", scope).cast(); // Evaluate a sequence of statements py::exec( "print('Hello')\n" "print('world!');", scope); // Evaluate the statements in an separate Python file on disk py::eval_file("script.py", scope); C++11 raw string literals are also supported and quite handy for this purpose. The only requirement is that the first statement must be on a new line following the raw string delimiter ``R"(``, ensuring all lines have common leading indent: .. code-block:: cpp py::exec(R"( x = get_answer() if x == 42: print('Hello World!') else: print('Bye!') )", scope ); .. note:: `eval` and `eval_file` accept a template parameter that describes how the string/file should be interpreted. Possible choices include ``eval_expr`` (isolated expression), ``eval_single_statement`` (a single statement, return value is always ``none``), and ``eval_statements`` (sequence of statements, return value is always ``none``). `eval` defaults to ``eval_expr``, `eval_file` defaults to ``eval_statements`` and `exec` is just a shortcut for ``eval``. aoflagger-v3.4.0/external/pybind11/docs/advanced/pycpp/object.rst0000644000175000017500000002150614507760431023435 0ustar olesolesPython types ############ .. _wrappers: Available wrappers ================== All major Python types are available as thin C++ wrapper classes. These can also be used as function parameters -- see :ref:`python_objects_as_args`. Available types include :class:`handle`, :class:`object`, :class:`bool_`, :class:`int_`, :class:`float_`, :class:`str`, :class:`bytes`, :class:`tuple`, :class:`list`, :class:`dict`, :class:`slice`, :class:`none`, :class:`capsule`, :class:`iterable`, :class:`iterator`, :class:`function`, :class:`buffer`, :class:`array`, and :class:`array_t`. .. warning:: Be sure to review the :ref:`pytypes_gotchas` before using this heavily in your C++ API. .. _instantiating_compound_types: Instantiating compound Python types from C++ ============================================ Dictionaries can be initialized in the :class:`dict` constructor: .. code-block:: cpp using namespace pybind11::literals; // to bring in the `_a` literal py::dict d("spam"_a=py::none(), "eggs"_a=42); A tuple of python objects can be instantiated using :func:`py::make_tuple`: .. code-block:: cpp py::tuple tup = py::make_tuple(42, py::none(), "spam"); Each element is converted to a supported Python type. A `simple namespace`_ can be instantiated using .. code-block:: cpp using namespace pybind11::literals; // to bring in the `_a` literal py::object SimpleNamespace = py::module_::import("types").attr("SimpleNamespace"); py::object ns = SimpleNamespace("spam"_a=py::none(), "eggs"_a=42); Attributes on a namespace can be modified with the :func:`py::delattr`, :func:`py::getattr`, and :func:`py::setattr` functions. Simple namespaces can be useful as lightweight stand-ins for class instances. .. _simple namespace: https://docs.python.org/3/library/types.html#types.SimpleNamespace .. _casting_back_and_forth: Casting back and forth ====================== In this kind of mixed code, it is often necessary to convert arbitrary C++ types to Python, which can be done using :func:`py::cast`: .. code-block:: cpp MyClass *cls = ...; py::object obj = py::cast(cls); The reverse direction uses the following syntax: .. code-block:: cpp py::object obj = ...; MyClass *cls = obj.cast(); When conversion fails, both directions throw the exception :class:`cast_error`. .. _python_libs: Accessing Python libraries from C++ =================================== It is also possible to import objects defined in the Python standard library or available in the current Python environment (``sys.path``) and work with these in C++. This example obtains a reference to the Python ``Decimal`` class. .. code-block:: cpp // Equivalent to "from decimal import Decimal" py::object Decimal = py::module_::import("decimal").attr("Decimal"); .. code-block:: cpp // Try to import scipy py::object scipy = py::module_::import("scipy"); return scipy.attr("__version__"); .. _calling_python_functions: Calling Python functions ======================== It is also possible to call Python classes, functions and methods via ``operator()``. .. code-block:: cpp // Construct a Python object of class Decimal py::object pi = Decimal("3.14159"); .. code-block:: cpp // Use Python to make our directories py::object os = py::module_::import("os"); py::object makedirs = os.attr("makedirs"); makedirs("/tmp/path/to/somewhere"); One can convert the result obtained from Python to a pure C++ version if a ``py::class_`` or type conversion is defined. .. code-block:: cpp py::function f = <...>; py::object result_py = f(1234, "hello", some_instance); MyClass &result = result_py.cast(); .. _calling_python_methods: Calling Python methods ======================== To call an object's method, one can again use ``.attr`` to obtain access to the Python method. .. code-block:: cpp // Calculate e^Ï€ in decimal py::object exp_pi = pi.attr("exp")(); py::print(py::str(exp_pi)); In the example above ``pi.attr("exp")`` is a *bound method*: it will always call the method for that same instance of the class. Alternately one can create an *unbound method* via the Python class (instead of instance) and pass the ``self`` object explicitly, followed by other arguments. .. code-block:: cpp py::object decimal_exp = Decimal.attr("exp"); // Compute the e^n for n=0..4 for (int n = 0; n < 5; n++) { py::print(decimal_exp(Decimal(n)); } Keyword arguments ================= Keyword arguments are also supported. In Python, there is the usual call syntax: .. code-block:: python def f(number, say, to): ... # function code f(1234, say="hello", to=some_instance) # keyword call in Python In C++, the same call can be made using: .. code-block:: cpp using namespace pybind11::literals; // to bring in the `_a` literal f(1234, "say"_a="hello", "to"_a=some_instance); // keyword call in C++ Unpacking arguments =================== Unpacking of ``*args`` and ``**kwargs`` is also possible and can be mixed with other arguments: .. code-block:: cpp // * unpacking py::tuple args = py::make_tuple(1234, "hello", some_instance); f(*args); // ** unpacking py::dict kwargs = py::dict("number"_a=1234, "say"_a="hello", "to"_a=some_instance); f(**kwargs); // mixed keywords, * and ** unpacking py::tuple args = py::make_tuple(1234); py::dict kwargs = py::dict("to"_a=some_instance); f(*args, "say"_a="hello", **kwargs); Generalized unpacking according to PEP448_ is also supported: .. code-block:: cpp py::dict kwargs1 = py::dict("number"_a=1234); py::dict kwargs2 = py::dict("to"_a=some_instance); f(**kwargs1, "say"_a="hello", **kwargs2); .. seealso:: The file :file:`tests/test_pytypes.cpp` contains a complete example that demonstrates passing native Python types in more detail. The file :file:`tests/test_callbacks.cpp` presents a few examples of calling Python functions from C++, including keywords arguments and unpacking. .. _PEP448: https://www.python.org/dev/peps/pep-0448/ .. _implicit_casting: Implicit casting ================ When using the C++ interface for Python types, or calling Python functions, objects of type :class:`object` are returned. It is possible to invoke implicit conversions to subclasses like :class:`dict`. The same holds for the proxy objects returned by ``operator[]`` or ``obj.attr()``. Casting to subtypes improves code readability and allows values to be passed to C++ functions that require a specific subtype rather than a generic :class:`object`. .. code-block:: cpp #include using namespace pybind11::literals; py::module_ os = py::module_::import("os"); py::module_ path = py::module_::import("os.path"); // like 'import os.path as path' py::module_ np = py::module_::import("numpy"); // like 'import numpy as np' py::str curdir_abs = path.attr("abspath")(path.attr("curdir")); py::print(py::str("Current directory: ") + curdir_abs); py::dict environ = os.attr("environ"); py::print(environ["HOME"]); py::array_t arr = np.attr("ones")(3, "dtype"_a="float32"); py::print(py::repr(arr + py::int_(1))); These implicit conversions are available for subclasses of :class:`object`; there is no need to call ``obj.cast()`` explicitly as for custom classes, see :ref:`casting_back_and_forth`. .. note:: If a trivial conversion via move constructor is not possible, both implicit and explicit casting (calling ``obj.cast()``) will attempt a "rich" conversion. For instance, ``py::list env = os.attr("environ");`` will succeed and is equivalent to the Python code ``env = list(os.environ)`` that produces a list of the dict keys. .. TODO: Adapt text once PR #2349 has landed Handling exceptions =================== Python exceptions from wrapper classes will be thrown as a ``py::error_already_set``. See :ref:`Handling exceptions from Python in C++ ` for more information on handling exceptions raised when calling C++ wrapper classes. .. _pytypes_gotchas: Gotchas ======= Default-Constructed Wrappers ---------------------------- When a wrapper type is default-constructed, it is **not** a valid Python object (i.e. it is not ``py::none()``). It is simply the same as ``PyObject*`` null pointer. To check for this, use ``static_cast(my_wrapper)``. Assigning py::none() to wrappers -------------------------------- You may be tempted to use types like ``py::str`` and ``py::dict`` in C++ signatures (either pure C++, or in bound signatures), and assign them default values of ``py::none()``. However, in a best case scenario, it will fail fast because ``None`` is not convertible to that type (e.g. ``py::dict``), or in a worse case scenario, it will silently work but corrupt the types you want to work with (e.g. ``py::str(py::none())`` will yield ``"None"`` in Python). aoflagger-v3.4.0/external/pybind11/docs/advanced/pycpp/numpy.rst0000644000175000017500000004141114507760431023334 0ustar olesoles.. _numpy: NumPy ##### Buffer protocol =============== Python supports an extremely general and convenient approach for exchanging data between plugin libraries. Types can expose a buffer view [#f2]_, which provides fast direct access to the raw internal data representation. Suppose we want to bind the following simplistic Matrix class: .. code-block:: cpp class Matrix { public: Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) { m_data = new float[rows*cols]; } float *data() { return m_data; } size_t rows() const { return m_rows; } size_t cols() const { return m_cols; } private: size_t m_rows, m_cols; float *m_data; }; The following binding code exposes the ``Matrix`` contents as a buffer object, making it possible to cast Matrices into NumPy arrays. It is even possible to completely avoid copy operations with Python expressions like ``np.array(matrix_instance, copy = False)``. .. code-block:: cpp py::class_(m, "Matrix", py::buffer_protocol()) .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( m.data(), /* Pointer to buffer */ sizeof(float), /* Size of one scalar */ py::format_descriptor::format(), /* Python struct-style format descriptor */ 2, /* Number of dimensions */ { m.rows(), m.cols() }, /* Buffer dimensions */ { sizeof(float) * m.cols(), /* Strides (in bytes) for each index */ sizeof(float) } ); }); Supporting the buffer protocol in a new type involves specifying the special ``py::buffer_protocol()`` tag in the ``py::class_`` constructor and calling the ``def_buffer()`` method with a lambda function that creates a ``py::buffer_info`` description record on demand describing a given matrix instance. The contents of ``py::buffer_info`` mirror the Python buffer protocol specification. .. code-block:: cpp struct buffer_info { void *ptr; py::ssize_t itemsize; std::string format; py::ssize_t ndim; std::vector shape; std::vector strides; }; To create a C++ function that can take a Python buffer object as an argument, simply use the type ``py::buffer`` as one of its arguments. Buffers can exist in a great variety of configurations, hence some safety checks are usually necessary in the function body. Below, you can see a basic example on how to define a custom constructor for the Eigen double precision matrix (``Eigen::MatrixXd``) type, which supports initialization from compatible buffer objects (e.g. a NumPy matrix). .. code-block:: cpp /* Bind MatrixXd (or some other Eigen type) to Python */ typedef Eigen::MatrixXd Matrix; typedef Matrix::Scalar Scalar; constexpr bool rowMajor = Matrix::Flags & Eigen::RowMajorBit; py::class_(m, "Matrix", py::buffer_protocol()) .def(py::init([](py::buffer b) { typedef Eigen::Stride Strides; /* Request a buffer descriptor from Python */ py::buffer_info info = b.request(); /* Some basic validation checks ... */ if (info.format != py::format_descriptor::format()) throw std::runtime_error("Incompatible format: expected a double array!"); if (info.ndim != 2) throw std::runtime_error("Incompatible buffer dimension!"); auto strides = Strides( info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar), info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar)); auto map = Eigen::Map( static_cast(info.ptr), info.shape[0], info.shape[1], strides); return Matrix(map); })); For reference, the ``def_buffer()`` call for this Eigen data type should look as follows: .. code-block:: cpp .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( m.data(), /* Pointer to buffer */ sizeof(Scalar), /* Size of one scalar */ py::format_descriptor::format(), /* Python struct-style format descriptor */ 2, /* Number of dimensions */ { m.rows(), m.cols() }, /* Buffer dimensions */ { sizeof(Scalar) * (rowMajor ? m.cols() : 1), sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } /* Strides (in bytes) for each index */ ); }) For a much easier approach of binding Eigen types (although with some limitations), refer to the section on :doc:`/advanced/cast/eigen`. .. seealso:: The file :file:`tests/test_buffers.cpp` contains a complete example that demonstrates using the buffer protocol with pybind11 in more detail. .. [#f2] http://docs.python.org/3/c-api/buffer.html Arrays ====== By exchanging ``py::buffer`` with ``py::array`` in the above snippet, we can restrict the function so that it only accepts NumPy arrays (rather than any type of Python object satisfying the buffer protocol). In many situations, we want to define a function which only accepts a NumPy array of a certain data type. This is possible via the ``py::array_t`` template. For instance, the following function requires the argument to be a NumPy array containing double precision values. .. code-block:: cpp void f(py::array_t array); When it is invoked with a different type (e.g. an integer or a list of integers), the binding code will attempt to cast the input into a NumPy array of the requested type. This feature requires the :file:`pybind11/numpy.h` header to be included. Note that :file:`pybind11/numpy.h` does not depend on the NumPy headers, and thus can be used without declaring a build-time dependency on NumPy; NumPy>=1.7.0 is a runtime dependency. Data in NumPy arrays is not guaranteed to packed in a dense manner; furthermore, entries can be separated by arbitrary column and row strides. Sometimes, it can be useful to require a function to only accept dense arrays using either the C (row-major) or Fortran (column-major) ordering. This can be accomplished via a second template argument with values ``py::array::c_style`` or ``py::array::f_style``. .. code-block:: cpp void f(py::array_t array); The ``py::array::forcecast`` argument is the default value of the second template parameter, and it ensures that non-conforming arguments are converted into an array satisfying the specified requirements instead of trying the next function overload. There are several methods on arrays; the methods listed below under references work, as well as the following functions based on the NumPy API: - ``.dtype()`` returns the type of the contained values. - ``.strides()`` returns a pointer to the strides of the array (optionally pass an integer axis to get a number). - ``.flags()`` returns the flag settings. ``.writable()`` and ``.owndata()`` are directly available. - ``.offset_at()`` returns the offset (optionally pass indices). - ``.squeeze()`` returns a view with length-1 axes removed. - ``.view(dtype)`` returns a view of the array with a different dtype. - ``.reshape({i, j, ...})`` returns a view of the array with a different shape. ``.resize({...})`` is also available. - ``.index_at(i, j, ...)`` gets the count from the beginning to a given index. There are also several methods for getting references (described below). Structured types ================ In order for ``py::array_t`` to work with structured (record) types, we first need to register the memory layout of the type. This can be done via ``PYBIND11_NUMPY_DTYPE`` macro, called in the plugin definition code, which expects the type followed by field names: .. code-block:: cpp struct A { int x; double y; }; struct B { int z; A a; }; // ... PYBIND11_MODULE(test, m) { // ... PYBIND11_NUMPY_DTYPE(A, x, y); PYBIND11_NUMPY_DTYPE(B, z, a); /* now both A and B can be used as template arguments to py::array_t */ } The structure should consist of fundamental arithmetic types, ``std::complex``, previously registered substructures, and arrays of any of the above. Both C++ arrays and ``std::array`` are supported. While there is a static assertion to prevent many types of unsupported structures, it is still the user's responsibility to use only "plain" structures that can be safely manipulated as raw memory without violating invariants. Vectorizing functions ===================== Suppose we want to bind a function with the following signature to Python so that it can process arbitrary NumPy array arguments (vectors, matrices, general N-D arrays) in addition to its normal arguments: .. code-block:: cpp double my_func(int x, float y, double z); After including the ``pybind11/numpy.h`` header, this is extremely simple: .. code-block:: cpp m.def("vectorized_func", py::vectorize(my_func)); Invoking the function like below causes 4 calls to be made to ``my_func`` with each of the array elements. The significant advantage of this compared to solutions like ``numpy.vectorize()`` is that the loop over the elements runs entirely on the C++ side and can be crunched down into a tight, optimized loop by the compiler. The result is returned as a NumPy array of type ``numpy.dtype.float64``. .. code-block:: pycon >>> x = np.array([[1, 3], [5, 7]]) >>> y = np.array([[2, 4], [6, 8]]) >>> z = 3 >>> result = vectorized_func(x, y, z) The scalar argument ``z`` is transparently replicated 4 times. The input arrays ``x`` and ``y`` are automatically converted into the right types (they are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and ``numpy.dtype.float32``, respectively). .. note:: Only arithmetic, complex, and POD types passed by value or by ``const &`` reference are vectorized; all other arguments are passed through as-is. Functions taking rvalue reference arguments cannot be vectorized. In cases where the computation is too complicated to be reduced to ``vectorize``, it will be necessary to create and access the buffer contents manually. The following snippet contains a complete example that shows how this works (the code is somewhat contrived, since it could have been done more simply using ``vectorize``). .. code-block:: cpp #include #include namespace py = pybind11; py::array_t add_arrays(py::array_t input1, py::array_t input2) { py::buffer_info buf1 = input1.request(), buf2 = input2.request(); if (buf1.ndim != 1 || buf2.ndim != 1) throw std::runtime_error("Number of dimensions must be one"); if (buf1.size != buf2.size) throw std::runtime_error("Input shapes must match"); /* No pointer is passed, so NumPy will allocate the buffer */ auto result = py::array_t(buf1.size); py::buffer_info buf3 = result.request(); double *ptr1 = static_cast(buf1.ptr); double *ptr2 = static_cast(buf2.ptr); double *ptr3 = static_cast(buf3.ptr); for (size_t idx = 0; idx < buf1.shape[0]; idx++) ptr3[idx] = ptr1[idx] + ptr2[idx]; return result; } PYBIND11_MODULE(test, m) { m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); } .. seealso:: The file :file:`tests/test_numpy_vectorize.cpp` contains a complete example that demonstrates using :func:`vectorize` in more detail. Direct access ============= For performance reasons, particularly when dealing with very large arrays, it is often desirable to directly access array elements without internal checking of dimensions and bounds on every access when indices are known to be already valid. To avoid such checks, the ``array`` class and ``array_t`` template class offer an unchecked proxy object that can be used for this unchecked access through the ``unchecked`` and ``mutable_unchecked`` methods, where ``N`` gives the required dimensionality of the array: .. code-block:: cpp m.def("sum_3d", [](py::array_t x) { auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable double sum = 0; for (py::ssize_t i = 0; i < r.shape(0); i++) for (py::ssize_t j = 0; j < r.shape(1); j++) for (py::ssize_t k = 0; k < r.shape(2); k++) sum += r(i, j, k); return sum; }); m.def("increment_3d", [](py::array_t x) { auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false for (py::ssize_t i = 0; i < r.shape(0); i++) for (py::ssize_t j = 0; j < r.shape(1); j++) for (py::ssize_t k = 0; k < r.shape(2); k++) r(i, j, k) += 1.0; }, py::arg().noconvert()); To obtain the proxy from an ``array`` object, you must specify both the data type and number of dimensions as template arguments, such as ``auto r = myarray.mutable_unchecked()``. If the number of dimensions is not known at compile time, you can omit the dimensions template parameter (i.e. calling ``arr_t.unchecked()`` or ``arr.unchecked()``. This will give you a proxy object that works in the same way, but results in less optimizable code and thus a small efficiency loss in tight loops. Note that the returned proxy object directly references the array's data, and only reads its shape, strides, and writeable flag when constructed. You must take care to ensure that the referenced array is not destroyed or reshaped for the duration of the returned object, typically by limiting the scope of the returned instance. The returned proxy object supports some of the same methods as ``py::array`` so that it can be used as a drop-in replacement for some existing, index-checked uses of ``py::array``: - ``.ndim()`` returns the number of dimensions - ``.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to the ``const T`` or ``T`` data, respectively, at the given indices. The latter is only available to proxies obtained via ``a.mutable_unchecked()``. - ``.itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``. - ``.ndim()`` returns the number of dimensions. - ``.shape(n)`` returns the size of dimension ``n`` - ``.size()`` returns the total number of elements (i.e. the product of the shapes). - ``.nbytes()`` returns the number of bytes used by the referenced elements (i.e. ``itemsize()`` times ``size()``). .. seealso:: The file :file:`tests/test_numpy_array.cpp` contains additional examples demonstrating the use of this feature. Ellipsis ======== Python provides a convenient ``...`` ellipsis notation that is often used to slice multidimensional arrays. For instance, the following snippet extracts the middle dimensions of a tensor with the first and last index set to zero. .. code-block:: python a = ... # a NumPy array b = a[0, ..., 0] The function ``py::ellipsis()`` function can be used to perform the same operation on the C++ side: .. code-block:: cpp py::array a = /* A NumPy array */; py::array b = a[py::make_tuple(0, py::ellipsis(), 0)]; Memory view =========== For a case when we simply want to provide a direct accessor to C/C++ buffer without a concrete class object, we can return a ``memoryview`` object. Suppose we wish to expose a ``memoryview`` for 2x4 uint8_t array, we can do the following: .. code-block:: cpp const uint8_t buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; m.def("get_memoryview2d", []() { return py::memoryview::from_buffer( buffer, // buffer pointer { 2, 4 }, // shape (rows, cols) { sizeof(uint8_t) * 4, sizeof(uint8_t) } // strides in bytes ); }); This approach is meant for providing a ``memoryview`` for a C/C++ buffer not managed by Python. The user is responsible for managing the lifetime of the buffer. Using a ``memoryview`` created in this way after deleting the buffer in C++ side results in undefined behavior. We can also use ``memoryview::from_memory`` for a simple 1D contiguous buffer: .. code-block:: cpp m.def("get_memoryview1d", []() { return py::memoryview::from_memory( buffer, // buffer pointer sizeof(uint8_t) * 8 // buffer size ); }); .. versionchanged:: 2.6 ``memoryview::from_memory`` added. aoflagger-v3.4.0/external/pybind11/docs/advanced/pycpp/index.rst0000644000175000017500000000042614507760431023274 0ustar olesolesPython C++ interface #################### pybind11 exposes Python types and functions using thin C++ wrappers, which makes it possible to conveniently call Python code from C++ without resorting to Python's C API. .. toctree:: :maxdepth: 2 object numpy utilities aoflagger-v3.4.0/external/pybind11/docs/advanced/classes.rst0000644000175000017500000013526414507760431022500 0ustar olesolesClasses ####### This section presents advanced binding code for classes and it is assumed that you are already familiar with the basics from :doc:`/classes`. .. _overriding_virtuals: Overriding virtual functions in Python ====================================== Suppose that a C++ class or interface has a virtual function that we'd like to override from within Python (we'll focus on the class ``Animal``; ``Dog`` is given as a specific example of how one would do this with traditional C++ code). .. code-block:: cpp class Animal { public: virtual ~Animal() { } virtual std::string go(int n_times) = 0; }; class Dog : public Animal { public: std::string go(int n_times) override { std::string result; for (int i=0; igo(3); } Normally, the binding code for these classes would look as follows: .. code-block:: cpp PYBIND11_MODULE(example, m) { py::class_(m, "Animal") .def("go", &Animal::go); py::class_(m, "Dog") .def(py::init<>()); m.def("call_go", &call_go); } However, these bindings are impossible to extend: ``Animal`` is not constructible, and we clearly require some kind of "trampoline" that redirects virtual calls back to Python. Defining a new type of ``Animal`` from within Python is possible but requires a helper class that is defined as follows: .. code-block:: cpp class PyAnimal : public Animal { public: /* Inherit the constructors */ using Animal::Animal; /* Trampoline (need one for each virtual function) */ std::string go(int n_times) override { PYBIND11_OVERRIDE_PURE( std::string, /* Return type */ Animal, /* Parent class */ go, /* Name of function in C++ (must match Python name) */ n_times /* Argument(s) */ ); } }; The macro :c:macro:`PYBIND11_OVERRIDE_PURE` should be used for pure virtual functions, and :c:macro:`PYBIND11_OVERRIDE` should be used for functions which have a default implementation. There are also two alternate macros :c:macro:`PYBIND11_OVERRIDE_PURE_NAME` and :c:macro:`PYBIND11_OVERRIDE_NAME` which take a string-valued name argument between the *Parent class* and *Name of the function* slots, which defines the name of function in Python. This is required when the C++ and Python versions of the function have different names, e.g. ``operator()`` vs ``__call__``. The binding code also needs a few minor adaptations (highlighted): .. code-block:: cpp :emphasize-lines: 2,3 PYBIND11_MODULE(example, m) { py::class_(m, "Animal") .def(py::init<>()) .def("go", &Animal::go); py::class_(m, "Dog") .def(py::init<>()); m.def("call_go", &call_go); } Importantly, pybind11 is made aware of the trampoline helper class by specifying it as an extra template argument to :class:`class_`. (This can also be combined with other template arguments such as a custom holder type; the order of template types does not matter). Following this, we are able to define a constructor as usual. Bindings should be made against the actual class, not the trampoline helper class. .. code-block:: cpp :emphasize-lines: 3 py::class_(m, "Animal"); .def(py::init<>()) .def("go", &PyAnimal::go); /* <--- THIS IS WRONG, use &Animal::go */ Note, however, that the above is sufficient for allowing python classes to extend ``Animal``, but not ``Dog``: see :ref:`virtual_and_inheritance` for the necessary steps required to providing proper overriding support for inherited classes. The Python session below shows how to override ``Animal::go`` and invoke it via a virtual method call. .. code-block:: pycon >>> from example import * >>> d = Dog() >>> call_go(d) 'woof! woof! woof! ' >>> class Cat(Animal): ... def go(self, n_times): ... return "meow! " * n_times ... >>> c = Cat() >>> call_go(c) 'meow! meow! meow! ' If you are defining a custom constructor in a derived Python class, you *must* ensure that you explicitly call the bound C++ constructor using ``__init__``, *regardless* of whether it is a default constructor or not. Otherwise, the memory for the C++ portion of the instance will be left uninitialized, which will generally leave the C++ instance in an invalid state and cause undefined behavior if the C++ instance is subsequently used. .. versionchanged:: 2.6 The default pybind11 metaclass will throw a ``TypeError`` when it detects that ``__init__`` was not called by a derived class. Here is an example: .. code-block:: python class Dachshund(Dog): def __init__(self, name): Dog.__init__(self) # Without this, a TypeError is raised. self.name = name def bark(self): return "yap!" Note that a direct ``__init__`` constructor *should be called*, and ``super()`` should not be used. For simple cases of linear inheritance, ``super()`` may work, but once you begin mixing Python and C++ multiple inheritance, things will fall apart due to differences between Python's MRO and C++'s mechanisms. Please take a look at the :ref:`macro_notes` before using this feature. .. note:: When the overridden type returns a reference or pointer to a type that pybind11 converts from Python (for example, numeric values, std::string, and other built-in value-converting types), there are some limitations to be aware of: - because in these cases there is no C++ variable to reference (the value is stored in the referenced Python variable), pybind11 provides one in the PYBIND11_OVERRIDE macros (when needed) with static storage duration. Note that this means that invoking the overridden method on *any* instance will change the referenced value stored in *all* instances of that type. - Attempts to modify a non-const reference will not have the desired effect: it will change only the static cache variable, but this change will not propagate to underlying Python instance, and the change will be replaced the next time the override is invoked. .. warning:: The :c:macro:`PYBIND11_OVERRIDE` and accompanying macros used to be called ``PYBIND11_OVERLOAD`` up until pybind11 v2.5.0, and :func:`get_override` used to be called ``get_overload``. This naming was corrected and the older macro and function names may soon be deprecated, in order to reduce confusion with overloaded functions and methods and ``py::overload_cast`` (see :ref:`classes`). .. seealso:: The file :file:`tests/test_virtual_functions.cpp` contains a complete example that demonstrates how to override virtual functions using pybind11 in more detail. .. _virtual_and_inheritance: Combining virtual functions and inheritance =========================================== When combining virtual methods with inheritance, you need to be sure to provide an override for each method for which you want to allow overrides from derived python classes. For example, suppose we extend the above ``Animal``/``Dog`` example as follows: .. code-block:: cpp class Animal { public: virtual std::string go(int n_times) = 0; virtual std::string name() { return "unknown"; } }; class Dog : public Animal { public: std::string go(int n_times) override { std::string result; for (int i=0; i class PyAnimal : public AnimalBase { public: using AnimalBase::AnimalBase; // Inherit constructors std::string go(int n_times) override { PYBIND11_OVERRIDE_PURE(std::string, AnimalBase, go, n_times); } std::string name() override { PYBIND11_OVERRIDE(std::string, AnimalBase, name, ); } }; template class PyDog : public PyAnimal { public: using PyAnimal::PyAnimal; // Inherit constructors // Override PyAnimal's pure virtual go() with a non-pure one: std::string go(int n_times) override { PYBIND11_OVERRIDE(std::string, DogBase, go, n_times); } std::string bark() override { PYBIND11_OVERRIDE(std::string, DogBase, bark, ); } }; This technique has the advantage of requiring just one trampoline method to be declared per virtual method and pure virtual method override. It does, however, require the compiler to generate at least as many methods (and possibly more, if both pure virtual and overridden pure virtual methods are exposed, as above). The classes are then registered with pybind11 using: .. code-block:: cpp py::class_> animal(m, "Animal"); py::class_> dog(m, "Dog"); py::class_> husky(m, "Husky"); // ... add animal, dog, husky definitions Note that ``Husky`` did not require a dedicated trampoline template class at all, since it neither declares any new virtual methods nor provides any pure virtual method implementations. With either the repeated-virtuals or templated trampoline methods in place, you can now create a python class that inherits from ``Dog``: .. code-block:: python class ShihTzu(Dog): def bark(self): return "yip!" .. seealso:: See the file :file:`tests/test_virtual_functions.cpp` for complete examples using both the duplication and templated trampoline approaches. .. _extended_aliases: Extended trampoline class functionality ======================================= .. _extended_class_functionality_forced_trampoline: Forced trampoline class initialisation -------------------------------------- The trampoline classes described in the previous sections are, by default, only initialized when needed. More specifically, they are initialized when a python class actually inherits from a registered type (instead of merely creating an instance of the registered type), or when a registered constructor is only valid for the trampoline class but not the registered class. This is primarily for performance reasons: when the trampoline class is not needed for anything except virtual method dispatching, not initializing the trampoline class improves performance by avoiding needing to do a run-time check to see if the inheriting python instance has an overridden method. Sometimes, however, it is useful to always initialize a trampoline class as an intermediate class that does more than just handle virtual method dispatching. For example, such a class might perform extra class initialization, extra destruction operations, and might define new members and methods to enable a more python-like interface to a class. In order to tell pybind11 that it should *always* initialize the trampoline class when creating new instances of a type, the class constructors should be declared using ``py::init_alias()`` instead of the usual ``py::init()``. This forces construction via the trampoline class, ensuring member initialization and (eventual) destruction. .. seealso:: See the file :file:`tests/test_virtual_functions.cpp` for complete examples showing both normal and forced trampoline instantiation. Different method signatures --------------------------- The macro's introduced in :ref:`overriding_virtuals` cover most of the standard use cases when exposing C++ classes to Python. Sometimes it is hard or unwieldy to create a direct one-on-one mapping between the arguments and method return type. An example would be when the C++ signature contains output arguments using references (See also :ref:`faq_reference_arguments`). Another way of solving this is to use the method body of the trampoline class to do conversions to the input and return of the Python method. The main building block to do so is the :func:`get_override`, this function allows retrieving a method implemented in Python from within the trampoline's methods. Consider for example a C++ method which has the signature ``bool myMethod(int32_t& value)``, where the return indicates whether something should be done with the ``value``. This can be made convenient on the Python side by allowing the Python function to return ``None`` or an ``int``: .. code-block:: cpp bool MyClass::myMethod(int32_t& value) { pybind11::gil_scoped_acquire gil; // Acquire the GIL while in this scope. // Try to look up the overridden method on the Python side. pybind11::function override = pybind11::get_override(this, "myMethod"); if (override) { // method is found auto obj = override(value); // Call the Python function. if (py::isinstance(obj)) { // check if it returned a Python integer type value = obj.cast(); // Cast it and assign it to the value. return true; // Return true; value should be used. } else { return false; // Python returned none, return false. } } return false; // Alternatively return MyClass::myMethod(value); } .. _custom_constructors: Custom constructors =================== The syntax for binding constructors was previously introduced, but it only works when a constructor of the appropriate arguments actually exists on the C++ side. To extend this to more general cases, pybind11 makes it possible to bind factory functions as constructors. For example, suppose you have a class like this: .. code-block:: cpp class Example { private: Example(int); // private constructor public: // Factory function: static Example create(int a) { return Example(a); } }; py::class_(m, "Example") .def(py::init(&Example::create)); While it is possible to create a straightforward binding of the static ``create`` method, it may sometimes be preferable to expose it as a constructor on the Python side. This can be accomplished by calling ``.def(py::init(...))`` with the function reference returning the new instance passed as an argument. It is also possible to use this approach to bind a function returning a new instance by raw pointer or by the holder (e.g. ``std::unique_ptr``). The following example shows the different approaches: .. code-block:: cpp class Example { private: Example(int); // private constructor public: // Factory function - returned by value: static Example create(int a) { return Example(a); } // These constructors are publicly callable: Example(double); Example(int, int); Example(std::string); }; py::class_(m, "Example") // Bind the factory function as a constructor: .def(py::init(&Example::create)) // Bind a lambda function returning a pointer wrapped in a holder: .def(py::init([](std::string arg) { return std::unique_ptr(new Example(arg)); })) // Return a raw pointer: .def(py::init([](int a, int b) { return new Example(a, b); })) // You can mix the above with regular C++ constructor bindings as well: .def(py::init()) ; When the constructor is invoked from Python, pybind11 will call the factory function and store the resulting C++ instance in the Python instance. When combining factory functions constructors with :ref:`virtual function trampolines ` there are two approaches. The first is to add a constructor to the alias class that takes a base value by rvalue-reference. If such a constructor is available, it will be used to construct an alias instance from the value returned by the factory function. The second option is to provide two factory functions to ``py::init()``: the first will be invoked when no alias class is required (i.e. when the class is being used but not inherited from in Python), and the second will be invoked when an alias is required. You can also specify a single factory function that always returns an alias instance: this will result in behaviour similar to ``py::init_alias<...>()``, as described in the :ref:`extended trampoline class documentation `. The following example shows the different factory approaches for a class with an alias: .. code-block:: cpp #include class Example { public: // ... virtual ~Example() = default; }; class PyExample : public Example { public: using Example::Example; PyExample(Example &&base) : Example(std::move(base)) {} }; py::class_(m, "Example") // Returns an Example pointer. If a PyExample is needed, the Example // instance will be moved via the extra constructor in PyExample, above. .def(py::init([]() { return new Example(); })) // Two callbacks: .def(py::init([]() { return new Example(); } /* no alias needed */, []() { return new PyExample(); } /* alias needed */)) // *Always* returns an alias instance (like py::init_alias<>()) .def(py::init([]() { return new PyExample(); })) ; Brace initialization -------------------- ``pybind11::init<>`` internally uses C++11 brace initialization to call the constructor of the target class. This means that it can be used to bind *implicit* constructors as well: .. code-block:: cpp struct Aggregate { int a; std::string b; }; py::class_(m, "Aggregate") .def(py::init()); .. note:: Note that brace initialization preferentially invokes constructor overloads taking a ``std::initializer_list``. In the rare event that this causes an issue, you can work around it by using ``py::init(...)`` with a lambda function that constructs the new object as desired. .. _classes_with_non_public_destructors: Non-public destructors ====================== If a class has a private or protected destructor (as might e.g. be the case in a singleton pattern), a compile error will occur when creating bindings via pybind11. The underlying issue is that the ``std::unique_ptr`` holder type that is responsible for managing the lifetime of instances will reference the destructor even if no deallocations ever take place. In order to expose classes with private or protected destructors, it is possible to override the holder type via a holder type argument to ``class_``. Pybind11 provides a helper class ``py::nodelete`` that disables any destructor invocations. In this case, it is crucial that instances are deallocated on the C++ side to avoid memory leaks. .. code-block:: cpp /* ... definition ... */ class MyClass { private: ~MyClass() { } }; /* ... binding code ... */ py::class_>(m, "MyClass") .def(py::init<>()) .. _destructors_that_call_python: Destructors that call Python ============================ If a Python function is invoked from a C++ destructor, an exception may be thrown of type :class:`error_already_set`. If this error is thrown out of a class destructor, ``std::terminate()`` will be called, terminating the process. Class destructors must catch all exceptions of type :class:`error_already_set` to discard the Python exception using :func:`error_already_set::discard_as_unraisable`. Every Python function should be treated as *possibly throwing*. When a Python generator stops yielding items, Python will throw a ``StopIteration`` exception, which can pass though C++ destructors if the generator's stack frame holds the last reference to C++ objects. For more information, see :ref:`the documentation on exceptions `. .. code-block:: cpp class MyClass { public: ~MyClass() { try { py::print("Even printing is dangerous in a destructor"); py::exec("raise ValueError('This is an unraisable exception')"); } catch (py::error_already_set &e) { // error_context should be information about where/why the occurred, // e.g. use __func__ to get the name of the current function e.discard_as_unraisable(__func__); } } }; .. note:: pybind11 does not support C++ destructors marked ``noexcept(false)``. .. versionadded:: 2.6 .. _implicit_conversions: Implicit conversions ==================== Suppose that instances of two types ``A`` and ``B`` are used in a project, and that an ``A`` can easily be converted into an instance of type ``B`` (examples of this could be a fixed and an arbitrary precision number type). .. code-block:: cpp py::class_(m, "A") /// ... members ... py::class_(m, "B") .def(py::init()) /// ... members ... m.def("func", [](const B &) { /* .... */ } ); To invoke the function ``func`` using a variable ``a`` containing an ``A`` instance, we'd have to write ``func(B(a))`` in Python. On the other hand, C++ will automatically apply an implicit type conversion, which makes it possible to directly write ``func(a)``. In this situation (i.e. where ``B`` has a constructor that converts from ``A``), the following statement enables similar implicit conversions on the Python side: .. code-block:: cpp py::implicitly_convertible(); .. note:: Implicit conversions from ``A`` to ``B`` only work when ``B`` is a custom data type that is exposed to Python via pybind11. To prevent runaway recursion, implicit conversions are non-reentrant: an implicit conversion invoked as part of another implicit conversion of the same type (i.e. from ``A`` to ``B``) will fail. .. _static_properties: Static properties ================= The section on :ref:`properties` discussed the creation of instance properties that are implemented in terms of C++ getters and setters. Static properties can also be created in a similar way to expose getters and setters of static class attributes. Note that the implicit ``self`` argument also exists in this case and is used to pass the Python ``type`` subclass instance. This parameter will often not be needed by the C++ side, and the following example illustrates how to instantiate a lambda getter function that ignores it: .. code-block:: cpp py::class_(m, "Foo") .def_property_readonly_static("foo", [](py::object /* self */) { return Foo(); }); Operator overloading ==================== Suppose that we're given the following ``Vector2`` class with a vector addition and scalar multiplication operation, all implemented using overloaded operators in C++. .. code-block:: cpp class Vector2 { public: Vector2(float x, float y) : x(x), y(y) { } Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } Vector2 operator*(float value) const { return Vector2(x * value, y * value); } Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } Vector2& operator*=(float v) { x *= v; y *= v; return *this; } friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } private: float x, y; }; The following snippet shows how the above operators can be conveniently exposed to Python. .. code-block:: cpp #include PYBIND11_MODULE(example, m) { py::class_(m, "Vector2") .def(py::init()) .def(py::self + py::self) .def(py::self += py::self) .def(py::self *= float()) .def(float() * py::self) .def(py::self * float()) .def(-py::self) .def("__repr__", &Vector2::toString); } Note that a line like .. code-block:: cpp .def(py::self * float()) is really just short hand notation for .. code-block:: cpp .def("__mul__", [](const Vector2 &a, float b) { return a * b; }, py::is_operator()) This can be useful for exposing additional operators that don't exist on the C++ side, or to perform other types of customization. The ``py::is_operator`` flag marker is needed to inform pybind11 that this is an operator, which returns ``NotImplemented`` when invoked with incompatible arguments rather than throwing a type error. .. note:: To use the more convenient ``py::self`` notation, the additional header file :file:`pybind11/operators.h` must be included. .. seealso:: The file :file:`tests/test_operator_overloading.cpp` contains a complete example that demonstrates how to work with overloaded operators in more detail. .. _pickling: Pickling support ================ Python's ``pickle`` module provides a powerful facility to serialize and de-serialize a Python object graph into a binary data stream. To pickle and unpickle C++ classes using pybind11, a ``py::pickle()`` definition must be provided. Suppose the class in question has the following signature: .. code-block:: cpp class Pickleable { public: Pickleable(const std::string &value) : m_value(value) { } const std::string &value() const { return m_value; } void setExtra(int extra) { m_extra = extra; } int extra() const { return m_extra; } private: std::string m_value; int m_extra = 0; }; Pickling support in Python is enabled by defining the ``__setstate__`` and ``__getstate__`` methods [#f3]_. For pybind11 classes, use ``py::pickle()`` to bind these two functions: .. code-block:: cpp py::class_(m, "Pickleable") .def(py::init()) .def("value", &Pickleable::value) .def("extra", &Pickleable::extra) .def("setExtra", &Pickleable::setExtra) .def(py::pickle( [](const Pickleable &p) { // __getstate__ /* Return a tuple that fully encodes the state of the object */ return py::make_tuple(p.value(), p.extra()); }, [](py::tuple t) { // __setstate__ if (t.size() != 2) throw std::runtime_error("Invalid state!"); /* Create a new C++ instance */ Pickleable p(t[0].cast()); /* Assign any additional state */ p.setExtra(t[1].cast()); return p; } )); The ``__setstate__`` part of the ``py::pickle()`` definition follows the same rules as the single-argument version of ``py::init()``. The return type can be a value, pointer or holder type. See :ref:`custom_constructors` for details. An instance can now be pickled as follows: .. code-block:: python import pickle p = Pickleable("test_value") p.setExtra(15) data = pickle.dumps(p) .. note:: If given, the second argument to ``dumps`` must be 2 or larger - 0 and 1 are not supported. Newer versions are also fine; for instance, specify ``-1`` to always use the latest available version. Beware: failure to follow these instructions will cause important pybind11 memory allocation routines to be skipped during unpickling, which will likely lead to memory corruption and/or segmentation faults. Python defaults to version 3 (Python 3-3.7) and version 4 for Python 3.8+. .. seealso:: The file :file:`tests/test_pickling.cpp` contains a complete example that demonstrates how to pickle and unpickle types using pybind11 in more detail. .. [#f3] http://docs.python.org/3/library/pickle.html#pickling-class-instances Deepcopy support ================ Python normally uses references in assignments. Sometimes a real copy is needed to prevent changing all copies. The ``copy`` module [#f5]_ provides these capabilities. A class with pickle support is automatically also (deep)copy compatible. However, performance can be improved by adding custom ``__copy__`` and ``__deepcopy__`` methods. For simple classes (deep)copy can be enabled by using the copy constructor, which should look as follows: .. code-block:: cpp py::class_(m, "Copyable") .def("__copy__", [](const Copyable &self) { return Copyable(self); }) .def("__deepcopy__", [](const Copyable &self, py::dict) { return Copyable(self); }, "memo"_a); .. note:: Dynamic attributes will not be copied in this example. .. [#f5] https://docs.python.org/3/library/copy.html Multiple Inheritance ==================== pybind11 can create bindings for types that derive from multiple base types (aka. *multiple inheritance*). To do so, specify all bases in the template arguments of the ``class_`` declaration: .. code-block:: cpp py::class_(m, "MyType") ... The base types can be specified in arbitrary order, and they can even be interspersed with alias types and holder types (discussed earlier in this document)---pybind11 will automatically find out which is which. The only requirement is that the first template argument is the type to be declared. It is also permitted to inherit multiply from exported C++ classes in Python, as well as inheriting from multiple Python and/or pybind11-exported classes. There is one caveat regarding the implementation of this feature: When only one base type is specified for a C++ type that actually has multiple bases, pybind11 will assume that it does not participate in multiple inheritance, which can lead to undefined behavior. In such cases, add the tag ``multiple_inheritance`` to the class constructor: .. code-block:: cpp py::class_(m, "MyType", py::multiple_inheritance()); The tag is redundant and does not need to be specified when multiple base types are listed. .. _module_local: Module-local class bindings =========================== When creating a binding for a class, pybind11 by default makes that binding "global" across modules. What this means is that a type defined in one module can be returned from any module resulting in the same Python type. For example, this allows the following: .. code-block:: cpp // In the module1.cpp binding code for module1: py::class_(m, "Pet") .def(py::init()) .def_readonly("name", &Pet::name); .. code-block:: cpp // In the module2.cpp binding code for module2: m.def("create_pet", [](std::string name) { return new Pet(name); }); .. code-block:: pycon >>> from module1 import Pet >>> from module2 import create_pet >>> pet1 = Pet("Kitty") >>> pet2 = create_pet("Doggy") >>> pet2.name() 'Doggy' When writing binding code for a library, this is usually desirable: this allows, for example, splitting up a complex library into multiple Python modules. In some cases, however, this can cause conflicts. For example, suppose two unrelated modules make use of an external C++ library and each provide custom bindings for one of that library's classes. This will result in an error when a Python program attempts to import both modules (directly or indirectly) because of conflicting definitions on the external type: .. code-block:: cpp // dogs.cpp // Binding for external library class: py::class(m, "Pet") .def("name", &pets::Pet::name); // Binding for local extension class: py::class(m, "Dog") .def(py::init()); .. code-block:: cpp // cats.cpp, in a completely separate project from the above dogs.cpp. // Binding for external library class: py::class(m, "Pet") .def("get_name", &pets::Pet::name); // Binding for local extending class: py::class(m, "Cat") .def(py::init()); .. code-block:: pycon >>> import cats >>> import dogs Traceback (most recent call last): File "", line 1, in ImportError: generic_type: type "Pet" is already registered! To get around this, you can tell pybind11 to keep the external class binding localized to the module by passing the ``py::module_local()`` attribute into the ``py::class_`` constructor: .. code-block:: cpp // Pet binding in dogs.cpp: py::class(m, "Pet", py::module_local()) .def("name", &pets::Pet::name); .. code-block:: cpp // Pet binding in cats.cpp: py::class(m, "Pet", py::module_local()) .def("get_name", &pets::Pet::name); This makes the Python-side ``dogs.Pet`` and ``cats.Pet`` into distinct classes, avoiding the conflict and allowing both modules to be loaded. C++ code in the ``dogs`` module that casts or returns a ``Pet`` instance will result in a ``dogs.Pet`` Python instance, while C++ code in the ``cats`` module will result in a ``cats.Pet`` Python instance. This does come with two caveats, however: First, external modules cannot return or cast a ``Pet`` instance to Python (unless they also provide their own local bindings). Second, from the Python point of view they are two distinct classes. Note that the locality only applies in the C++ -> Python direction. When passing such a ``py::module_local`` type into a C++ function, the module-local classes are still considered. This means that if the following function is added to any module (including but not limited to the ``cats`` and ``dogs`` modules above) it will be callable with either a ``dogs.Pet`` or ``cats.Pet`` argument: .. code-block:: cpp m.def("pet_name", [](const pets::Pet &pet) { return pet.name(); }); For example, suppose the above function is added to each of ``cats.cpp``, ``dogs.cpp`` and ``frogs.cpp`` (where ``frogs.cpp`` is some other module that does *not* bind ``Pets`` at all). .. code-block:: pycon >>> import cats, dogs, frogs # No error because of the added py::module_local() >>> mycat, mydog = cats.Cat("Fluffy"), dogs.Dog("Rover") >>> (cats.pet_name(mycat), dogs.pet_name(mydog)) ('Fluffy', 'Rover') >>> (cats.pet_name(mydog), dogs.pet_name(mycat), frogs.pet_name(mycat)) ('Rover', 'Fluffy', 'Fluffy') It is possible to use ``py::module_local()`` registrations in one module even if another module registers the same type globally: within the module with the module-local definition, all C++ instances will be cast to the associated bound Python type. In other modules any such values are converted to the global Python type created elsewhere. .. note:: STL bindings (as provided via the optional :file:`pybind11/stl_bind.h` header) apply ``py::module_local`` by default when the bound type might conflict with other modules; see :ref:`stl_bind` for details. .. note:: The localization of the bound types is actually tied to the shared object or binary generated by the compiler/linker. For typical modules created with ``PYBIND11_MODULE()``, this distinction is not significant. It is possible, however, when :ref:`embedding` to embed multiple modules in the same binary (see :ref:`embedding_modules`). In such a case, the localization will apply across all embedded modules within the same binary. .. seealso:: The file :file:`tests/test_local_bindings.cpp` contains additional examples that demonstrate how ``py::module_local()`` works. Binding protected member functions ================================== It's normally not possible to expose ``protected`` member functions to Python: .. code-block:: cpp class A { protected: int foo() const { return 42; } }; py::class_(m, "A") .def("foo", &A::foo); // error: 'foo' is a protected member of 'A' On one hand, this is good because non-``public`` members aren't meant to be accessed from the outside. But we may want to make use of ``protected`` functions in derived Python classes. The following pattern makes this possible: .. code-block:: cpp class A { protected: int foo() const { return 42; } }; class Publicist : public A { // helper type for exposing protected functions public: using A::foo; // inherited with different access modifier }; py::class_(m, "A") // bind the primary class .def("foo", &Publicist::foo); // expose protected methods via the publicist This works because ``&Publicist::foo`` is exactly the same function as ``&A::foo`` (same signature and address), just with a different access modifier. The only purpose of the ``Publicist`` helper class is to make the function name ``public``. If the intent is to expose ``protected`` ``virtual`` functions which can be overridden in Python, the publicist pattern can be combined with the previously described trampoline: .. code-block:: cpp class A { public: virtual ~A() = default; protected: virtual int foo() const { return 42; } }; class Trampoline : public A { public: int foo() const override { PYBIND11_OVERRIDE(int, A, foo, ); } }; class Publicist : public A { public: using A::foo; }; py::class_(m, "A") // <-- `Trampoline` here .def("foo", &Publicist::foo); // <-- `Publicist` here, not `Trampoline`! Binding final classes ===================== Some classes may not be appropriate to inherit from. In C++11, classes can use the ``final`` specifier to ensure that a class cannot be inherited from. The ``py::is_final`` attribute can be used to ensure that Python classes cannot inherit from a specified type. The underlying C++ type does not need to be declared final. .. code-block:: cpp class IsFinal final {}; py::class_(m, "IsFinal", py::is_final()); When you try to inherit from such a class in Python, you will now get this error: .. code-block:: pycon >>> class PyFinalChild(IsFinal): ... pass ... TypeError: type 'IsFinal' is not an acceptable base type .. note:: This attribute is currently ignored on PyPy .. versionadded:: 2.6 Binding classes with template parameters ======================================== pybind11 can also wrap classes that have template parameters. Consider these classes: .. code-block:: cpp struct Cat {}; struct Dog {}; template struct Cage { Cage(PetType& pet); PetType& get(); }; C++ templates may only be instantiated at compile time, so pybind11 can only wrap instantiated templated classes. You cannot wrap a non-instantiated template: .. code-block:: cpp // BROKEN (this will not compile) py::class_(m, "Cage"); .def("get", &Cage::get); You must explicitly specify each template/type combination that you want to wrap separately. .. code-block:: cpp // ok py::class_>(m, "CatCage") .def("get", &Cage::get); // ok py::class_>(m, "DogCage") .def("get", &Cage::get); If your class methods have template parameters you can wrap those as well, but once again each instantiation must be explicitly specified: .. code-block:: cpp typename struct MyClass { template T fn(V v); }; py::class>(m, "MyClassT") .def("fn", &MyClass::fn); Custom automatic downcasters ============================ As explained in :ref:`inheritance`, pybind11 comes with built-in understanding of the dynamic type of polymorphic objects in C++; that is, returning a Pet to Python produces a Python object that knows it's wrapping a Dog, if Pet has virtual methods and pybind11 knows about Dog and this Pet is in fact a Dog. Sometimes, you might want to provide this automatic downcasting behavior when creating bindings for a class hierarchy that does not use standard C++ polymorphism, such as LLVM [#f4]_. As long as there's some way to determine at runtime whether a downcast is safe, you can proceed by specializing the ``pybind11::polymorphic_type_hook`` template: .. code-block:: cpp enum class PetKind { Cat, Dog, Zebra }; struct Pet { // Not polymorphic: has no virtual methods const PetKind kind; int age = 0; protected: Pet(PetKind _kind) : kind(_kind) {} }; struct Dog : Pet { Dog() : Pet(PetKind::Dog) {} std::string sound = "woof!"; std::string bark() const { return sound; } }; namespace PYBIND11_NAMESPACE { template<> struct polymorphic_type_hook { static const void *get(const Pet *src, const std::type_info*& type) { // note that src may be nullptr if (src && src->kind == PetKind::Dog) { type = &typeid(Dog); return static_cast(src); } return src; } }; } // namespace PYBIND11_NAMESPACE When pybind11 wants to convert a C++ pointer of type ``Base*`` to a Python object, it calls ``polymorphic_type_hook::get()`` to determine if a downcast is possible. The ``get()`` function should use whatever runtime information is available to determine if its ``src`` parameter is in fact an instance of some class ``Derived`` that inherits from ``Base``. If it finds such a ``Derived``, it sets ``type = &typeid(Derived)`` and returns a pointer to the ``Derived`` object that contains ``src``. Otherwise, it just returns ``src``, leaving ``type`` at its default value of nullptr. If you set ``type`` to a type that pybind11 doesn't know about, no downcasting will occur, and the original ``src`` pointer will be used with its static type ``Base*``. It is critical that the returned pointer and ``type`` argument of ``get()`` agree with each other: if ``type`` is set to something non-null, the returned pointer must point to the start of an object whose type is ``type``. If the hierarchy being exposed uses only single inheritance, a simple ``return src;`` will achieve this just fine, but in the general case, you must cast ``src`` to the appropriate derived-class pointer (e.g. using ``static_cast(src)``) before allowing it to be returned as a ``void*``. .. [#f4] https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html .. note:: pybind11's standard support for downcasting objects whose types have virtual methods is implemented using ``polymorphic_type_hook`` too, using the standard C++ ability to determine the most-derived type of a polymorphic object using ``typeid()`` and to cast a base pointer to that most-derived type (even if you don't know what it is) using ``dynamic_cast``. .. seealso:: The file :file:`tests/test_tagbased_polymorphic.cpp` contains a more complete example, including a demonstration of how to provide automatic downcasting for an entire class hierarchy without writing one get() function for each class. Accessing the type object ========================= You can get the type object from a C++ class that has already been registered using: .. code-block:: cpp py::type T_py = py::type::of(); You can directly use ``py::type::of(ob)`` to get the type object from any python object, just like ``type(ob)`` in Python. .. note:: Other types, like ``py::type::of()``, do not work, see :ref:`type-conversions`. .. versionadded:: 2.6 Custom type setup ================= For advanced use cases, such as enabling garbage collection support, you may wish to directly manipulate the ``PyHeapTypeObject`` corresponding to a ``py::class_`` definition. You can do that using ``py::custom_type_setup``: .. code-block:: cpp struct OwnsPythonObjects { py::object value = py::none(); }; py::class_ cls( m, "OwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) { auto *type = &heap_type->ht_type; type->tp_flags |= Py_TPFLAGS_HAVE_GC; type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) { auto &self = py::cast(py::handle(self_base)); Py_VISIT(self.value.ptr()); return 0; }; type->tp_clear = [](PyObject *self_base) { auto &self = py::cast(py::handle(self_base)); self.value = py::none(); return 0; }; })); cls.def(py::init<>()); cls.def_readwrite("value", &OwnsPythonObjects::value); .. versionadded:: 2.8 aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/0000755000175000017500000000000014516225226021226 5ustar olesolesaoflagger-v3.4.0/external/pybind11/docs/advanced/cast/chrono.rst0000644000175000017500000000754114507760431023261 0ustar olesolesChrono ====== When including the additional header file :file:`pybind11/chrono.h` conversions from C++11 chrono datatypes to python datetime objects are automatically enabled. This header also enables conversions of python floats (often from sources such as ``time.monotonic()``, ``time.perf_counter()`` and ``time.process_time()``) into durations. An overview of clocks in C++11 ------------------------------ A point of confusion when using these conversions is the differences between clocks provided in C++11. There are three clock types defined by the C++11 standard and users can define their own if needed. Each of these clocks have different properties and when converting to and from python will give different results. The first clock defined by the standard is ``std::chrono::system_clock``. This clock measures the current date and time. However, this clock changes with to updates to the operating system time. For example, if your time is synchronised with a time server this clock will change. This makes this clock a poor choice for timing purposes but good for measuring the wall time. The second clock defined in the standard is ``std::chrono::steady_clock``. This clock ticks at a steady rate and is never adjusted. This makes it excellent for timing purposes, however the value in this clock does not correspond to the current date and time. Often this clock will be the amount of time your system has been on, although it does not have to be. This clock will never be the same clock as the system clock as the system clock can change but steady clocks cannot. The third clock defined in the standard is ``std::chrono::high_resolution_clock``. This clock is the clock that has the highest resolution out of the clocks in the system. It is normally a typedef to either the system clock or the steady clock but can be its own independent clock. This is important as when using these conversions as the types you get in python for this clock might be different depending on the system. If it is a typedef of the system clock, python will get datetime objects, but if it is a different clock they will be timedelta objects. Provided conversions -------------------- .. rubric:: C++ to Python - ``std::chrono::system_clock::time_point`` → ``datetime.datetime`` System clock times are converted to python datetime instances. They are in the local timezone, but do not have any timezone information attached to them (they are naive datetime objects). - ``std::chrono::duration`` → ``datetime.timedelta`` Durations are converted to timedeltas, any precision in the duration greater than microseconds is lost by rounding towards zero. - ``std::chrono::[other_clocks]::time_point`` → ``datetime.timedelta`` Any clock time that is not the system clock is converted to a time delta. This timedelta measures the time from the clocks epoch to now. .. rubric:: Python to C++ - ``datetime.datetime`` or ``datetime.date`` or ``datetime.time`` → ``std::chrono::system_clock::time_point`` Date/time objects are converted into system clock timepoints. Any timezone information is ignored and the type is treated as a naive object. - ``datetime.timedelta`` → ``std::chrono::duration`` Time delta are converted into durations with microsecond precision. - ``datetime.timedelta`` → ``std::chrono::[other_clocks]::time_point`` Time deltas that are converted into clock timepoints are treated as the amount of time from the start of the clocks epoch. - ``float`` → ``std::chrono::duration`` Floats that are passed to C++ as durations be interpreted as a number of seconds. These will be converted to the duration using ``duration_cast`` from the float. - ``float`` → ``std::chrono::[other_clocks]::time_point`` Floats that are passed to C++ as time points will be interpreted as the number of seconds from the start of the clocks epoch. aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/stl.rst0000644000175000017500000002256214507760431022573 0ustar olesolesSTL containers ############## Automatic conversion ==================== When including the additional header file :file:`pybind11/stl.h`, conversions between ``std::vector<>``/``std::deque<>``/``std::list<>``/``std::array<>``/``std::valarray<>``, ``std::set<>``/``std::unordered_set<>``, and ``std::map<>``/``std::unordered_map<>`` and the Python ``list``, ``set`` and ``dict`` data structures are automatically enabled. The types ``std::pair<>`` and ``std::tuple<>`` are already supported out of the box with just the core :file:`pybind11/pybind11.h` header. The major downside of these implicit conversions is that containers must be converted (i.e. copied) on every Python->C++ and C++->Python transition, which can have implications on the program semantics and performance. Please read the next sections for more details and alternative approaches that avoid this. .. note:: Arbitrary nesting of any of these types is possible. .. seealso:: The file :file:`tests/test_stl.cpp` contains a complete example that demonstrates how to pass STL data types in more detail. .. _cpp17_container_casters: C++17 library containers ======================== The :file:`pybind11/stl.h` header also includes support for ``std::optional<>`` and ``std::variant<>``. These require a C++17 compiler and standard library. In C++14 mode, ``std::experimental::optional<>`` is supported if available. Various versions of these containers also exist for C++11 (e.g. in Boost). pybind11 provides an easy way to specialize the ``type_caster`` for such types: .. code-block:: cpp // `boost::optional` as an example -- can be any `std::optional`-like container namespace PYBIND11_NAMESPACE { namespace detail { template struct type_caster> : optional_caster> {}; }} The above should be placed in a header file and included in all translation units where automatic conversion is needed. Similarly, a specialization can be provided for custom variant types: .. code-block:: cpp // `boost::variant` as an example -- can be any `std::variant`-like container namespace PYBIND11_NAMESPACE { namespace detail { template struct type_caster> : variant_caster> {}; // Specifies the function used to visit the variant -- `apply_visitor` instead of `visit` template <> struct visit_helper { template static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) { return boost::apply_visitor(args...); } }; }} // namespace PYBIND11_NAMESPACE::detail The ``visit_helper`` specialization is not required if your ``name::variant`` provides a ``name::visit()`` function. For any other function name, the specialization must be included to tell pybind11 how to visit the variant. .. warning:: When converting a ``variant`` type, pybind11 follows the same rules as when determining which function overload to call (:ref:`overload_resolution`), and so the same caveats hold. In particular, the order in which the ``variant``'s alternatives are listed is important, since pybind11 will try conversions in this order. This means that, for example, when converting ``variant``, the ``bool`` variant will never be selected, as any Python ``bool`` is already an ``int`` and is convertible to a C++ ``int``. Changing the order of alternatives (and using ``variant``, in this example) provides a solution. .. note:: pybind11 only supports the modern implementation of ``boost::variant`` which makes use of variadic templates. This requires Boost 1.56 or newer. .. _opaque: Making opaque types =================== pybind11 heavily relies on a template matching mechanism to convert parameters and return values that are constructed from STL data types such as vectors, linked lists, hash tables, etc. This even works in a recursive manner, for instance to deal with lists of hash maps of pairs of elementary and custom types, etc. However, a fundamental limitation of this approach is that internal conversions between Python and C++ types involve a copy operation that prevents pass-by-reference semantics. What does this mean? Suppose we bind the following function .. code-block:: cpp void append_1(std::vector &v) { v.push_back(1); } and call it from Python, the following happens: .. code-block:: pycon >>> v = [5, 6] >>> append_1(v) >>> print(v) [5, 6] As you can see, when passing STL data structures by reference, modifications are not propagated back the Python side. A similar situation arises when exposing STL data structures using the ``def_readwrite`` or ``def_readonly`` functions: .. code-block:: cpp /* ... definition ... */ class MyClass { std::vector contents; }; /* ... binding code ... */ py::class_(m, "MyClass") .def(py::init<>()) .def_readwrite("contents", &MyClass::contents); In this case, properties can be read and written in their entirety. However, an ``append`` operation involving such a list type has no effect: .. code-block:: pycon >>> m = MyClass() >>> m.contents = [5, 6] >>> print(m.contents) [5, 6] >>> m.contents.append(7) >>> print(m.contents) [5, 6] Finally, the involved copy operations can be costly when dealing with very large lists. To deal with all of the above situations, pybind11 provides a macro named ``PYBIND11_MAKE_OPAQUE(T)`` that disables the template-based conversion machinery of types, thus rendering them *opaque*. The contents of opaque objects are never inspected or extracted, hence they *can* be passed by reference. For instance, to turn ``std::vector`` into an opaque type, add the declaration .. code-block:: cpp PYBIND11_MAKE_OPAQUE(std::vector); before any binding code (e.g. invocations to ``class_::def()``, etc.). This macro must be specified at the top level (and outside of any namespaces), since it adds a template instantiation of ``type_caster``. If your binding code consists of multiple compilation units, it must be present in every file (typically via a common header) preceding any usage of ``std::vector``. Opaque types must also have a corresponding ``class_`` declaration to associate them with a name in Python, and to define a set of available operations, e.g.: .. code-block:: cpp py::class_>(m, "IntVector") .def(py::init<>()) .def("clear", &std::vector::clear) .def("pop_back", &std::vector::pop_back) .def("__len__", [](const std::vector &v) { return v.size(); }) .def("__iter__", [](std::vector &v) { return py::make_iterator(v.begin(), v.end()); }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */ // .... .. seealso:: The file :file:`tests/test_opaque_types.cpp` contains a complete example that demonstrates how to create and expose opaque types using pybind11 in more detail. .. _stl_bind: Binding STL containers ====================== The ability to expose STL containers as native Python objects is a fairly common request, hence pybind11 also provides an optional header file named :file:`pybind11/stl_bind.h` that does exactly this. The mapped containers try to match the behavior of their native Python counterparts as much as possible. The following example showcases usage of :file:`pybind11/stl_bind.h`: .. code-block:: cpp // Don't forget this #include PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(std::map); // ... // later in binding code: py::bind_vector>(m, "VectorInt"); py::bind_map>(m, "MapStringDouble"); When binding STL containers pybind11 considers the types of the container's elements to decide whether the container should be confined to the local module (via the :ref:`module_local` feature). If the container element types are anything other than already-bound custom types bound without ``py::module_local()`` the container binding will have ``py::module_local()`` applied. This includes converting types such as numeric types, strings, Eigen types; and types that have not yet been bound at the time of the stl container binding. This module-local binding is designed to avoid potential conflicts between module bindings (for example, from two separate modules each attempting to bind ``std::vector`` as a python type). It is possible to override this behavior to force a definition to be either module-local or global. To do so, you can pass the attributes ``py::module_local()`` (to make the binding module-local) or ``py::module_local(false)`` (to make the binding global) into the ``py::bind_vector`` or ``py::bind_map`` arguments: .. code-block:: cpp py::bind_vector>(m, "VectorInt", py::module_local(false)); Note, however, that such a global binding would make it impossible to load this module at the same time as any other pybind module that also attempts to bind the same container type (``std::vector`` in the above example). See :ref:`module_local` for more details on module-local bindings. .. seealso:: The file :file:`tests/test_stl_binders.cpp` shows how to use the convenience STL container wrappers. aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/overview.rst0000644000175000017500000003012314507760431023627 0ustar olesolesOverview ######## .. rubric:: 1. Native type in C++, wrapper in Python Exposing a custom C++ type using :class:`py::class_` was covered in detail in the :doc:`/classes` section. There, the underlying data structure is always the original C++ class while the :class:`py::class_` wrapper provides a Python interface. Internally, when an object like this is sent from C++ to Python, pybind11 will just add the outer wrapper layer over the native C++ object. Getting it back from Python is just a matter of peeling off the wrapper. .. rubric:: 2. Wrapper in C++, native type in Python This is the exact opposite situation. Now, we have a type which is native to Python, like a ``tuple`` or a ``list``. One way to get this data into C++ is with the :class:`py::object` family of wrappers. These are explained in more detail in the :doc:`/advanced/pycpp/object` section. We'll just give a quick example here: .. code-block:: cpp void print_list(py::list my_list) { for (auto item : my_list) std::cout << item << " "; } .. code-block:: pycon >>> print_list([1, 2, 3]) 1 2 3 The Python ``list`` is not converted in any way -- it's just wrapped in a C++ :class:`py::list` class. At its core it's still a Python object. Copying a :class:`py::list` will do the usual reference-counting like in Python. Returning the object to Python will just remove the thin wrapper. .. rubric:: 3. Converting between native C++ and Python types In the previous two cases we had a native type in one language and a wrapper in the other. Now, we have native types on both sides and we convert between them. .. code-block:: cpp void print_vector(const std::vector &v) { for (auto item : v) std::cout << item << "\n"; } .. code-block:: pycon >>> print_vector([1, 2, 3]) 1 2 3 In this case, pybind11 will construct a new ``std::vector`` and copy each element from the Python ``list``. The newly constructed object will be passed to ``print_vector``. The same thing happens in the other direction: a new ``list`` is made to match the value returned from C++. Lots of these conversions are supported out of the box, as shown in the table below. They are very convenient, but keep in mind that these conversions are fundamentally based on copying data. This is perfectly fine for small immutable types but it may become quite expensive for large data structures. This can be avoided by overriding the automatic conversion with a custom wrapper (i.e. the above-mentioned approach 1). This requires some manual effort and more details are available in the :ref:`opaque` section. .. _conversion_table: List of all builtin conversions ------------------------------- The following basic data types are supported out of the box (some may require an additional extension header to be included). To pass other data structures as arguments and return values, refer to the section on binding :ref:`classes`. +------------------------------------+---------------------------+-----------------------------------+ | Data type | Description | Header file | +====================================+===========================+===================================+ | ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``char`` | Character literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` | | ``std::u16string_view``, etc. | | | +------------------------------------+---------------------------+-----------------------------------+ | ``std::pair`` | Pair of two custom types | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::complex`` | Complex numbers | :file:`pybind11/complex.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::array`` | STL static array | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::vector`` | STL dynamic array | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::deque`` | STL double-ended queue | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::valarray`` | STL value array | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::list`` | STL linked list | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::map`` | STL ordered map | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::unordered_map`` | STL unordered map | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::set`` | STL ordered set | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::unordered_set`` | STL unordered set | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::optional`` | STL optional type (C++17) | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::experimental::optional`` | STL optional type (exp.) | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::filesystem::path`` | STL path (C++17) [#]_ | :file:`pybind11/stl/filesystem.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` | +------------------------------------+---------------------------+-----------------------------------+ | ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | +------------------------------------+---------------------------+-----------------------------------+ .. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and ``os.PathLike`` is converted to ``std::filesystem::path``. aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/functional.rst0000644000175000017500000000746114507760431024134 0ustar olesolesFunctional ########## The following features must be enabled by including :file:`pybind11/functional.h`. Callbacks and passing anonymous functions ========================================= The C++11 standard brought lambda functions and the generic polymorphic function wrapper ``std::function<>`` to the C++ programming language, which enable powerful new ways of working with functions. Lambda functions come in two flavors: stateless lambda function resemble classic function pointers that link to an anonymous piece of code, while stateful lambda functions additionally depend on captured variables that are stored in an anonymous *lambda closure object*. Here is a simple example of a C++ function that takes an arbitrary function (stateful or stateless) with signature ``int -> int`` as an argument and runs it with the value 10. .. code-block:: cpp int func_arg(const std::function &f) { return f(10); } The example below is more involved: it takes a function of signature ``int -> int`` and returns another function of the same kind. The return value is a stateful lambda function, which stores the value ``f`` in the capture object and adds 1 to its return value upon execution. .. code-block:: cpp std::function func_ret(const std::function &f) { return [f](int i) { return f(i) + 1; }; } This example demonstrates using python named parameters in C++ callbacks which requires using ``py::cpp_function`` as a wrapper. Usage is similar to defining methods of classes: .. code-block:: cpp py::cpp_function func_cpp() { return py::cpp_function([](int i) { return i+1; }, py::arg("number")); } After including the extra header file :file:`pybind11/functional.h`, it is almost trivial to generate binding code for all of these functions. .. code-block:: cpp #include PYBIND11_MODULE(example, m) { m.def("func_arg", &func_arg); m.def("func_ret", &func_ret); m.def("func_cpp", &func_cpp); } The following interactive session shows how to call them from Python. .. code-block:: pycon $ python >>> import example >>> def square(i): ... return i * i ... >>> example.func_arg(square) 100L >>> square_plus_1 = example.func_ret(square) >>> square_plus_1(4) 17L >>> plus_1 = func_cpp() >>> plus_1(number=43) 44L .. warning:: Keep in mind that passing a function from C++ to Python (or vice versa) will instantiate a piece of wrapper code that translates function invocations between the two languages. Naturally, this translation increases the computational cost of each function call somewhat. A problematic situation can arise when a function is copied back and forth between Python and C++ many times in a row, in which case the underlying wrappers will accumulate correspondingly. The resulting long sequence of C++ -> Python -> C++ -> ... roundtrips can significantly decrease performance. There is one exception: pybind11 detects case where a stateless function (i.e. a function pointer or a lambda function without captured variables) is passed as an argument to another C++ function exposed in Python. In this case, there is no overhead. Pybind11 will extract the underlying C++ function pointer from the wrapped function to sidestep a potential C++ -> Python -> C++ roundtrip. This is demonstrated in :file:`tests/test_callbacks.cpp`. .. note:: This functionality is very useful when generating bindings for callbacks in C++ libraries (e.g. GUI libraries, asynchronous networking libraries, etc.). The file :file:`tests/test_callbacks.cpp` contains a complete example that demonstrates how to work with callbacks and anonymous functions in more detail. aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/eigen.rst0000644000175000017500000003371314507760431023060 0ustar olesolesEigen ##### `Eigen `_ is C++ header-based library for dense and sparse linear algebra. Due to its popularity and widespread adoption, pybind11 provides transparent conversion and limited mapping support between Eigen and Scientific Python linear algebra data types. To enable the built-in Eigen support you must include the optional header file :file:`pybind11/eigen.h`. Pass-by-value ============= When binding a function with ordinary Eigen dense object arguments (for example, ``Eigen::MatrixXd``), pybind11 will accept any input value that is already (or convertible to) a ``numpy.ndarray`` with dimensions compatible with the Eigen type, copy its values into a temporary Eigen variable of the appropriate type, then call the function with this temporary variable. Sparse matrices are similarly copied to or from ``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` objects. Pass-by-reference ================= One major limitation of the above is that every data conversion implicitly involves a copy, which can be both expensive (for large matrices) and disallows binding functions that change their (Matrix) arguments. Pybind11 allows you to work around this by using Eigen's ``Eigen::Ref`` class much as you would when writing a function taking a generic type in Eigen itself (subject to some limitations discussed below). When calling a bound function accepting a ``Eigen::Ref`` type, pybind11 will attempt to avoid copying by using an ``Eigen::Map`` object that maps into the source ``numpy.ndarray`` data: this requires both that the data types are the same (e.g. ``dtype='float64'`` and ``MatrixType::Scalar`` is ``double``); and that the storage is layout compatible. The latter limitation is discussed in detail in the section below, and requires careful consideration: by default, numpy matrices and Eigen matrices are *not* storage compatible. If the numpy matrix cannot be used as is (either because its types differ, e.g. passing an array of integers to an Eigen parameter requiring doubles, or because the storage is incompatible), pybind11 makes a temporary copy and passes the copy instead. When a bound function parameter is instead ``Eigen::Ref`` (note the lack of ``const``), pybind11 will only allow the function to be called if it can be mapped *and* if the numpy array is writeable (that is ``a.flags.writeable`` is true). Any access (including modification) made to the passed variable will be transparently carried out directly on the ``numpy.ndarray``. This means you can write code such as the following and have it work as expected: .. code-block:: cpp void scale_by_2(Eigen::Ref v) { v *= 2; } Note, however, that you will likely run into limitations due to numpy and Eigen's difference default storage order for data; see the below section on :ref:`storage_orders` for details on how to bind code that won't run into such limitations. .. note:: Passing by reference is not supported for sparse types. Returning values to Python ========================== When returning an ordinary dense Eigen matrix type to numpy (e.g. ``Eigen::MatrixXd`` or ``Eigen::RowVectorXf``) pybind11 keeps the matrix and returns a numpy array that directly references the Eigen matrix: no copy of the data is performed. The numpy array will have ``array.flags.owndata`` set to ``False`` to indicate that it does not own the data, and the lifetime of the stored Eigen matrix will be tied to the returned ``array``. If you bind a function with a non-reference, ``const`` return type (e.g. ``const Eigen::MatrixXd``), the same thing happens except that pybind11 also sets the numpy array's ``writeable`` flag to false. If you return an lvalue reference or pointer, the usual pybind11 rules apply, as dictated by the binding function's return value policy (see the documentation on :ref:`return_value_policies` for full details). That means, without an explicit return value policy, lvalue references will be copied and pointers will be managed by pybind11. In order to avoid copying, you should explicitly specify an appropriate return value policy, as in the following example: .. code-block:: cpp class MyClass { Eigen::MatrixXd big_mat = Eigen::MatrixXd::Zero(10000, 10000); public: Eigen::MatrixXd &getMatrix() { return big_mat; } const Eigen::MatrixXd &viewMatrix() { return big_mat; } }; // Later, in binding code: py::class_(m, "MyClass") .def(py::init<>()) .def("copy_matrix", &MyClass::getMatrix) // Makes a copy! .def("get_matrix", &MyClass::getMatrix, py::return_value_policy::reference_internal) .def("view_matrix", &MyClass::viewMatrix, py::return_value_policy::reference_internal) ; .. code-block:: python a = MyClass() m = a.get_matrix() # flags.writeable = True, flags.owndata = False v = a.view_matrix() # flags.writeable = False, flags.owndata = False c = a.copy_matrix() # flags.writeable = True, flags.owndata = True # m[5,6] and v[5,6] refer to the same element, c[5,6] does not. Note in this example that ``py::return_value_policy::reference_internal`` is used to tie the life of the MyClass object to the life of the returned arrays. You may also return an ``Eigen::Ref``, ``Eigen::Map`` or other map-like Eigen object (for example, the return value of ``matrix.block()`` and related methods) that map into a dense Eigen type. When doing so, the default behaviour of pybind11 is to simply reference the returned data: you must take care to ensure that this data remains valid! You may ask pybind11 to explicitly *copy* such a return value by using the ``py::return_value_policy::copy`` policy when binding the function. You may also use ``py::return_value_policy::reference_internal`` or a ``py::keep_alive`` to ensure the data stays valid as long as the returned numpy array does. When returning such a reference of map, pybind11 additionally respects the readonly-status of the returned value, marking the numpy array as non-writeable if the reference or map was itself read-only. .. note:: Sparse types are always copied when returned. .. _storage_orders: Storage orders ============== Passing arguments via ``Eigen::Ref`` has some limitations that you must be aware of in order to effectively pass matrices by reference. First and foremost is that the default ``Eigen::Ref`` class requires contiguous storage along columns (for column-major types, the default in Eigen) or rows if ``MatrixType`` is specifically an ``Eigen::RowMajor`` storage type. The former, Eigen's default, is incompatible with ``numpy``'s default row-major storage, and so you will not be able to pass numpy arrays to Eigen by reference without making one of two changes. (Note that this does not apply to vectors (or column or row matrices): for such types the "row-major" and "column-major" distinction is meaningless). The first approach is to change the use of ``Eigen::Ref`` to the more general ``Eigen::Ref>`` (or similar type with a fully dynamic stride type in the third template argument). Since this is a rather cumbersome type, pybind11 provides a ``py::EigenDRef`` type alias for your convenience (along with EigenDMap for the equivalent Map, and EigenDStride for just the stride type). This type allows Eigen to map into any arbitrary storage order. This is not the default in Eigen for performance reasons: contiguous storage allows vectorization that cannot be done when storage is not known to be contiguous at compile time. The default ``Eigen::Ref`` stride type allows non-contiguous storage along the outer dimension (that is, the rows of a column-major matrix or columns of a row-major matrix), but not along the inner dimension. This type, however, has the added benefit of also being able to map numpy array slices. For example, the following (contrived) example uses Eigen with a numpy slice to multiply by 2 all coefficients that are both on even rows (0, 2, 4, ...) and in columns 2, 5, or 8: .. code-block:: cpp m.def("scale", [](py::EigenDRef m, double c) { m *= c; }); .. code-block:: python # a = np.array(...) scale_by_2(myarray[0::2, 2:9:3]) The second approach to avoid copying is more intrusive: rearranging the underlying data types to not run into the non-contiguous storage problem in the first place. In particular, that means using matrices with ``Eigen::RowMajor`` storage, where appropriate, such as: .. code-block:: cpp using RowMatrixXd = Eigen::Matrix; // Use RowMatrixXd instead of MatrixXd Now bound functions accepting ``Eigen::Ref`` arguments will be callable with numpy's (default) arrays without involving a copying. You can, alternatively, change the storage order that numpy arrays use by adding the ``order='F'`` option when creating an array: .. code-block:: python myarray = np.array(source, order="F") Such an object will be passable to a bound function accepting an ``Eigen::Ref`` (or similar column-major Eigen type). One major caveat with this approach, however, is that it is not entirely as easy as simply flipping all Eigen or numpy usage from one to the other: some operations may alter the storage order of a numpy array. For example, ``a2 = array.transpose()`` results in ``a2`` being a view of ``array`` that references the same data, but in the opposite storage order! While this approach allows fully optimized vectorized calculations in Eigen, it cannot be used with array slices, unlike the first approach. When *returning* a matrix to Python (either a regular matrix, a reference via ``Eigen::Ref<>``, or a map/block into a matrix), no special storage consideration is required: the created numpy array will have the required stride that allows numpy to properly interpret the array, whatever its storage order. Failing rather than copying =========================== The default behaviour when binding ``Eigen::Ref`` Eigen references is to copy matrix values when passed a numpy array that does not conform to the element type of ``MatrixType`` or does not have a compatible stride layout. If you want to explicitly avoid copying in such a case, you should bind arguments using the ``py::arg().noconvert()`` annotation (as described in the :ref:`nonconverting_arguments` documentation). The following example shows an example of arguments that don't allow data copying to take place: .. code-block:: cpp // The method and function to be bound: class MyClass { // ... double some_method(const Eigen::Ref &matrix) { /* ... */ } }; float some_function(const Eigen::Ref &big, const Eigen::Ref &small) { // ... } // The associated binding code: using namespace pybind11::literals; // for "arg"_a py::class_(m, "MyClass") // ... other class definitions .def("some_method", &MyClass::some_method, py::arg().noconvert()); m.def("some_function", &some_function, "big"_a.noconvert(), // <- Don't allow copying for this arg "small"_a // <- This one can be copied if needed ); With the above binding code, attempting to call the the ``some_method(m)`` method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)`` will raise a ``RuntimeError`` rather than making a temporary copy of the array. It will, however, allow the ``m2`` argument to be copied into a temporary if necessary. Note that explicitly specifying ``.noconvert()`` is not required for *mutable* Eigen references (e.g. ``Eigen::Ref`` without ``const`` on the ``MatrixXd``): mutable references will never be called with a temporary copy. Vectors versus column/row matrices ================================== Eigen and numpy have fundamentally different notions of a vector. In Eigen, a vector is simply a matrix with the number of columns or rows set to 1 at compile time (for a column vector or row vector, respectively). NumPy, in contrast, has comparable 2-dimensional 1xN and Nx1 arrays, but *also* has 1-dimensional arrays of size N. When passing a 2-dimensional 1xN or Nx1 array to Eigen, the Eigen type must have matching dimensions: That is, you cannot pass a 2-dimensional Nx1 numpy array to an Eigen value expecting a row vector, or a 1xN numpy array as a column vector argument. On the other hand, pybind11 allows you to pass 1-dimensional arrays of length N as Eigen parameters. If the Eigen type can hold a column vector of length N it will be passed as such a column vector. If not, but the Eigen type constraints will accept a row vector, it will be passed as a row vector. (The column vector takes precedence when both are supported, for example, when passing a 1D numpy array to a MatrixXd argument). Note that the type need not be explicitly a vector: it is permitted to pass a 1D numpy array of size 5 to an Eigen ``Matrix``: you would end up with a 1x5 Eigen matrix. Passing the same to an ``Eigen::MatrixXd`` would result in a 5x1 Eigen matrix. When returning an Eigen vector to numpy, the conversion is ambiguous: a row vector of length 4 could be returned as either a 1D array of length 4, or as a 2D array of size 1x4. When encountering such a situation, pybind11 compromises by considering the returned Eigen type: if it is a compile-time vector--that is, the type has either the number of rows or columns set to 1 at compile time--pybind11 converts to a 1D numpy array when returning the value. For instances that are a vector only at run-time (e.g. ``MatrixXd``, ``Matrix``), pybind11 returns the vector as a 2D array to numpy. If this isn't want you want, you can use ``array.reshape(...)`` to get a view of the same data in the desired dimensions. .. seealso:: The file :file:`tests/test_eigen.cpp` contains a complete example that shows how to pass Eigen sparse and dense data types in more detail. aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/strings.rst0000644000175000017500000002123714507760431023460 0ustar olesolesStrings, bytes and Unicode conversions ###################################### Passing Python strings to C++ ============================= When a Python ``str`` is passed from Python to a C++ function that accepts ``std::string`` or ``char *`` as arguments, pybind11 will encode the Python string to UTF-8. All Python ``str`` can be encoded in UTF-8, so this operation does not fail. The C++ language is encoding agnostic. It is the responsibility of the programmer to track encodings. It's often easiest to simply `use UTF-8 everywhere `_. .. code-block:: c++ m.def("utf8_test", [](const std::string &s) { cout << "utf-8 is icing on the cake.\n"; cout << s; } ); m.def("utf8_charptr", [](const char *s) { cout << "My favorite food is\n"; cout << s; } ); .. code-block:: pycon >>> utf8_test("🎂") utf-8 is icing on the cake. 🎂 >>> utf8_charptr("ðŸ•") My favorite food is 🕠.. note:: Some terminal emulators do not support UTF-8 or emoji fonts and may not display the example above correctly. The results are the same whether the C++ function accepts arguments by value or reference, and whether or not ``const`` is used. Passing bytes to C++ -------------------- A Python ``bytes`` object will be passed to C++ functions that accept ``std::string`` or ``char*`` *without* conversion. In order to make a function *only* accept ``bytes`` (and not ``str``), declare it as taking a ``py::bytes`` argument. Returning C++ strings to Python =============================== When a C++ function returns a ``std::string`` or ``char*`` to a Python caller, **pybind11 will assume that the string is valid UTF-8** and will decode it to a native Python ``str``, using the same API as Python uses to perform ``bytes.decode('utf-8')``. If this implicit conversion fails, pybind11 will raise a ``UnicodeDecodeError``. .. code-block:: c++ m.def("std_string_return", []() { return std::string("This string needs to be UTF-8 encoded"); } ); .. code-block:: pycon >>> isinstance(example.std_string_return(), str) True Because UTF-8 is inclusive of pure ASCII, there is never any issue with returning a pure ASCII string to Python. If there is any possibility that the string is not pure ASCII, it is necessary to ensure the encoding is valid UTF-8. .. warning:: Implicit conversion assumes that a returned ``char *`` is null-terminated. If there is no null terminator a buffer overrun will occur. Explicit conversions -------------------- If some C++ code constructs a ``std::string`` that is not a UTF-8 string, one can perform a explicit conversion and return a ``py::str`` object. Explicit conversion has the same overhead as implicit conversion. .. code-block:: c++ // This uses the Python C API to convert Latin-1 to Unicode m.def("str_output", []() { std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1 py::str py_s = PyUnicode_DecodeLatin1(s.data(), s.length()); return py_s; } ); .. code-block:: pycon >>> str_output() 'Send your résumé to Alice in HR' The `Python C API `_ provides several built-in codecs. One could also use a third party encoding library such as libiconv to transcode to UTF-8. Return C++ strings without conversion ------------------------------------- If the data in a C++ ``std::string`` does not represent text and should be returned to Python as ``bytes``, then one can return the data as a ``py::bytes`` object. .. code-block:: c++ m.def("return_bytes", []() { std::string s("\xba\xd0\xba\xd0"); // Not valid UTF-8 return py::bytes(s); // Return the data without transcoding } ); .. code-block:: pycon >>> example.return_bytes() b'\xba\xd0\xba\xd0' Note the asymmetry: pybind11 will convert ``bytes`` to ``std::string`` without encoding, but cannot convert ``std::string`` back to ``bytes`` implicitly. .. code-block:: c++ m.def("asymmetry", [](std::string s) { // Accepts str or bytes from Python return s; // Looks harmless, but implicitly converts to str } ); .. code-block:: pycon >>> isinstance(example.asymmetry(b"have some bytes"), str) True >>> example.asymmetry(b"\xba\xd0\xba\xd0") # invalid utf-8 as bytes UnicodeDecodeError: 'utf-8' codec can't decode byte 0xba in position 0: invalid start byte Wide character strings ====================== When a Python ``str`` is passed to a C++ function expecting ``std::wstring``, ``wchar_t*``, ``std::u16string`` or ``std::u32string``, the ``str`` will be encoded to UTF-16 or UTF-32 depending on how the C++ compiler implements each type, in the platform's native endianness. When strings of these types are returned, they are assumed to contain valid UTF-16 or UTF-32, and will be decoded to Python ``str``. .. code-block:: c++ #define UNICODE #include m.def("set_window_text", [](HWND hwnd, std::wstring s) { // Call SetWindowText with null-terminated UTF-16 string ::SetWindowText(hwnd, s.c_str()); } ); m.def("get_window_text", [](HWND hwnd) { const int buffer_size = ::GetWindowTextLength(hwnd) + 1; auto buffer = std::make_unique< wchar_t[] >(buffer_size); ::GetWindowText(hwnd, buffer.data(), buffer_size); std::wstring text(buffer.get()); // wstring will be converted to Python str return text; } ); Strings in multibyte encodings such as Shift-JIS must transcoded to a UTF-8/16/32 before being returned to Python. Character literals ================== C++ functions that accept character literals as input will receive the first character of a Python ``str`` as their input. If the string is longer than one Unicode character, trailing characters will be ignored. When a character literal is returned from C++ (such as a ``char`` or a ``wchar_t``), it will be converted to a ``str`` that represents the single character. .. code-block:: c++ m.def("pass_char", [](char c) { return c; }); m.def("pass_wchar", [](wchar_t w) { return w; }); .. code-block:: pycon >>> example.pass_char("A") 'A' While C++ will cast integers to character types (``char c = 0x65;``), pybind11 does not convert Python integers to characters implicitly. The Python function ``chr()`` can be used to convert integers to characters. .. code-block:: pycon >>> example.pass_char(0x65) TypeError >>> example.pass_char(chr(0x65)) 'A' If the desire is to work with an 8-bit integer, use ``int8_t`` or ``uint8_t`` as the argument type. Grapheme clusters ----------------- A single grapheme may be represented by two or more Unicode characters. For example 'é' is usually represented as U+00E9 but can also be expressed as the combining character sequence U+0065 U+0301 (that is, the letter 'e' followed by a combining acute accent). The combining character will be lost if the two-character sequence is passed as an argument, even though it renders as a single grapheme. .. code-block:: pycon >>> example.pass_wchar("é") 'é' >>> combining_e_acute = "e" + "\u0301" >>> combining_e_acute 'eÌ' >>> combining_e_acute == "é" False >>> example.pass_wchar(combining_e_acute) 'e' Normalizing combining characters before passing the character literal to C++ may resolve *some* of these issues: .. code-block:: pycon >>> example.pass_wchar(unicodedata.normalize("NFC", combining_e_acute)) 'é' In some languages (Thai for example), there are `graphemes that cannot be expressed as a single Unicode code point `_, so there is no way to capture them in a C++ character type. C++17 string views ================== C++17 string views are automatically supported when compiling in C++17 mode. They follow the same rules for encoding and decoding as the corresponding STL string type (for example, a ``std::u16string_view`` argument will be passed UTF-16-encoded data, and a returned ``std::string_view`` will be decoded as UTF-8). References ========== * `The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) `_ * `C++ - Using STL Strings at Win32 API Boundaries `_ aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/custom.rst0000644000175000017500000000654514507760431023306 0ustar olesolesCustom type casters =================== In very rare cases, applications may require custom type casters that cannot be expressed using the abstractions provided by pybind11, thus requiring raw Python C API calls. This is fairly advanced usage and should only be pursued by experts who are familiar with the intricacies of Python reference counting. The following snippets demonstrate how this works for a very simple ``inty`` type that that should be convertible from Python types that provide a ``__int__(self)`` method. .. code-block:: cpp struct inty { long long_value; }; void print(inty s) { std::cout << s.long_value << std::endl; } The following Python snippet demonstrates the intended usage from the Python side: .. code-block:: python class A: def __int__(self): return 123 from example import print print(A()) To register the necessary conversion routines, it is necessary to add an instantiation of the ``pybind11::detail::type_caster`` template. Although this is an implementation detail, adding an instantiation of this type is explicitly allowed. .. code-block:: cpp namespace PYBIND11_NAMESPACE { namespace detail { template <> struct type_caster { public: /** * This macro establishes the name 'inty' in * function signatures and declares a local variable * 'value' of type inty */ PYBIND11_TYPE_CASTER(inty, const_name("inty")); /** * Conversion part 1 (Python->C++): convert a PyObject into a inty * instance or return false upon failure. The second argument * indicates whether implicit conversions should be applied. */ bool load(handle src, bool) { /* Extract PyObject from handle */ PyObject *source = src.ptr(); /* Try converting into a Python integer value */ PyObject *tmp = PyNumber_Long(source); if (!tmp) return false; /* Now try to convert into a C++ int */ value.long_value = PyLong_AsLong(tmp); Py_DECREF(tmp); /* Ensure return code was OK (to avoid out-of-range errors etc) */ return !(value.long_value == -1 && !PyErr_Occurred()); } /** * Conversion part 2 (C++ -> Python): convert an inty instance into * a Python object. The second and third arguments are used to * indicate the return value policy and parent object (for * ``return_value_policy::reference_internal``) and are generally * ignored by implicit casters. */ static handle cast(inty src, return_value_policy /* policy */, handle /* parent */) { return PyLong_FromLong(src.long_value); } }; }} // namespace PYBIND11_NAMESPACE::detail .. note:: A ``type_caster`` defined with ``PYBIND11_TYPE_CASTER(T, ...)`` requires that ``T`` is default-constructible (``value`` is first default constructed and then ``load()`` assigns to it). .. warning:: When using custom type casters, it's important to declare them consistently in every compilation unit of the Python extension module. Otherwise, undefined behavior can ensue. aoflagger-v3.4.0/external/pybind11/docs/advanced/cast/index.rst0000644000175000017500000000302414507760431023070 0ustar olesoles.. _type-conversions: Type conversions ################ Apart from enabling cross-language function calls, a fundamental problem that a binding tool like pybind11 must address is to provide access to native Python types in C++ and vice versa. There are three fundamentally different ways to do this—which approach is preferable for a particular type depends on the situation at hand. 1. Use a native C++ type everywhere. In this case, the type must be wrapped using pybind11-generated bindings so that Python can interact with it. 2. Use a native Python type everywhere. It will need to be wrapped so that C++ functions can interact with it. 3. Use a native C++ type on the C++ side and a native Python type on the Python side. pybind11 refers to this as a *type conversion*. Type conversions are the most "natural" option in the sense that native (non-wrapped) types are used everywhere. The main downside is that a copy of the data must be made on every Python ↔ C++ transition: this is needed since the C++ and Python versions of the same type generally won't have the same memory layout. pybind11 can perform many kinds of conversions automatically. An overview is provided in the table ":ref:`conversion_table`". The following subsections discuss the differences between these options in more detail. The main focus in this section is on type conversions, which represent the last case of the above list. .. toctree:: :maxdepth: 1 overview strings stl functional chrono eigen custom aoflagger-v3.4.0/external/pybind11/docs/advanced/exceptions.rst0000644000175000017500000004260414507760431023217 0ustar olesolesExceptions ########## Built-in C++ to Python exception translation ============================================ When Python calls C++ code through pybind11, pybind11 provides a C++ exception handler that will trap C++ exceptions, translate them to the corresponding Python exception, and raise them so that Python code can handle them. pybind11 defines translations for ``std::exception`` and its standard subclasses, and several special exception classes that translate to specific Python exceptions. Note that these are not actually Python exceptions, so they cannot be examined using the Python C API. Instead, they are pure C++ objects that pybind11 will translate the corresponding Python exception when they arrive at its exception handler. .. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| +--------------------------------------+--------------------------------------+ | Exception thrown by C++ | Translated to Python exception type | +======================================+======================================+ | :class:`std::exception` | ``RuntimeError`` | +--------------------------------------+--------------------------------------+ | :class:`std::bad_alloc` | ``MemoryError`` | +--------------------------------------+--------------------------------------+ | :class:`std::domain_error` | ``ValueError`` | +--------------------------------------+--------------------------------------+ | :class:`std::invalid_argument` | ``ValueError`` | +--------------------------------------+--------------------------------------+ | :class:`std::length_error` | ``ValueError`` | +--------------------------------------+--------------------------------------+ | :class:`std::out_of_range` | ``IndexError`` | +--------------------------------------+--------------------------------------+ | :class:`std::range_error` | ``ValueError`` | +--------------------------------------+--------------------------------------+ | :class:`std::overflow_error` | ``OverflowError`` | +--------------------------------------+--------------------------------------+ | :class:`pybind11::stop_iteration` | ``StopIteration`` (used to implement | | | custom iterators) | +--------------------------------------+--------------------------------------+ | :class:`pybind11::index_error` | ``IndexError`` (used to indicate out | | | of bounds access in ``__getitem__``, | | | ``__setitem__``, etc.) | +--------------------------------------+--------------------------------------+ | :class:`pybind11::key_error` | ``KeyError`` (used to indicate out | | | of bounds access in ``__getitem__``, | | | ``__setitem__`` in dict-like | | | objects, etc.) | +--------------------------------------+--------------------------------------+ | :class:`pybind11::value_error` | ``ValueError`` (used to indicate | | | wrong value passed in | | | ``container.remove(...)``) | +--------------------------------------+--------------------------------------+ | :class:`pybind11::type_error` | ``TypeError`` | +--------------------------------------+--------------------------------------+ | :class:`pybind11::buffer_error` | ``BufferError`` | +--------------------------------------+--------------------------------------+ | :class:`pybind11::import_error` | ``ImportError`` | +--------------------------------------+--------------------------------------+ | :class:`pybind11::attribute_error` | ``AttributeError`` | +--------------------------------------+--------------------------------------+ | Any other exception | ``RuntimeError`` | +--------------------------------------+--------------------------------------+ Exception translation is not bidirectional. That is, *catching* the C++ exceptions defined above will not trap exceptions that originate from Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below ` for further details. There is also a special exception :class:`cast_error` that is thrown by :func:`handle::call` when the input arguments cannot be converted to Python objects. Registering custom translators ============================== If the default exception conversion policy described above is insufficient, pybind11 also provides support for registering custom exception translators. Similar to pybind11 classes, exception translators can be local to the module they are defined in or global to the entire python session. To register a simple exception conversion that translates a C++ exception into a new Python exception using the C++ exception's ``what()`` method, a helper function is available: .. code-block:: cpp py::register_exception(module, "PyExp"); This call creates a Python exception class with the name ``PyExp`` in the given module and automatically converts any encountered exceptions of type ``CppExp`` into Python exceptions of type ``PyExp``. A matching function is available for registering a local exception translator: .. code-block:: cpp py::register_local_exception(module, "PyExp"); It is possible to specify base class for the exception using the third parameter, a ``handle``: .. code-block:: cpp py::register_exception(module, "PyExp", PyExc_RuntimeError); py::register_local_exception(module, "PyExp", PyExc_RuntimeError); Then ``PyExp`` can be caught both as ``PyExp`` and ``RuntimeError``. The class objects of the built-in Python exceptions are listed in the Python documentation on `Standard Exceptions `_. The default base class is ``PyExc_Exception``. When more advanced exception translation is needed, the functions ``py::register_exception_translator(translator)`` and ``py::register_local_exception_translator(translator)`` can be used to register functions that can translate arbitrary exception types (and which may include additional logic to do so). The functions takes a stateless callable (e.g. a function pointer or a lambda function without captured variables) with the call signature ``void(std::exception_ptr)``. When a C++ exception is thrown, the registered exception translators are tried in reverse order of registration (i.e. the last registered translator gets the first shot at handling the exception). All local translators will be tried before a global translator is tried. Inside the translator, ``std::rethrow_exception`` should be used within a try block to re-throw the exception. One or more catch clauses to catch the appropriate exceptions should then be used with each clause using ``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set the python exception to a custom exception type (see below). To declare a custom Python exception type, declare a ``py::exception`` variable and use this in the associated exception translator (note: it is often useful to make this a static declaration when using it inside a lambda expression without requiring capturing). The following example demonstrates this for a hypothetical exception classes ``MyCustomException`` and ``OtherException``: the first is translated to a custom python exception ``MyCustomError``, while the second is translated to a standard python RuntimeError: .. code-block:: cpp static py::exception exc(m, "MyCustomError"); py::register_exception_translator([](std::exception_ptr p) { try { if (p) std::rethrow_exception(p); } catch (const MyCustomException &e) { exc(e.what()); } catch (const OtherException &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); } }); Multiple exceptions can be handled by a single translator, as shown in the example above. If the exception is not caught by the current translator, the previously registered one gets a chance. If none of the registered exception translators is able to handle the exception, it is handled by the default converter as described in the previous section. .. seealso:: The file :file:`tests/test_exceptions.cpp` contains examples of various custom exception translators and custom exception types. .. note:: Call either ``PyErr_SetString`` or a custom exception's call operator (``exc(string)``) for every exception caught in a custom exception translator. Failure to do so will cause Python to crash with ``SystemError: error return without exception set``. Exceptions that you do not plan to handle should simply not be caught, or may be explicitly (re-)thrown to delegate it to the other, previously-declared existing exception translators. Note that ``libc++`` and ``libstdc++`` `behave differently under macOS `_ with ``-fvisibility=hidden``. Therefore exceptions that are used across ABI boundaries need to be explicitly exported, as exercised in ``tests/test_exceptions.h``. See also: "Problems with C++ exceptions" under `GCC Wiki `_. Local vs Global Exception Translators ===================================== When a global exception translator is registered, it will be applied across all modules in the reverse order of registration. This can create behavior where the order of module import influences how exceptions are translated. If module1 has the following translator: .. code-block:: cpp py::register_exception_translator([](std::exception_ptr p) { try { if (p) std::rethrow_exception(p); } catch (const std::invalid_argument &e) { PyErr_SetString("module1 handled this") } } and module2 has the following similar translator: .. code-block:: cpp py::register_exception_translator([](std::exception_ptr p) { try { if (p) std::rethrow_exception(p); } catch (const std::invalid_argument &e) { PyErr_SetString("module2 handled this") } } then which translator handles the invalid_argument will be determined by the order that module1 and module2 are imported. Since exception translators are applied in the reverse order of registration, which ever module was imported last will "win" and that translator will be applied. If there are multiple pybind11 modules that share exception types (either standard built-in or custom) loaded into a single python instance and consistent error handling behavior is needed, then local translators should be used. Changing the previous example to use ``register_local_exception_translator`` would mean that when invalid_argument is thrown in the module2 code, the module2 translator will always handle it, while in module1, the module1 translator will do the same. .. _handling_python_exceptions_cpp: Handling exceptions from Python in C++ ====================================== When C++ calls Python functions, such as in a callback function or when manipulating Python objects, and Python raises an ``Exception``, pybind11 converts the Python exception into a C++ exception of type :class:`pybind11::error_already_set` whose payload contains a C++ string textual summary and the actual Python exception. ``error_already_set`` is used to propagate Python exception back to Python (or possibly, handle them in C++). .. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| +--------------------------------------+--------------------------------------+ | Exception raised in Python | Thrown as C++ exception type | +======================================+======================================+ | Any Python ``Exception`` | :class:`pybind11::error_already_set` | +--------------------------------------+--------------------------------------+ For example: .. code-block:: cpp try { // open("missing.txt", "r") auto file = py::module_::import("io").attr("open")("missing.txt", "r"); auto text = file.attr("read")(); file.attr("close")(); } catch (py::error_already_set &e) { if (e.matches(PyExc_FileNotFoundError)) { py::print("missing.txt not found"); } else if (e.matches(PyExc_PermissionError)) { py::print("missing.txt found but not accessible"); } else { throw; } } Note that C++ to Python exception translation does not apply here, since that is a method for translating C++ exceptions to Python, not vice versa. The error raised from Python is always ``error_already_set``. This example illustrates this behavior: .. code-block:: cpp try { py::eval("raise ValueError('The Ring')"); } catch (py::value_error &boromir) { // Boromir never gets the ring assert(false); } catch (py::error_already_set &frodo) { // Frodo gets the ring py::print("I will take the ring"); } try { // py::value_error is a request for pybind11 to raise a Python exception throw py::value_error("The ball"); } catch (py::error_already_set &cat) { // cat won't catch the ball since // py::value_error is not a Python exception assert(false); } catch (py::value_error &dog) { // dog will catch the ball py::print("Run Spot run"); throw; // Throw it again (pybind11 will raise ValueError) } Handling errors from the Python C API ===================================== Where possible, use :ref:`pybind11 wrappers ` instead of calling the Python C API directly. When calling the Python C API directly, in addition to manually managing reference counts, one must follow the pybind11 error protocol, which is outlined here. After calling the Python C API, if Python returns an error, ``throw py::error_already_set();``, which allows pybind11 to deal with the exception and pass it back to the Python interpreter. This includes calls to the error setting functions such as ``PyErr_SetString``. .. code-block:: cpp PyErr_SetString(PyExc_TypeError, "C API type error demo"); throw py::error_already_set(); // But it would be easier to simply... throw py::type_error("pybind11 wrapper type error"); Alternately, to ignore the error, call `PyErr_Clear `_. Any Python error must be thrown or cleared, or Python/pybind11 will be left in an invalid state. Chaining exceptions ('raise from') ================================== Python has a mechanism for indicating that exceptions were caused by other exceptions: .. code-block:: py try: print(1 / 0) except Exception as exc: raise RuntimeError("could not divide by zero") from exc To do a similar thing in pybind11, you can use the ``py::raise_from`` function. It sets the current python error indicator, so to continue propagating the exception you should ``throw py::error_already_set()``. .. code-block:: cpp try { py::eval("print(1 / 0")); } catch (py::error_already_set &e) { py::raise_from(e, PyExc_RuntimeError, "could not divide by zero"); throw py::error_already_set(); } .. versionadded:: 2.8 .. _unraisable_exceptions: Handling unraisable exceptions ============================== If a Python function invoked from a C++ destructor or any function marked ``noexcept(true)`` (collectively, "noexcept functions") throws an exception, there is no way to propagate the exception, as such functions may not throw. Should they throw or fail to catch any exceptions in their call graph, the C++ runtime calls ``std::terminate()`` to abort immediately. Similarly, Python exceptions raised in a class's ``__del__`` method do not propagate, but are logged by Python as an unraisable error. In Python 3.8+, a `system hook is triggered `_ and an auditing event is logged. Any noexcept function should have a try-catch block that traps class:`error_already_set` (or any other exception that can occur). Note that pybind11 wrappers around Python exceptions such as :class:`pybind11::value_error` are *not* Python exceptions; they are C++ exceptions that pybind11 catches and converts to Python exceptions. Noexcept functions cannot propagate these exceptions either. A useful approach is to convert them to Python exceptions and then ``discard_as_unraisable`` as shown below. .. code-block:: cpp void nonthrowing_func() noexcept(true) { try { // ... } catch (py::error_already_set &eas) { // Discard the Python error using Python APIs, using the C++ magic // variable __func__. Python already knows the type and value and of the // exception object. eas.discard_as_unraisable(__func__); } catch (const std::exception &e) { // Log and discard C++ exceptions. third_party::log(e); } } .. versionadded:: 2.6 aoflagger-v3.4.0/external/pybind11/docs/advanced/misc.rst0000644000175000017500000003644314507760431021775 0ustar olesolesMiscellaneous ############# .. _macro_notes: General notes regarding convenience macros ========================================== pybind11 provides a few convenience macros such as :func:`PYBIND11_DECLARE_HOLDER_TYPE` and ``PYBIND11_OVERRIDE_*``. Since these are "just" macros that are evaluated in the preprocessor (which has no concept of types), they *will* get confused by commas in a template argument; for example, consider: .. code-block:: cpp PYBIND11_OVERRIDE(MyReturnType, Class, func) The limitation of the C preprocessor interprets this as five arguments (with new arguments beginning after each comma) rather than three. To get around this, there are two alternatives: you can use a type alias, or you can wrap the type using the ``PYBIND11_TYPE`` macro: .. code-block:: cpp // Version 1: using a type alias using ReturnType = MyReturnType; using ClassType = Class; PYBIND11_OVERRIDE(ReturnType, ClassType, func); // Version 2: using the PYBIND11_TYPE macro: PYBIND11_OVERRIDE(PYBIND11_TYPE(MyReturnType), PYBIND11_TYPE(Class), func) The ``PYBIND11_MAKE_OPAQUE`` macro does *not* require the above workarounds. .. _gil: Global Interpreter Lock (GIL) ============================= The Python C API dictates that the Global Interpreter Lock (GIL) must always be held by the current thread to safely access Python objects. As a result, when Python calls into C++ via pybind11 the GIL must be held, and pybind11 will never implicitly release the GIL. .. code-block:: cpp void my_function() { /* GIL is held when this function is called from Python */ } PYBIND11_MODULE(example, m) { m.def("my_function", &my_function); } pybind11 will ensure that the GIL is held when it knows that it is calling Python code. For example, if a Python callback is passed to C++ code via ``std::function``, when C++ code calls the function the built-in wrapper will acquire the GIL before calling the Python callback. Similarly, the ``PYBIND11_OVERRIDE`` family of macros will acquire the GIL before calling back into Python. When writing C++ code that is called from other C++ code, if that code accesses Python state, it must explicitly acquire and release the GIL. The classes :class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be used to acquire and release the global interpreter lock in the body of a C++ function call. In this way, long-running C++ code can be parallelized using multiple Python threads, **but great care must be taken** when any :class:`gil_scoped_release` appear: if there is any way that the C++ code can access Python objects, :class:`gil_scoped_acquire` should be used to reacquire the GIL. Taking :ref:`overriding_virtuals` as an example, this could be realized as follows (important changes highlighted): .. code-block:: cpp :emphasize-lines: 8,30,31 class PyAnimal : public Animal { public: /* Inherit the constructors */ using Animal::Animal; /* Trampoline (need one for each virtual function) */ std::string go(int n_times) { /* PYBIND11_OVERRIDE_PURE will acquire the GIL before accessing Python state */ PYBIND11_OVERRIDE_PURE( std::string, /* Return type */ Animal, /* Parent class */ go, /* Name of function */ n_times /* Argument(s) */ ); } }; PYBIND11_MODULE(example, m) { py::class_ animal(m, "Animal"); animal .def(py::init<>()) .def("go", &Animal::go); py::class_(m, "Dog", animal) .def(py::init<>()); m.def("call_go", [](Animal *animal) -> std::string { // GIL is held when called from Python code. Release GIL before // calling into (potentially long-running) C++ code py::gil_scoped_release release; return call_go(animal); }); } The ``call_go`` wrapper can also be simplified using the ``call_guard`` policy (see :ref:`call_policies`) which yields the same result: .. code-block:: cpp m.def("call_go", &call_go, py::call_guard()); Common Sources Of Global Interpreter Lock Errors ================================================================== Failing to properly hold the Global Interpreter Lock (GIL) is one of the more common sources of bugs within code that uses pybind11. If you are running into GIL related errors, we highly recommend you consult the following checklist. - Do you have any global variables that are pybind11 objects or invoke pybind11 functions in either their constructor or destructor? You are generally not allowed to invoke any Python function in a global static context. We recommend using lazy initialization and then intentionally leaking at the end of the program. - Do you have any pybind11 objects that are members of other C++ structures? One commonly overlooked requirement is that pybind11 objects have to increase their reference count whenever their copy constructor is called. Thus, you need to be holding the GIL to invoke the copy constructor of any C++ class that has a pybind11 member. This can sometimes be very tricky to track for complicated programs Think carefully when you make a pybind11 object a member in another struct. - C++ destructors that invoke Python functions can be particularly troublesome as destructors can sometimes get invoked in weird and unexpected circumstances as a result of exceptions. - You should try running your code in a debug build. That will enable additional assertions within pybind11 that will throw exceptions on certain GIL handling errors (reference counting operations). Binding sequence data types, iterators, the slicing protocol, etc. ================================================================== Please refer to the supplemental example for details. .. seealso:: The file :file:`tests/test_sequences_and_iterators.cpp` contains a complete example that shows how to bind a sequence data type, including length queries (``__len__``), iterators (``__iter__``), the slicing protocol and other kinds of useful operations. Partitioning code over multiple extension modules ================================================= It's straightforward to split binding code over multiple extension modules, while referencing types that are declared elsewhere. Everything "just" works without any special precautions. One exception to this rule occurs when extending a type declared in another extension module. Recall the basic example from Section :ref:`inheritance`. .. code-block:: cpp py::class_ pet(m, "Pet"); pet.def(py::init()) .def_readwrite("name", &Pet::name); py::class_(m, "Dog", pet /* <- specify parent */) .def(py::init()) .def("bark", &Dog::bark); Suppose now that ``Pet`` bindings are defined in a module named ``basic``, whereas the ``Dog`` bindings are defined somewhere else. The challenge is of course that the variable ``pet`` is not available anymore though it is needed to indicate the inheritance relationship to the constructor of ``class_``. However, it can be acquired as follows: .. code-block:: cpp py::object pet = (py::object) py::module_::import("basic").attr("Pet"); py::class_(m, "Dog", pet) .def(py::init()) .def("bark", &Dog::bark); Alternatively, you can specify the base class as a template parameter option to ``class_``, which performs an automated lookup of the corresponding Python type. Like the above code, however, this also requires invoking the ``import`` function once to ensure that the pybind11 binding code of the module ``basic`` has been executed: .. code-block:: cpp py::module_::import("basic"); py::class_(m, "Dog") .def(py::init()) .def("bark", &Dog::bark); Naturally, both methods will fail when there are cyclic dependencies. Note that pybind11 code compiled with hidden-by-default symbol visibility (e.g. via the command line flag ``-fvisibility=hidden`` on GCC/Clang), which is required for proper pybind11 functionality, can interfere with the ability to access types defined in another extension module. Working around this requires manually exporting types that are accessed by multiple extension modules; pybind11 provides a macro to do just this: .. code-block:: cpp class PYBIND11_EXPORT Dog : public Animal { ... }; Note also that it is possible (although would rarely be required) to share arbitrary C++ objects between extension modules at runtime. Internal library data is shared between modules using capsule machinery [#f6]_ which can be also utilized for storing, modifying and accessing user-defined data. Note that an extension module will "see" other extensions' data if and only if they were built with the same pybind11 version. Consider the following example: .. code-block:: cpp auto data = reinterpret_cast(py::get_shared_data("mydata")); if (!data) data = static_cast(py::set_shared_data("mydata", new MyData(42))); If the above snippet was used in several separately compiled extension modules, the first one to be imported would create a ``MyData`` instance and associate a ``"mydata"`` key with a pointer to it. Extensions that are imported later would be then able to access the data behind the same pointer. .. [#f6] https://docs.python.org/3/extending/extending.html#using-capsules Module Destructors ================== pybind11 does not provide an explicit mechanism to invoke cleanup code at module destruction time. In rare cases where such functionality is required, it is possible to emulate it using Python capsules or weak references with a destruction callback. .. code-block:: cpp auto cleanup_callback = []() { // perform cleanup here -- this function is called with the GIL held }; m.add_object("_cleanup", py::capsule(cleanup_callback)); This approach has the potential downside that instances of classes exposed within the module may still be alive when the cleanup callback is invoked (whether this is acceptable will generally depend on the application). Alternatively, the capsule may also be stashed within a type object, which ensures that it not called before all instances of that type have been collected: .. code-block:: cpp auto cleanup_callback = []() { /* ... */ }; m.attr("BaseClass").attr("_cleanup") = py::capsule(cleanup_callback); Both approaches also expose a potentially dangerous ``_cleanup`` attribute in Python, which may be undesirable from an API standpoint (a premature explicit call from Python might lead to undefined behavior). Yet another approach that avoids this issue involves weak reference with a cleanup callback: .. code-block:: cpp // Register a callback function that is invoked when the BaseClass object is collected py::cpp_function cleanup_callback( [](py::handle weakref) { // perform cleanup here -- this function is called with the GIL held weakref.dec_ref(); // release weak reference } ); // Create a weak reference with a cleanup callback and initially leak it (void) py::weakref(m.attr("BaseClass"), cleanup_callback).release(); .. note:: PyPy does not garbage collect objects when the interpreter exits. An alternative approach (which also works on CPython) is to use the :py:mod:`atexit` module [#f7]_, for example: .. code-block:: cpp auto atexit = py::module_::import("atexit"); atexit.attr("register")(py::cpp_function([]() { // perform cleanup here -- this function is called with the GIL held })); .. [#f7] https://docs.python.org/3/library/atexit.html Generating documentation using Sphinx ===================================== Sphinx [#f4]_ has the ability to inspect the signatures and documentation strings in pybind11-based extension modules to automatically generate beautiful documentation in a variety formats. The python_example repository [#f5]_ contains a simple example repository which uses this approach. There are two potential gotchas when using this approach: first, make sure that the resulting strings do not contain any :kbd:`TAB` characters, which break the docstring parsing routines. You may want to use C++11 raw string literals, which are convenient for multi-line comments. Conveniently, any excess indentation will be automatically be removed by Sphinx. However, for this to work, it is important that all lines are indented consistently, i.e.: .. code-block:: cpp // ok m.def("foo", &foo, R"mydelimiter( The foo function Parameters ---------- )mydelimiter"); // *not ok* m.def("foo", &foo, R"mydelimiter(The foo function Parameters ---------- )mydelimiter"); By default, pybind11 automatically generates and prepends a signature to the docstring of a function registered with ``module_::def()`` and ``class_::def()``. Sometimes this behavior is not desirable, because you want to provide your own signature or remove the docstring completely to exclude the function from the Sphinx documentation. The class ``options`` allows you to selectively suppress auto-generated signatures: .. code-block:: cpp PYBIND11_MODULE(example, m) { py::options options; options.disable_function_signatures(); m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers"); } pybind11 also appends all members of an enum to the resulting enum docstring. This default behavior can be disabled by using the ``disable_enum_members_docstring()`` function of the ``options`` class. With ``disable_user_defined_docstrings()`` all user defined docstrings of ``module_::def()``, ``class_::def()`` and ``enum_()`` are disabled, but the function signatures and enum members are included in the docstring, unless they are disabled separately. Note that changes to the settings affect only function bindings created during the lifetime of the ``options`` instance. When it goes out of scope at the end of the module's init function, the default settings are restored to prevent unwanted side effects. .. [#f4] http://www.sphinx-doc.org .. [#f5] http://github.com/pybind/python_example .. _avoiding-cpp-types-in-docstrings: Avoiding C++ types in docstrings ================================ Docstrings are generated at the time of the declaration, e.g. when ``.def(...)`` is called. At this point parameter and return types should be known to pybind11. If a custom type is not exposed yet through a ``py::class_`` constructor or a custom type caster, its C++ type name will be used instead to generate the signature in the docstring: .. code-block:: text | __init__(...) | __init__(self: example.Foo, arg0: ns::Bar) -> None ^^^^^^^ This limitation can be circumvented by ensuring that C++ classes are registered with pybind11 before they are used as a parameter or return type of a function: .. code-block:: cpp PYBIND11_MODULE(example, m) { auto pyFoo = py::class_(m, "Foo"); auto pyBar = py::class_(m, "Bar"); pyFoo.def(py::init()); pyBar.def(py::init()); } aoflagger-v3.4.0/external/pybind11/docs/benchmark.rst0000644000175000017500000000614014507760431021216 0ustar olesolesBenchmark ========= The following is the result of a synthetic benchmark comparing both compilation time and module size of pybind11 against Boost.Python. A detailed report about a Boost.Python to pybind11 conversion of a real project is available here: [#f1]_. .. [#f1] http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf Setup ----- A python script (see the ``docs/benchmark.py`` file) was used to generate a set of files with dummy classes whose count increases for each successive benchmark (between 1 and 2048 classes in powers of two). Each class has four methods with a randomly generated signature with a return value and four arguments. (There was no particular reason for this setup other than the desire to generate many unique function signatures whose count could be controlled in a simple way.) Here is an example of the binding code for one class: .. code-block:: cpp ... class cl034 { public: cl279 *fn_000(cl084 *, cl057 *, cl065 *, cl042 *); cl025 *fn_001(cl098 *, cl262 *, cl414 *, cl121 *); cl085 *fn_002(cl445 *, cl297 *, cl145 *, cl421 *); cl470 *fn_003(cl200 *, cl323 *, cl332 *, cl492 *); }; ... PYBIND11_MODULE(example, m) { ... py::class_(m, "cl034") .def("fn_000", &cl034::fn_000) .def("fn_001", &cl034::fn_001) .def("fn_002", &cl034::fn_002) .def("fn_003", &cl034::fn_003) ... } The Boost.Python version looks almost identical except that a return value policy had to be specified as an argument to ``def()``. For both libraries, compilation was done with .. code-block:: bash Apple LLVM version 7.0.2 (clang-700.1.81) and the following compilation flags .. code-block:: bash g++ -Os -shared -rdynamic -undefined dynamic_lookup -fvisibility=hidden -std=c++14 Compilation time ---------------- The following log-log plot shows how the compilation time grows for an increasing number of class and function declarations. pybind11 includes many fewer headers, which initially leads to shorter compilation times, but the performance is ultimately fairly similar (pybind11 is 19.8 seconds faster for the largest largest file with 2048 classes and a total of 8192 methods -- a modest **1.2x** speedup relative to Boost.Python, which required 116.35 seconds). .. only:: not latex .. image:: pybind11_vs_boost_python1.svg .. only:: latex .. image:: pybind11_vs_boost_python1.png Module size ----------- Differences between the two libraries become much more pronounced when considering the file size of the generated Python plugin: for the largest file, the binary generated by Boost.Python required 16.8 MiB, which was **2.17 times** / **9.1 megabytes** larger than the output generated by pybind11. For very small inputs, Boost.Python has an edge in the plot below -- however, note that it stores many definitions in an external library, whose size was not included here, hence the comparison is slightly shifted in Boost.Python's favor. .. only:: not latex .. image:: pybind11_vs_boost_python2.svg .. only:: latex .. image:: pybind11_vs_boost_python2.png aoflagger-v3.4.0/external/pybind11/docs/benchmark.py0000644000175000017500000000545014507760431021041 0ustar olesolesimport datetime as dt import os import random nfns = 4 # Functions per class nargs = 4 # Arguments per function def generate_dummy_code_pybind11(nclasses=10): decl = "" bindings = "" for cl in range(nclasses): decl += f"class cl{cl:03};\n" decl += "\n" for cl in range(nclasses): decl += f"class {cl:03} {{\n" decl += "public:\n" bindings += f' py::class_(m, "cl{cl:03}")\n' for fn in range(nfns): ret = random.randint(0, nclasses - 1) params = [random.randint(0, nclasses - 1) for i in range(nargs)] decl += f" cl{ret:03} *fn_{fn:03}(" decl += ", ".join(f"cl{p:03} *" for p in params) decl += ");\n" bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03})\n' decl += "};\n\n" bindings += " ;\n" result = "#include \n\n" result += "namespace py = pybind11;\n\n" result += decl + "\n" result += "PYBIND11_MODULE(example, m) {\n" result += bindings result += "}" return result def generate_dummy_code_boost(nclasses=10): decl = "" bindings = "" for cl in range(nclasses): decl += f"class cl{cl:03};\n" decl += "\n" for cl in range(nclasses): decl += "class cl%03i {\n" % cl decl += "public:\n" bindings += f' py::class_("cl{cl:03}")\n' for fn in range(nfns): ret = random.randint(0, nclasses - 1) params = [random.randint(0, nclasses - 1) for i in range(nargs)] decl += f" cl{ret:03} *fn_{fn:03}(" decl += ", ".join(f"cl{p:03} *" for p in params) decl += ");\n" bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03}, py::return_value_policy())\n' decl += "};\n\n" bindings += " ;\n" result = "#include \n\n" result += "namespace py = boost::python;\n\n" result += decl + "\n" result += "BOOST_PYTHON_MODULE(example) {\n" result += bindings result += "}" return result for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: print("{") for i in range(0, 10): nclasses = 2**i with open("test.cpp", "w") as f: f.write(codegen(nclasses)) n1 = dt.datetime.now() os.system( "g++ -Os -shared -rdynamic -undefined dynamic_lookup " "-fvisibility=hidden -std=c++14 test.cpp -I include " "-I /System/Library/Frameworks/Python.framework/Headers -o test.so" ) n2 = dt.datetime.now() elapsed = (n2 - n1).total_seconds() size = os.stat("test.so").st_size print(" {%i, %f, %i}," % (nclasses * nfns, elapsed, size)) print("}") aoflagger-v3.4.0/external/pybind11/docs/pybind11-logo.png0000644000175000017500000016715214507760431021640 0ustar olesoles‰PNG  IHDRkP¬óTzTXtRaw profile type exifxÚ­šg²$9r„ÿç)x¨€8N@™ñ<>?Ϫ#–»cÆ~ÓýTU&áá9ÏùŸÿ¾Ïñ§Œžb­×QkàOe$ç‹>Æûo åý÷ýSçû¾ÿÃÏûñeâsæsþü¢ùçst~n¿ÞðãqþñçOÿþ&õï…¾¿øqÁ¬;'¾Ø¿/’Ÿ§ÏÏcù^hœï’Go¿/u¦Ïçõ}á»”ïßÜÞKÿ¼ˆ¾~ÿAiTi¯Ê)sxÿ-ŸäÏ_×Ïù7å¨×ñá|Ÿ>•üc¯äÛûñ9„ß ô‡"ÿøêùsõËúþúOÅOþ}EþS-ë·F|ñ·¿ˆö÷ÅKüÛóÏ¥?ýâÄô—í|ÿÞ»û½ç³;/•ŠÖ/¢Âó£:z/œl.¿o«|4þ_·÷cðу‡EsvXaò±âˆ‰êß'–¸£ÇÏûyÅÅK:©ñ9¥Esô³ž[iѺ¨xSË#ïÜéÛJçÉ™§Ÿk‰ï}Ç{¿;wÞ‘—¦ÈÅâÛìññü_¿ü'ϽêwŒ*&­Ÿ'œe¨sú—WÑx¿}³·À?>¾í¿ ¨ÒA{ËÜÙ ‡ù¹Ä´ø [ùísæuÆç/u/ÿì®É_|ˆl<6trVrÎàâ + ­ h´0œÁ…|±‰i°Ä|@çTÃûHmKÒ#s¡^œù£E*L»pBHèj]k!‰¯Ý¤Ö_èäøk@:Y me,c°'dÒÇõwt(üL)Lº]͛߮¦/c~ Kù)wfÐ £8X.ºŽ¤\6Ðr]èPÊ ëPÑäž&×ï)z}¡¢rÒÈg ôÉV®lƒÔ{ÚÕý?Ña¡Mé)„8öjY}¶wÞœµõôSðˆ«¶Èv^ކ÷7ò2ŒF%P×®¹|R·çuÝ z¨WDö9g˜¨ÚØË»YoŒðd‡—R4à ˆq_6–¨•DP 3*ŠRâ°ÏDŽ7{õÈïà(ÈæÀ¬ í¹ÂµÁÓ¾ ô88œIV"¿¸Hxâ–2N’1/Ð÷ÍÌfR2†•&.ÂE@ Ud‡ÂXÇËPõƒGè‡a ¬XÉtNC§)Ü>°Àº¼Èajˆ ¼-4„ð³Œlkj÷LAx¶F­©˜¸CÈŒ5˜T³ùÈ‚$ˆ¯c0&âpµp « ¾hWêä5&0rWþÇeÒCl €îcA)+ò6„FŠi »—(óe9ÞZ4ïöBÉëˆ$õ{P0l)ìû>±õ»6L¸šìIÇ).¼øœâl­? èâ¯.Ž˜©†ýñ…›0°5'ô³a6j÷¬ð ö*ß÷Ýæ€¨îôõNcÖ03¨&ÖÐȽMRÇÛ·K»§k$^‰ÂOoæð°¤˜Ë<7 aîPí @gæcáíÉZ1A{hÞ‚}±¡R% â046ò[ÆÇ­€¤¦²¬5Ÿ¤†Ë|±_à ]Æ\Ú€Z¤oví?†{7ÀœT'1Þ˜¼¸ÚSro’dxWbo% õéõ®¨ ­ö7œ·ÀÉ®ä½Q\Å„éŒ9.ã‘@ÍY±È›ˆr§ïZã¬%õ!´;E×i—Z‡WšV›Þ(3>8N°‡b“¸ÄFí‡xÛoÛ'ËÏIÝNsœ%3ßÖÔaÜP`tšŒNœ¨ AT±Wb£0.æ/ÜD™[‘#†ÈÁžò¹pf‚ψü™Òú(wÀoj×dQ€fùÅ:ýÁæAäL9Uƒj˜-}ƒF…ðàr‘c˜)vÆ Æ` ‰Á† ùQûÄ@Ã|@Æ©‡”yR\Á…”IGøÏÝ|¡ÏÔ%º–_ü®PÍ€æGUˆ«”m21Ò`AYâ&Ššb,6€XˆuƒÚôL Wo¶F©‰D:÷ × >rÛÓa=ɤ˜Ãã¯ÖIúø üc(ò3 UÞ‹ÑíÉಠnŒÄŒ7G²QpEð‹úB**ð(îŽÈî.³â:â'$jé sÔͽ©€zlLÀï '\œàg˜AT‘ a qËû-é#C=‘Œé(&ëp`"šC§S˜E \TüüàÝÃ[ iCmô†Ò+;)dÁ”¸–«š5ò'OªÀ»ìç’ ‡Uqj“Î+F¢×$fZ_&‰U37uÅÕÌ-Ê…øÈÜÐ/Ôzz]HN ý!ˆPÇUR¸ØÔ9UYÞ'I¨“™@ )p¼é³~6bÑ_z‹ÅÙö¨Ë¾6Þ&`þ¡"Dxo‘ ë×c—Ôk0¶p–D ïî-׎1ÃðÂzpõ&ïhá”ÙIJÿ KI'voÜQ#9­HB"©ÐØBþ«9Ö âõ¡9ž¤‰x˜rGzÃYH€¥ðfxgŠB€ƒÜ¯ÜÎuU›a‡rðøõa=ƒ5:†2R@‡N:‚‰ M&±â=ñº6u>8"ƒBÁÉ‘O.Ï;>â ¬ŠkÐ !»°‹€›Šõ$YC ˜€@ðÆÎÁÀ9MùñrÈW¶mt¾¶&®Ø gLÀÊž_ïq‰W§qqã°øºv‹?f¦ ü• g‚Dù©22ýY'5Ÿy˜äèfè Ø„Q—àËIéŠ FÌ9¦ˆr!6"0+ó ,Œâ#¿¡ SR8²@ ÅÐ`Âê°‹¿#ZÞžàª&dSð Lt¤Ò-no¬ÃmÖ`bë:Àc€žð!cñ½ö ×^Ó³¡™!_Ô¢ WDݳ›\o£¢l¤=íQ:õL7B* ³¥(™aÀ¦ÓCÑ5ã\if(1'5áƒ1tõïb­1u÷Ø O«*uŸNðÛ,”ÔMUPÌJ‘ïÛ”¶¤€d:²ŸŠ3$ñ-ŒÐE!\Õ§çJZb3~A–›ìˆË“ùtPAÔeï”Ît¾BÐ*Œ!9DNœÒà!Iü(ØÑk=DøntVžnˆábéxà¶£ôLÅÒÇGœ¡ ߇LæÜ™ù¼ÝÁª^›”%³vpÛ“ñWþŒL"ƒ½^Þ'Ð#q¦q}Þzöƒ;EÓõdN › F©yÎ(=w èD¿ tÌ:âvB[Âí2˜E(•Š1£ Ü (Ý[@áÀWÀ—í­çÖ k…™ž¢ÇZšãÀÀWOȸ[jX„ «Ê)0‚¤CØwƒµ2{©:i€ž!uÅ®‡³|5 P¤E\ÈáÂG#ðÌpž“ëÈtêœñ ÉXøO¤(µåfÆä¿ÖËÑþº'¡íêÄ*18:­Ä60Žm8…i(¿ N22T !öçCR%("ôÁBÎ%2NÚ°Ä~E) Ž„’Anä6ä€àµb©|ŒÓcøöUˆÚèµè•oÐÿšg†žÞ*¬×“`-t~ˆÍ£§Åñó#Ï[R±ž@RI'“e/ >Z5Ý”NôtnˆÕ¨Õ(ZHx?¡Ü` pŠ¥ìl’Õ@‚A ( ªÊ€ »ˆ #£ID½L j5éñ*yͶŸDW&¯ ²®Sέ•60@ Ý!Í.ÄÇADÔ‰Ò‘Ï2.s9c:9]ÓɆ·êìèw.V€Á É üpQ¹0 Ô$‚~ñÃèŸÜFá‘ ôÀ(D?z|ÆâmUf Š”pÒ[ „« ¾ÉÌã–TTô¸(›I)àl¨)½Ï®é=3@M :ÇNH»{ÒÓ/ vñ .G…‹òµºµ%+Ï+=:Jó|Ùq&“ùÅp·€11º"¦8Ñ 9ÓYŠ¥Ž)Rzêw ÆV©êÁ`ãØ¨)j€¿ì)®|d÷u,J–E_p,žM6cš¨%Ó³ Ì#;@n`†7øÂàä%lw”™IÜM‡ñ|Ýt²æ‹?ê4 Ÿ˜yC沩ŒÆý=òÃïTX$b¢q5xÚ+£ŒØXbaÉC:+´[#y„H ÄC ÂÚ )‚3krˆM‡}tØõH€±FÂ÷BKe#2,û>׉Ò5Ž;,=© D=%šDþm+:ž!Ô—÷8Þ‰ì\†BÇ\ÕëÄŒ"ºÊ1›)àcЦóå=´.:§?”…qG8ßÿ¬cÜNÓƒŽ›ual½ž+·¬“L’,âè²VWXÔÎwf‡ÝfÚ„VŒ_{郄lÜõ ’°6WÆ_oÒœ,ñF€_Õ Â]2A !dÀ¬§9P0ï¢áƒ`¡‘T]¡Œ |3¬f}ú{ž±Hu0 ÜJ.V½¡Cr.>Zð„î¾j;žÌ™Ž`pÖØ‰-ßzV¿tصžž)“¡a¸ß MÍ÷¤E)?/ ƒ§ú ÂÏÞYÅÀ,g@àbËà—)³EdÔ›Ž¡©«Î‚¦ ˆéa4§áÈýÑ@(]`ÂIÂ^—‚!Æe¾ ‘_ù+áBrÕÿ£‘§á[]‰2}Ÿ­vOä€<#ØLä& B/A±V,(V³Ñ-=ö\òóèmÑQxÇîTY`ÍšÕ‡ÇïøPúÕéšÎ”5tdÂädE^–½¦žAa)oÖñ¼™Æ÷J[µXŒ@‰f%cc ÙøùѨA¦¡›¬¯}ö±‰Q å«ë¤‹ðîÌŠùw¦ÿñç篿€gîÏÿ¡üoŸâÑo¤iCCPICC profilexœ}‘M(DQ†ƒHda’dqÊ’%CIšåoáÞ;¿5÷šîÙX*Û) ?ƒ…5[ [¥”Ÿ’•¥±Ñt}gfj&§Nçé=çýú¾÷€/Ÿ6-·a,;ëD¦ƒÚâÒ²ÖôJ ø€~Ýt3ápˆšëëž:uÞ ¨Zµßý¹Ú¢1ׄ:MxÜÌ8Yá5áÑÍlFñ¾°ßLêQásÕ# ?*Ý(ñ›âD‘UËøùȤ°_XKT±QÅfÒ±„G„QË–ú¾ÅGo)¶Òf¹O5akÌ^˜Sºì¦™a–0¤H“e@N[—ˆÜkø»‹þ°¸ q¥0Å1Å:zÑúƒßÙºñá¡R¥Ö 4¾xÞG/4íB!çyßÇžW8úg¸²+þõ<Œ}Šž«h#h߆‹ëŠfìÁåt=etG/Jõ²}ñ8¼ŸÉ7-AÇ-´¬”r+ßsúó’Uè¡/!µWkÌÝ\Û¿oÊùý-r‹˜½ÔÐbKGD S†) pHYs  šœtIMEä -µ8 IDATxÚì½yx[õö}Kçh_í¬dÁ&+„€-$m-ÚJ[°é …ÖJZºÍtâÎômàš^gfž§¡o§13ó4]¦DžIÛ™gè Lfúvš¶QJh!Ø&ˆœØY,9ÞäEzÿÐÑñщlI¶u´ÝŸë2ÈŽlIç·~ïóýÞ?€B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„Bf/!„B4 @-7€Å¿uè¾üB¼d„B!„B!³‹€qá%–å—€——B!„B!dæÔ {&ÕWñ¬B!„²eP„B™MZlSÿ°ªª ÕÕÕðx<ò¿„B!tvv¦ú»Ï´ òB!„B!„¤Ç¸ßLRfL]]]ìÙgŸeC{{{¬©©)U–MñÒ*B!„B!„2×5UUU±Äf©S§b ©D//9!„BJ–ABHùP+Õù –¯”*nÄýiäÓšššÐÚÚ ·{vº›ÏçCss3Âá°òÇ›7/&„\âÉãkw€'ãB!„”<ÌŽáët¾ZxùK–¤Œš;wÆrA{{{Ìår©ûU-/?!$‡¸ó¸nÆÀ²OB!„² ŸNžæSš´*Ûy÷îݱ\’B° !Ùb„ÒǓ絓Rƈ¼„RÈ.— µµ¹OH8xð òÛ6AI1[ß455Áëõæ¶×Ö"`ݺurwF¼Šb !$Wó€ø‰vÕÕÕ9}±P(¤< ¯“—ŸB!¤ôñBq:O®iooWg?ÒC.ª©©‰iÉÎ;Y*@Ñ?r\â©dÛ¶mÊyÍÇËOHy£ç% „²@N¥ñxr×vtt¨ƒzRZx¡0öù´)š››QWW§üQ ›„’˵S‹ŒT®„%k!„Î\o8¼ü%‡7ñ ©©I“>¥¦¥¥Eùmh6L™]ܪßðF!„BÉrjõ©S§ržÊ]WWGsáÒ¥Zëþ”a?keÓBf4,õìíí¥¹0!$ fÖBHé“d.œkƒD€æÂ%Ž,¾ÕÕÕiÒŸ&CehLQ2›xäETûŒTš B(ÖBHϨ0€ › ¤E‘ÆÆüê#*±¦ ,…"„éÚ’–R^~BÅB)£ 'kîÉ,P§eJûf’†)ÖBf}í¤¹0!$P¬!„n8s¹á ðò—U›mD%U³‰!³4×Ñ\˜’W(ÖBHéS§epÍ gI#w UF !„”ä\WSS“ó …BèêêRþ(À& „P¬!„2Ùpje.¬k‚l’Óž,@zxE!³€g’9F‹u“æÂ„k!¤äcY-7œÁ`áp8iÊ& ¹$ %}Ë+B)¶µ“æÂ„TP¬!„2Ùpæ¡æþ /?É5Á`A!$gk'ˇ !ù‚b !„pÃÉ 'É”à$m7T™5„2Sh.L)(ÖBHi£©¹0S¹Kž`âA8Vgµäö9BÈ,CsaBHA@±†BÊ`Ù'saÎ¥‰l~©J4' ¡³³“}Ž2›xäE”æÂ„6 !dð$敚šMæ2åZÍËOQÂÌB)M47V d”4~HÙ5ápÍÍÍš¾xKK‹:«¦…MB™<ò"JsaBHž¡XC!¥‰¦%P•`SSSkooŸqyê”1 5„\Ñ’˜gX>L!„BfobXWWÇ»ƒD+j¥€#©?455eíýpàÀXSS“º_Å/¹¢PCÉ>hèõÆòaBH:D^B)É àñxrþbtuuá±ÇË{Ÿ`éÒ¥Y´aOO¾óïàÉ'Ÿ,ˆ÷J±BHA®¥ ¹0!„’)Ð\8çA~¡šÐNö …èW“aûåë´.Ð\˜BHAsaB!$;òi.,ç@? ŶnÝZpBM}}=Í…3h¿áááØ®]» ®ýPb'y± ŠBJG¬‰? ¹0!„Rpkg¹˜ ƒ íd¼ÿýïç¨@ú²§'žxO?ýtÁ½ïR2(ÖBHÉm8ó`Í… !„píÌfí,I±& í3Ï<ƒG}´`ßÿm·ÝvÍÏÊÉï$Ðö«_ý õõõûþKí$/žE!%¶á¤A"!„’ù4”S ßÓÓƒmÛ¶´P”·¹p&§u²PÐ\˜BH®±ÐÐ\xË–-4&„RÌx_saw)ùSqèС‚3¡Í…3n¿`0X4íGsaB!…†ææÂuuuÊű‘M@!¤È ¹pŽýB6¡Í…3jü~Ñ´JÌ\`!„”ŠX ‘¹ðÁƒ•ß² ŠB×Î)(Esá©á®®.|ùË_Æ—¾ô¥¢ù<åf.ßñãNjƄej.ZR¢”Ì…Kõ´®©(—“¼É€f>iÁ aæ¦PAéoµð*PBÈÔk244Þ¶m›rܶòòB)Â},Í…§ô§2¡Ý¼ysQ›Ð¢ÄÍ…§j¿P(Û±cGI¶ßñãÇKÒš™5ÚÈÓëvHÂÊL¨Ð(-nu9zŸUÒ—òï‡¥ëæ—¾BEÜþ³ÐÓ%$½~9ãPç÷‹vÐÜ\Xe’¨E*·Éâmí$Ý€ê}…@ÉU ;ÙøL59KŸL3«•}!ˆüeVÓ\x’ ª/ÚT”‚¹pºö;qâ¾ò•¯”LÙ“šR4(Öh¹±©ËÓkf°y¥à²*£Î$ècV³8¢×äƒV³›Y„^¯ƒ(è èõŠŒa`x :£cÑ¡îÞ!ËÒ AúÚxÉ…Å)Ü„òØ8þ€¦xÛ‹}à ä´î¾Zú<µR›¹¡HSÏ€m)~Ö…‰¬½é+È!AHFsK­4.§3SÑ©‡Мœ}âÚyZùÿ\ÍÖÎbð«IWöÔÚڊǼd;w±û¤k¿_üâ%a=¥|’Åí¸|Èòù^Ä3@&]€]vì7­½÷Ö¿‹—\‡;n«Á3?û/ÝïwÀ4~Q/E= éÿ¢¢ ‡^¯ƒ^K¢”ðtw?úFîÁéîœééOõÒuÒW+â¢Mk^ù~Ÿn”ïÍ–xaä¦dHSƒÄ`0ˆp8<[›N·´áOdíUåà-§ÊØëB\ð Hÿ'é×ož^{62Cµ 5Oë|`ç7em-â7Kf›é«I1/&Æa±gÏ–êÞ51GçªOL5Oý#”ƒÏ¦ÙÚYÈbM¹™ÐNF1û¤;­ë;ßùž|òÉ’n¿R5(Öh¹àn^V[–U&ý㉮–.°Ãd ×:è€iN‘‘q<ûÛ`¶‹‚[Ú7§ZŒMF×Ï·cåR'–.°Ãlp¶ß†O>ú,˜?nz=>ýÈGqûm·âŸw?È•S0E=DQQÐÁ ‰4‚^Nåxý»ü8‘`yº»'φqúB?.††•oÉ`‹ôÕ&½ïBßä%5ʃצּÉ(dô‹£cQïêE¥Ã ³I€É(ÂhÐCÐë èL²–ìñ.‡‡•}0P†cÏ£Ü~ð®¥pÚŒ)ŸøÆÙ>,žg…A èl×èÐÕÎ_‚ËfÀX4Šç_íQþs®úh>ïN×\Ø+mþ2ŽðjjàvÇ3ìÝn÷5Ÿ5 ÊÆÇ¡PéƒÄü–_™Ž¬ÇÆKð¾%O¯;Ó>Û¨øÊ8¯ªªJ*¹¬­­•ǧüƤ²4ãQ=»Ù³$ãÝ‹,tuŸ¨®®¾¦,7 %­!L7O7I_¹è4FyšÐNF1š —Ûi]SQÊæÂk4kn¹¡"I˜HøãE¬^jÕlH)fdÊÉ3Iw½;3Øì6#~gîšÚÊ%.¬]V•K“ÿ©ý­A<ìõÂjµÀd2Áh!zèt:ܼf5š6?ý—Ý@ÿ™¸X#è zésÅŨL>Ûõ ìòµ Œà¥ãñ꛽ˆŒŽ+ŸÖ$m4[Pøf§‰ ‚É(\ÓRÇïõ`Ùb¬¦xY™Ù$Àh ¦é'V“ˆËߺËtìµÈ ñ|;Öª„R%ýƒ£X<×£Q€(è Ïbž8ÆðÈ8ª¯³Ãbñò‰Kò¿L¸</GŸ¯.ÎlîVKswª °¦¦ÕÕÕ¨­­MfåKò+EÐèR]Rñ¤\¿ò@¯Ï¬‹5µÒXœR q¹\¨­­•ÇcbLNw<&Õ@ €ŽŽu– Ǣ¶Tc"ƒ®J«>!wâ@Á`Pž§'q”}#‘]=]1×£™fúþ3Úü%¯=1¯Mè‡Ãa|ó›ß,ùl %Åæw’®ìi÷îÝøÒ—¾T6íWJ'yQ¬É²‚?¿Âšò ï¼iž$Ø8ã‚ –½`ÓÓ;”é‚à‘»¤…Ùdpûê¹X»¼®/¿qõþ¬V+¬3ÌfDƒz½€Nl>ØðqüÏø DòP£×AzNöÐe3âý·-Æûo[ŒWߺ‚@ûÛS\;›BÝà}¡o`$£¶|ãlæ¸Ì0ô0âåd¢RøšâZί4+ËÉjQ~w+=J1cí ¦¼Ö6³!눌Œãè[W«&£€±ñ(NžBF#øZ®ƒÄ6®–‚®”žAUUUhll„Çã™õZj·Û Ç“”â …à÷ûá÷ûÕÁbâwp[(¦^¿8óóz½èêꚉ‘7±¦¦¦­­¹½gp÷ÝwO7èK¬u“â‰ñâñxf]üM÷ÊñØÑџϿ߯lsŽEmEšIçghhhÈYŸêeHÊy:Eߨ‰‰t-3³åh.\î&´©(6¿“teOO<ñž~ú鲚ÌJÕ\˜bv#Ài3Âlš¼ôå7ÍCÇÉK¸±ª:‚>†lë¡Nw$­©biã“T‚`2¸ýƹ¸ýÆy)Ës"#ãxµkž<€ù Àn·Âb±Àd4Bèôú$á`ý·áÄñ8ì€QéSLO¨Q³vY%ÌF=½CøÃ{02UL+^ht$®{¸dJàXW/†‡Çá´`20ãÙ4qB¨I×7ÌAÝî冼‰[:ß>e&Ó•¾Þìaq¿kn¨Hû‡Ã#xãl†#c°Y 0ô°E˜~õÒ9ùy;^êÏY_,dsáIƒ—Ë¯× ¯×«ÙûV 8²0ä÷ûáóù°wïÞTb¢44€òE^¿ªªª4ñvPfE•Y“ ,èóJc±*ÕXLŒ‡|OÖÖÖ¢µµ­­­ðù|hkkãXÔF¤iÅ$¥¨MMMyëJÇãñ µµhmmU ì.ÄMå½ÒW`:c¶ÜÌ…Óec<óÌ3xôÑGËn@‹ß ËÖRSÊæÂ çš¥ÝFn~…9í“+fô\B4C4d{B¼Ê˜·#ÅÆ»C½@o¸e¾Øx6ܺ0¥Psº»o]ðƇ1þB8vØlñÌC¢*…p°Éû)ŒYËŸ˜½ãîû‡F±|‰ŸþÀJ¬[57iÿ)mî Q¬ N\Ókþ±§wGN\‹Ç/ÐÁi7ÂlŒ—=™ Œ=D}Ü÷'“R²ù–”ý°Œ‚ÌŒ²j`d,ŠÛW,€Å$àõ3a¼|ò½z'Ï„qº»§»ûq,Ø‹Î7®à…×zpìT/t6#ÌFS¼zû"xûÒ üw‡úñ§ZÌ-f.Ü"ý[’PSSSƒÝ»w# ¡µµUs¡&ðûý8uê¶lÙ¢^ìk‚šr-#äñ¶t² ú¥5g·Z¨ihhÀ³Ï>‹P(ŸÏW'„x<ø|>ôööbÛ¶m‹¹!q³î”zXUU…Ý»w£···`ú„r\ù|>ƒÁT}£Jêþ,úFYš §ËÆØ¶m[Y 5@qø¤Úž|òɲj€Ò6¦X£¹XcIûäëØ1ÃX4Šh4†X‡ª*¬ZZ¤MÞ´-oæizz‡ðÚéaT,]‡º{€Óé€Ëå„Ëé€Ýf…Ùl‚Á ÊY5©æµuwÜ…±ñ(¢±bÓŸ&£w`/Ÿ¼ˆ§Ã𬻟|ÿ2µqlS–‹·¦bMh ‚ã]!t¾qGN\ÂïŽ^@ðí«ÐAÊÀ2 °˜XÍ,F&£”U#ÄËÉ2YB250.QZÖ.«œ2«&<0‚ññt:`ñ<V/uá+çâöUóÐ78‚à…~œ¿4ˆþÁQŒŽÃdÐÃf1ÀlJ´‘«I„Å$¢ýä„KÉŠNäöN°¦tÂÀW¢s’÷ÓøÝNy7]WW‡ ££^¯· ;Kuu5Z[[ ±eË5^±[¤ÏU[†ãˆÇÛ¦§NÙ4ƒS´YÀ³ÊõÞår¡©© §N‚ßï/Ø#\Ýn7ZZZ ÑÔÔ”j,Êt,Δfi’tQós0„×ëÕÄ¿e6úƶmÛÔÿÜÅ<]væÂSú‡Æ£>ZVþ4j ÝïdªöëêêÂý÷ß_ÒǪ§£”Í…)Öh¼ÙÍÄPlfá«#Y §»SfÕ¸%ÑB^Ù ¢ˆµ«®Ã;nœ/•Ý/<ÆÆðV¯îÞ…÷ÜûܸöT¸¨¬tcN¥N§6«ƒz½2«&ç½ëµ.ÕìšžÞ!\ç¶áöUóqÓõn¼y®—¯ãÆ\¨tšbªÅ;P@‚¼b_Ņ˃G,ƒÍb³3,&VS\0Å ¡f Q, ’ÅÁº2sd‘UóÖ¹>¸ƸY³¢/›Œn[=ïºi^\ÌÑëâ%iRÛØÌØÍXÍ",&ç.àÜʼnŒ©È`Î;ÖÔ\8_M3€vå&8q§6hr÷r¶‚ÖÖV´··£®.iÈTIs‰å·Íðúh13¸>-Ò8Lê¼[¶lA0„ÏçÓÄÛj¶Æ¢ÏçC{{;jjjÔv9ŽÅéR-]¯Pˆè5558pà@QÍÏjÑæÔ©S©æéö4}ã\£ÊÕ\ˆgc|ï{߯ ÊÊŸ&Åêw²wï^TWW—}û•²¹0Åm¨™$xž”ëØq©/‚ññXVÙ5=½IÇ['DŠé®Ë—UáÇmÿ€ÿÜû ¾ùÔ?áîÆÇ0wå{qý­õXvÛqË»Q»á>ܾރªêep»˜SYysç`NeÜn'v;Lf# 1^’3…€àt:0wÁâ¤ìš™r¦g³½0™¬Xâĺsq×M °nÕ\Ý<·E}ý ÅX7„xÆ`Å¢ÑD½fC¼”Æf6H_",‰“ŸD¢ Ÿ8Ö=CÊ8³¦%ñ`í²ÔFÙcfc㱸¶^¿Æºd7 “QÀ†[Ài5"Áj`3‹rYŒ"LÏu¾=ñ;ü,Ç›2ÍÍ…' iõ;ÕÁa!gÒ¤½¸µµع3éc%J,[Êqý*çãm3‡ª 1'¨NÉéP½DV›LCCN:…ÖÖւΘH7;::Ô™‰±ØÌ-æ”4Jý¢N¹^ìÞ½E'Ò¨©®®–çiUiÔnL~:(K;/{úò—¿\§i]ÊSŒ~'‘H?þxAfHnÞ¼Yó×,esaŠ5¹G^ 6cVÁ³(è0•Ä ³kT™5!(NÏ{ïÂ?|篱榕Ðétp:¸ÿCñ—[ÿ••nŒDF`µZàtÚQávÉ"ͼ¹•˜3Ç ·» f³ F鍸ÑÑS  -Åøx ±h\vš‰`–NQJ®—__'eBÌŧê—C%ØÔ¡pÙž= œn^³Ÿßü)»ÎÀívÂívÁåŠgÓX-˜Œˆ¢˜•P#/z#¢ÑxVÍt¥š§Ã°YDˆ‚)PN$A¤z+M÷­Â\—Y-`åÛ˜Pâ‡GÇ“D€î+CÐëttŠ’œwî²—UffÕ<ÿj7lfFQ“AƒAÆôé ÍnY^‰·Î]M}B© "ÂçJ-NqW?  ·mÛVÒ€ÛíF Hx)Ö”NPSdbÍ5y)eµMF¢ô%ÅXdIÔ„?¼ÖÔÔ £££` ¥5š§•}ƒ¥^ýõ‚i·;v`ß¾}X½z5àøñãš¾~1š ’ضyóftwwcýúõ€S§Niúú¥n.L±FÃÜÒ Í…•Dc@,CCu”Ìšåóð؃ÕjÅb†Áh€ ×OZRãt:°á®ÛñÊ+Ça±˜a±˜a2™`0 BZšT¬]³ 1ƒ3«“­ÔœîîÇÕÁX¥;îᢓ±žŒGîY»Å üQ¾Oˆ’ëž+IC¨YQ‰7Ά¥«ƒÀL§—ÍPNãÍ'÷¹I²jÂ#ømÇÛ°E˜Mqófc¢Ü,!þeà tc•ç.`xd GŽ_’.ˆh…6ù4v)…šÝ»w£¥¥¥\݈ûB”ôúEsáIcWžÄš-ê€< –d6Mcq'ÊÛt8á[$_”¦¦&ttt”L)Ü ûF#XÚ îwR(%Pû÷ïÇÖ­[a2™äŸi}ªQ1úŠØ¶gÏ|÷»ßÅüùó埽òÊ+š¾‡R7¦X“{²6V‹en.|º{àZ¡fÙ<<ú™&Øm6ØmVX,fFˆ¢0¥ØróšÕX²x!.\èNÊòÐéur6M¶‚å«Ç^Gt 'î½3‹xât.Ân1Ä}\ bMºwb2 xàÝIuÌUȯA¨È«6“Q€ÍbÀ`d4.ÔÍÂQçªÌšR>îÔ Å1µê¬šÈÈ8ÚO^±`.»Qö2Iü›þ2éÞ.›Ãc8râ"R†” bdd;´ ¢äÃ\J¡¦Ôü¦ø¤À½d×/š O=µ0žl &òRΦÉb,¶¢<õN×.‹‡;wî„Ïç+Ë÷ót£–sZ¡–v^¸p!ï¾Á`7nLúyOOæï£Í…ó-¶Õ××£½½<òH’Ð@s/R7¦X“[<‰Ùš ËbüŸôœéI.ƒZ³b!zä,\¸N‡v»f³ † ˘6¬¿‡ž ãccˆFc³qâöô6¨'/!40»Õ“19¸Òø‹$X2߆«’6²[ò¸¡“wÜET‚UK]èz»ÖŽ:W —òn¾%ñ@™Usº»GN\‹Ç/"læøÉMf£ 6zˆ¢z½z]v™L«8vQþ^4¢E£Í˜¦Aâdb¹ 5Ê@Àï÷+7x.Ήs³¾~Ñ\8ý8Ìuà ‡¯ùù–-[Ê6 W媱è+ñµ.­P³{÷n47—wUXâèwUߨ¢¥XS¨Ù‚'OžÌëëïÚµ ûöíSBÞxã MßK1úä[lÛºu+öìÙ“r ií7TæÂk4ÚÈM'«æêàhÆÏUgh¬»ùlÚüY,X°‡ö„çŒÉ”6«Fɇ?ø~¼ðb;ÆÆÆ‹E¥LìŃ×_?‰‘ÂÄTœ8ÆsKüxd³Q€É7ƒÕgQ²¼»J-\´æ±oȳY*¯!«Ù0kG›“EÂR½ãè…"«Æe3â…×zð»£ÐÝ;$¬˜Œ,Æø‰[³³!Þ—ÉÈ.cìx×Dðd0árdß,µ Hi.\¶BM‚êêjøýIúL JëHoš §Ç£Õ5šL,mmmE¹“OKx,N9¥jÊynNšÄjk'3˹´SkADI„V‘€~'éÉ§Øæ÷û±}ûö¤²'%çÎÓôý”ƒ¹0Å6»Ùš ÀÕá1œ|û*Î]HûÜ·ÎO˜Þºv5ýÌ£p:p¹œp»œp8lq¿Q„^/d\Ê´tÉ"  ctt ããÑi{΄ú®ÂuÃu.ÃÙ~FÆÅ”ÏKdA~µýƒ#pÙñÀÚ?ÊÚld¿!‹’•7^Ÿt³­ù3Ü &¨Nð,œcÁ¥Ðð¬u>?Y(,UùYÞ˜¯]³sæ_£¨‡Ýb€Ùï;V“›Y„Íbˆ÷)££aú})<0‚Wߺ"?ÉùQÝy ¤Õ"ƒ‰Íþ–-[”?Ú†Ò)‡¢¹p]#ŽÁôcqÛ¶mÊmAéê»Ïè£P3êy:_óZ Ÿ?•9í‹/¾¨ùûP›ÐNýNÒ“±MyZ×dB@±-WˆœÊs¿‘ËÖ\822Ž5·¼Ÿxøatt´ãÈKÀÕK ‹F0>6»Í èâϳÚ]8}9 ¸yÍ*|þ³Âf³Âá°ÃåtÀé´ÃfµÂh4B„¬ýfL&"##qcbAÙ•s9{¸wãݘ3§» Fç«xóø1êÆàðt:ăg½6süÄ'£¨‡Q*Y1%„9«&ûS’ÖÜàÆÛ—p¦g@äçcCÄ"„û¯k\6#Nw`~,!“>¦?÷D=FÇ¢Ê~ÙQBãÌ EVÍÓ?øÞxãþû?ŸÅÕž· Šz= âÄ—(è`<„iö¥Ÿž86ÑdřȠ¦GÇjj.¬Üp6551PÐÒҿ߯Ì<ò•HHsá©©††æÂÊÌ£-[¶p N1åt¥î_ã‡ÂWŠBMæót¹—vjíw²k×.lÚ´iÊ ?ýN’)±mëÖ­xâ‰'2*7¢ØF±¦Ø˜¶¹ð™KÃxø±@ÜsÏF<Øø úûûñ̳ÿPè*L&# F£?ÿíkX¼x!¾ôا1wîØíVØmÖ‰ò'sü¹Ó9ÉéÝëïÀhwo¸QQ„^Ÿ72ýƒÏcù UE‚÷ʹ·Þƒûî½gϽü° gOv`|l‚^'ÒQ£A£Ï€0(O€ÒMù,_ìRŠ5uy/&ÃÃ)Ÿ`6è“N›®TÓÓ;„ysçàüÙ[¥Ôjù[>ñÑcé’EXºdæÏŸ‹û~„Ñðé$‘FLi¦w4úéîþ$¨È >“ Zk±¦®®®¬ý1R‘ðE¸ûsŠÅa›ÑúEsá©Ç¡–æÂMMM,}šŸÏ‡uëÖ)û°ÐTH׊V(D{ 5éçéÖÖV<øàƒšÍi…ZÚ©¥§H}}=ZZZÒfÓäã½%Þ_1úh)¶ùý~444dü|Šm¹eP¹Á“x0saÁ:&£ƒ¢ H†Àñcµ?ë}ŸøØ‡108³É£Á€ááþú¯þTU-Áüy•˜SY · » fsü9™˜ §Âétàí =G4ͪª¯ï*úS~ ^fõ7ÛŸÀû>ô ¸ç,ˆû‰˜DXårƒ|jO¢\E?Ï´h;ŒX4תüQ>\øäÈdx$µ—ÏȘäYLÛc822ŽÐ¨ &ŒT]BãÌ EVÍ×¾úùn^³x? ËœjIôÓËÆÔbBð›†P‡ŽvËMVtj\æÅ\¸¦¦Fí A“½Ç£n‹–RY¿h.œ~æ:ð …B‡Ãhhh Xš®QjkÑÔÔTJc1På2Û1Ã‹ÖØ(ÏÓå\Ú©•§H„6S¡FË÷– ýN´´”eO…öÞ”ï±Ì…)Öh°‘Ë6«æµ®x6~&“F£‚(B§×˜)–.Y„­ñe„ûú14<ŒoþõVT]¿sçT¢¢Â ·Ë ›M:ýiBM‚E‹`l|ŸO3a¨h#¨êj444`ïÞ½‰5£xK¡h.\@×( !P,Í·Ûææflß¾=ñ£”N)”’W’Ëåb¶c¶ƒVʼ*gsá\zŠÔ××ã[ßúVÚë«ÓétZ¿·T£ßI®­ýû÷cãÆiÛ/ïMM¹˜ S¬Ñ`#—©¹pdd}±9¨»k=¬VK<+FÓšÿé—¼øîþ÷ß £ÁQú„ ¯Ôy³þ¿øe¯;ÃÏAÇÑ×044œÝ†ÉåÄÍ7¯Æ;o¯Á‡î{FŸÅS·§NuáÜk¿^7:-´‹W4.‚,[ìDçÉËùkà &Ãj±fx$ŠX,ûó·Nw÷c æÆ>ˆ · .§ïºcöüôÙRkZReÕ(ùèGîÇÎ7^…9ïSÓtzõ­+I§w ^ÅŸ•z ][[K¡&Cš››•bMƒ4ւż~iqZ•YCsa\Yâõz•bMJÃGª ŸŸÏ‡êêj6v–h•‰T¨¥¹òÙºu+þüÏÿ<ël-ÞÛd£¹p®­úúzüð‡?DUUUFíG±bM)•¹pOïzGl¸¯ñ8ìvج˜Ífˆô)ʆÔ<úЃøÿ/Ðpÿ=²83²§{f~ñ?übÿÌ÷4¡p~‡¿ˆÿOØø¾÷à¡ßûî}ß”ïk“÷SøßÛ…hø8ô3qÖ„Èh¼œ«fÅ¥XÓ€x)”–é÷!eû_¯õ®°eüÇÂ#8{9ŠëW¬Ã7Þ—tt»Ãa‡ÙbVE¿GY5 œN®_±玞…N“Jñ²7©þÒ«Æ‚ŸE†4Ä5 µ" "Œ_ÊŽŽ„BÉð¶¶n·n·» ?³ÇãAMMr“îEqzfÐ\xj4÷ÒŠ„p¦“Êþ Ä³È ]$¨®®FSSÚÚÚ”c±˜Åšjå\ÒÐÐP4"^(’Çxª~U,óûtÆ‘DÉ› gbB›N¨¡ßIfäBÐÚ±cš››§<­+“ŒŠmkŠ $f`.|úâtÖE¸çÞúøQÛ{ÜoÆd„A SòNŒ®\Q3gÏcù²*¢]LK+Øôõ]Åžþ ~ø£Ÿ ïjÿ”Ï]¼d¬6ãÑ1,_5?)ëãÍ×{06C¸w}áÁk~÷W¿y¿úÍsXsÓ*üͶ¯aý·M~7Þƒß<{úØô±éÖS‰K`ƒÃj€Óf@ß@ÞJ¡:$‘•ÉðÉ3a¬¼õ6œ;‘ W0Ç.ba¥fSr_êéBx(†‘¨ ‹o¸ ï¾m¬V v\.'\.Þ»áÊ_«*1&oZÿ¢ùóSfÕ$ظу{B´1½.k ðÐÑ rV(êF#C±Ï1HœÞÆÝï÷£££8xð`öJBM <<OÁ,ÍÍÍØ´iS1‹5òú¥…¹p(RoÒi.¬ÕÔÑ‘4ÓKŠLyJŒÁB¼^¯W)Ö4!ž™*Òæj…¢ü©P}j%{@`Fó{mm­Ü·Š±ü¯\Ì…ëëëñÿðSz›dèÓï$=¹´:”Ö:“ö£ØF±¦ØÈÈ\8<0‚7.ŒàïªCõ Ëàv9à–2!¬V‹d , Ó°rÃú;àÛóï¸~ébˆ¢(ûÕLW¤™;×%Ë­°-¾ç™_¥ûp%$-Ç6?Œ¯5N§ãš×^çmüê—ˆ†#ªÓAÐÍNŠÍÉ3aèu:¼~:ŒX,·Ý¤kŸ>ŸO>-:;;ÑÙÙ‰§žz .— hii)ˆ»ýJ±¦Jj³Ž"_ùô«¡¹pŽñûýòW8žÑß:xð <ˆíÛ·£ªª ^¯ÍÍÍ\{<TUU)ƒˆ|”;ÏV“Ó Íì=!Àûý~eèŒç÷¶¶6lÚ´I>íJ‹’ÌRk.^¼8kkëÖ­xâ‰'¦ ˜³ñ¡ßIzfSÐÚ¼y3¾ùÍoΨl-Wï-ÊÉ\˜bMŽ7»jsáðÀzB#аWVãžûka·Ûáv9PQá†Ëå„Ýn…Ùd‚h³öl™?w"##0 =bz!eFÊáŽ`Ë_l»Æ$Øb1aU­‹o ¿>oéÕ]ÀÕ@Û7¢Ù.4²ã]Óߎ¹±Æ §ôM]ífÏñ—'2n~øôOqøù#ØýÿK™±¶öèüͱø >±Ù1Ç ‹°™ã'N¹ì&œîî¿f®ÕGÙ/”\¿¢ Ľ‡t:¸\´´üt:öý÷¯pô•cX¸p>ŒF L&#,3ì6vìvl6+¬3ŒF#DQÄ]ïzžÿýËÊ>(ÒñÕ’xðØg?•Rì›t|\·§{ŽAŒˆÅͦ3éW/¿ˆÈh<ûIu##ñ Ó ÑÒÒ¢¼»=eì§Ê9Ç­˜Sk¡(€p8Œ¶¶6´µµ¡©©)ï¢ÛíV {ÍO +±FU.à5ÊM0ÝÚÚ ŸÏ—ÉÝϰbüu(Ö©jL”Ð^“Ö×ÕÕ…íÛ·cûöíØ¶m[Áˆ6xê©§Š]¬iM<¨««+˜lÂÄüž¡ðשèKLçwòü^WW‡ÖÖÖ¢s…j.|üøñYùÛ3-{¢ßÉô˜-±m×®]Ø´iӌ˞”Pl£XS´bÍPL`¯‚(`dL‡Ê9sP{Ë 9À¶Ù¬p9ã5q, Â4ŽÛ~÷ú;ðÜ¡ñîõ·Ã ÐëõˆÅ&Äž¾¾«øvë÷ñçšô{••v¬z÷àå%«ÆþÉæîû^Û7¢ÁÙ¸mßI›#_ÓßFªW®×ûÈÏ =ÿVðÚ_ÇÆûÆüÛpóšä4Êuµ·àåߺ“ÊVâŸcúï%22Ž¡ÈæêÍô:èuÀ²EI~´5•p¥iíÛ!zp=D1.ÖèôÉ}àþmDÝ{Þ…]?øTU-Ae…‹V«6›6«E:Ë,›:ëõúkbÊ"[^L#«&ÑdÄx4†h,†X†y5ᑤ¬ÑkËÛÝÿ¢3i:¥þÂlÆœ[­¥ÿW)7õ~¿­­­ðz½y b§ÈƘü~ËùxÛ)¨F‘øFe0Ê1P‰3™ÌEµÒ8LŠÚ¶oß.‹Cù¼^¯R¬)¶±˜Xód©B( …Bhnnžª_u!~Ón&ó{bŽ—ç÷ƒbݺuضmZZZ ºÑ Õ\øñÇŸÑïgkB› ô;I&WbÛl”=QlÓ=µ•YG^X›¿ºÕ7½+o~'Ö½s=VÞ´N§n·••nÌS‰9•p»]²Pc4ˆÐK§&e;ç9 bdt ããñÓ„œ9{ùäç“„«Õ„µïÕ…ïÿó¡M/ügtî3ß¼íã9+Ú¾1Ü÷ÑÕo»¡ænÝ›²PqµÞÇþ}}W“â’E0Øæ`<“>GlF¯,Ø‹¹nK\¨‘³IÀüäR5­wÞòí¨žÞ!œîîÇê[ï€Ñh„ÁÏŽÒëôP—€9lýÚ—qéÒØlV¹U¸]qÏ#«&£a¢N¬½yu>?çl!ïвͪ€ê–c|<k2ìS‡ŽvËY5.GñM‰S4PK n¸á†Tù._pƒÔÿš¥ }¶óMHú=¯tMÄDVÂá06mÚ”W±F%rÔ xÄQ·28â±Ý“Š ×7* ¡¥¥µµµ©Æa@›4nÜR@Ü"ÖوЈ߈iP`“4Æåqøàƒæu&ú°¢LÃU„kŸ¼æ555å½Ô³µµÕÕÕ“ÍïÛ¥ù½zæ÷féïÜ­œß¸èñx®1¢/ Õ\¸§§gF¿¿cÇìÛ·/'B ýN2c&bÛÖ­[ÑÝÝ=¥P£“˜Îß§ØF±¦˜wéK_‡ú÷¿_ýÊçàt;Eár:QYiæÏ›‹¹s*PQá‚Ói‡U!Ôè§!ÔÈ ªÓattãÑDP ¼vì6Þ÷0^ûãëòóß`z}êÕ߯Ümß÷iuÚ¾1ì<[q«G·?ñ³³çÞ†÷±¿¸æ¹.—Ñhü3ÌDª9ÝݽNQÐÅDyo±FN.…†1b˜›o©ÕjÉd”2c&7˜þÓ/yqäåW`·[%šø)bq¡GH*£ËVØ(@¼˜AVM‚h,~|{&}*<0‚Wßšðfàk 'ºkkk¯1!•6ÚwKïVÌ~æš_šw„BülkkË[ X]]­ÞÐzŠdŒÉ},OæÂbºF…(˜yªJSº$A¥ZšKý³Ù”’pS¸ ›4kkkóX«ÄÓb‹IkžËåBkkkÞÞH(Bcc#¾úÕ¯NÕ¯Zr0¿¤6»ñŒÌø¢rð`Á 6…*@Ÿ?~Ú¿»ÿ~lݺuVËf”Ðï$=3ÛöìÙƒíÛ·Ïš?ŠmkŠ y÷vóšUòùd#n¾i5.^ºŒ9s*®É„°˜Í’ÏÌÌ„p»]ÅøØbÑ^;vùäç“L„×lÐuoüldùÏÍ›—ÂÑ@ìž•·é~”øþùßÁ·[¿M`kâ‘ulŠMddgz`³`ôqÁF¾Æ:µ¯PÞÄš?žÂ=zv» V‹&“ ¢(B§›ºÎûéá׿9A/@”ÄDæò÷Ö&—™yŠl\¹¡¨ÛŸNV œzëMÄb1Ä2”þ~óÒÄæÆdÅä×ï `ƒD¿ßÇ£Nýî’6Ø‚p¿0t*ÅææüLqª±Xîæ{´ìcª ¦“×hf477ãî»ïVoœ•Á´¹¿Ëß*½–œ ÑÙÙ™×ÀZÕNÅ´öµ(Û6_@ !^eVõ«\æÑ¶BéWÅ&ÖL' ®¯¯G0ÄÆ§ ògêB¿“ôLGl«¯¯G{{;y䑜 mÅ6Š5E,Ö¨ÊN°þÎÛpÓ+qùr/ìv+¬6+L&S<b5©ˆÅbÅØø8^}í>úð’„š[=ºýÇÅæªÜ)N‰}ná2ÝoßÿðG?Á™³Š )& 6Ó̬‰ŒŒã÷Çz0Çi‚Ñ ‡Á ‡¨WdÖè®É¬©ÖøÈ»Œy —^st»(Æ=k¦"qlûÙsçFSoÊç1ÍJ€f’Uc…ŒûÑéî~œ<;q12ˆÏ0H¼ŸÏ‡|P}·õ)äÇÄ:$]'yCÿÔSOÁï÷kßXÅy7¿v’÷Ÿ›è+¹\ £Ø®Q¡ŒÃ`0ˆÚÚZ¥7K"˜Þ®a0=å8ììì,á´ºHú™Ьš|]»„¯ ô÷æ©_%®Ë¦BèWŠ5|¼‡Ùð;ÙµkWNÊžg} IDATèw2=²Û¶nÝŠ={öL¹NMGhKÕ~Û(Ö­X³þÎÛ¯ùÇõwÞ†+WB†AaEˆ’ðl5 ±fllgξ‡>ó'¸* 5‹ï¸GÿäÑ@ìžBº`ÞŠ5XlúA î_óíßOú,‰Ìšøô¹dÁïõ`®Û “Q€É À(Æ3kôú sY—=éXë?¾¼‡ûú¦}tû†õw ½ã5Œ!¦ÌYºä:å·uE4¦ÜPœ¦3ݬ8vüuôöE2zî¡£Ýòc“U6Äe¨Ü5{½ÊcªâÝR{åëvgHzýNåûÔúŠ%³&ŸÇvÓ\xš×°¶¶VÕvPjË–dÁ¦­­-/¥<ªvª)’±Ø¢œ¿ò‘U3‰¿ qŸ¢|¦³ø¿! ÷«|ò“Q¨æÂ¿þõ¯3~î¡C‡ðÅ/~1§ÙJèw’^ÉFlóûý9-{RC±bM±!oÖ*Ê ”<ô‰pø÷/O”÷ »ã¹Óqér/úúû±å/¶ÉB Üôž±'_þeôñ¼f!Áý|â›ÿû³ÿ’³kº»{¤²•섚£o\Áñ®æºÍ0E˜LFq"«&‘}â²S‰ZL<8}úüŒŽnŸ3§—.÷btl±hôš’±TÇ£ ³’UÓ×w“ËÞq7¬×ß…«Æj\è7!22žô¼žÞ!:Ú3=c'2˜÷£— .HLqÊL' çHøP„¸Ù©Öw_UmäBáßÑO2æIP©›5ñ |£:::àñxÔÁôvijZ‚rͼˆgbÈóF0¨í[s»ÝjƒBO=ʱ˜ÌŸÏ—Jˆ_‡Â9ú¼ŠR»æææ‚(‡*Tsáp8Œýû÷§}ÞæÍ›sjB› údF&b[}}=Ž?ކ†Í„¶H$B±bMQ!ïn—,¾nÊ»ÿ·­[‹ß¿ÔŽññqDcñÀ:‹ÍÊ›¸tù ¾û½6¼~ò-ùg+oÓý¨@…@?¸˜øþßžÙ‡3gÏãt÷y\¸2$É*éç–§Ãx®óÆÆ£pX 0EXLÌÆDV‚^tI¦½ÎdÁFËœ¼k›öÑíüÀûðÒËG16:Šh4~Ò‘ºO-Y|]ÊþZàä¬dÕüöw@Ý{îÄGø0¼Ÿyù—OàO¿ö Ø—¿ǯ8ðÛŽ·ñ\ç¼y®GNÈ]Vö¡€²j !Hôù|j#áÎ cKî;mmmš‰55I7ñ ]¬©ä}çš ϺP“ði)Àëæ•×¼§)Ú«ÐOg“Û0'@utt¨Û(,Íïد‰€?ŸÌÊk§ü¶P.Ô… Ò>g×®]øîw¿«Y6Fú¤'±mëÖ­ø÷ÿw¬^½zÊö›í6̤oÍ&åh.L±&G9•™ë5ܼf5†1::†èx4cÃÓtœ9{¿þͯñË_É60X´B·÷䑨ç ýâàë²XóïûÐÑy ï{߇ñÁO~•«ß‡ˆc5‚}vœîîOú:ìEûÉKøÝÑ èËn„Õ,ÂbšjL¢¨4ÞM~íÙ5Z"çÌž žÑÑí¢ `tl ããã)Å¿"Ì®‘³j3Ȫ€7OuÁ$‰. ñÒÃ¥KáO¾ðYü¿Oþ-êïÿ8æ-X„Ë} +²m¯âÏ$*"ê@@}Ç5!Ôâ9ª>(î¾¶´hǪJŠán¾f}ŒæÂ³.ÔxP8YjBR` Ø»w¯:cq‚j(Ê”µ¶‚Áàd}«3ß‚P<@±fŠØàÌ™)ƒ_­Êžèw’AÄï÷cÇŽSйúŒ'OžÔôZ”£¹0ÅšT7ß¼*í“-._éÅØx겕éð‹_ÀÑWÞ˜!æáÜù7bErýä¢ã³çÞÆ‹G:°®v-ÞuG-yøãغõkøëÿõ¿°fÃ2\‡spþÒ ú‡Æ"žIca1 °˜DXMqÁ&!Ôzô’©pº}]6²ñ ¹»gFG·‹¢? Lql{²Xs]1ÉY5›†ÃaŸÖúÉ¿ù±bY5L&#ŒFQ”Œ›uò±æ_þâf<ôéMèê’ÏdÁÏPÙ"$ƒA46&M'],ÔÈ{xå†FËTyU)Q¡ßÍ×T¤¹pYÓIM…pêóù´m¸âɬ‘×¼ššÍûYcc£º¬®ÐûV+å®Z÷«4bM ï!• räÈ‘”ÏM˜ÐjYö¤†~'é™LlS–=MÅlµ_ª¾õÆohz-ÊÑ\˜bMŽ6r©Ì…Õ|à^:’([‰"UÙJ¶|ÿŸö`82 0uãá‹X[D×/Emûù·{`4Ƴ ½:èàr:ðئGñ­'ÿžû>ŠŠ¹ aõ0âÍ,Âf‰ÿßb`2èaHjRg•ɰֻpyA?wþÂŒŽnŸ;wNÒ±íê>µté¢b “²j>ç}xz‹ÜÙó†Ói‡ÙlŠ‹5z½tUšŽW108 DŒD†ð¹B›[ò)Öx½^u˜o£ÉLðCQ‚‘G#Êj “54Îd …ÔÁt±5 ZÚÚÚ îÈåÁ+/€gÕ´´´¨Íq7Aß A‘Q–o£áb2Þ³g¦&´© ßIf‚H*±mÇŽØ·oŸæeOj^|ñEM¯O9š S¬™]Òš _#¸ÃøxtÆBÍßüïVœ;ß#o²ÆšŠ šT¸8<£Á í꓌D&Ä} ÇÂ¥+`6 °šDXÍ"¬fÌ&©ôIH5S .›!ŸŸ9˜xðü Gfl48¶=š"[Ë•ì÷RÈ™5IY5›?ó 8ÙgÕôõ]Åž}K–,Œ‡n6Á Ф23õsø£ŸÈß "vÈøÉ{˜ØÈdO¡pËêÔÈïsïÞ½y‹Å\¸¾¾íííxä‘G43¡ úd†ZlÛ¿?¶nÝš÷ö‹D"xúé§5½åh.L±föw·éÌ…• attò²•l‚ÒùÉÏäïíøC?.Âë(¯vÇþø:L¦xpk®}rÃý÷â3Ÿý<\ VÀlLøÓèa‚‚Ú£¦ÀN´cÿŒÿØØØ¸BüKîP7'{)z*¸ ìv¼ŸùÄ´ÆÄÿùþ?ã¦Õ+`·Ù`µZ¤S¶ Ð+J üà韠O:=M4èFF†±ƒA¢ÔAƒAõF¾­ˆ6òI›y-½2òqÜîLûÍ…Ó_£|¦~¿_}úÚö"ƒòGɇX£j³B½Qá•U›ÆFMçUO'÷³¡ Pk?$ùM¨­¯eOSÍaZdc$ ßIz”b[}}=‚Á 6nÜXíG±bM±‘±¹°§Ó1eÙJ¦|zóWpµ0hŽõ÷â“Ez“¸ËWz!ˆ¢ÂøÚùçæ5«QÿÁû!XçÄ}\¤ô¸æÔ§Bÿ̯ýñõý¡¾¾«ˆFH×ö#WrvJ¡nX“²jy¨‡=+!óÌÙóøÇïµaåòj8ìv86ج˜LFD:•øwæìù¤¬½+”¬š¼‰@¼üIAW‘mäcLö5Pmª Í… -Õ<ˆÂ<õ)+±†Âé5ë^Ã$âINIQþäe¿šñ¼V0‹LBI˜Ðæ«ì‰~'ÓŸÿøi]ûöíCUUU^Úoª¾¥åj. P¬™õ€*saÅä5eÙJ&|óɧÐyô¸ü½Ñû?(¬#t³E®µ¸xñ2D!\O¹‹®Û€%«ÞO$‘§ª¢j Μ=?í?¤ÓéâÇÀËý+ùßU™5…*OËY56›|òÁ¬~ùÇÿêÇÞ}¿ÄŠåÕp8ìp¹pØí°Z-0ÐëèTÇÀ{ç÷嬃 —G†QHÇÜç-HLlðTåO^_y% ÈÞÐj3¯ ë øÚÐ\¸À®QÒ„ØÜ¬ö©)Æ`úšq‡ óVeV‘kžªªª4ëcÁ`P}ŠÒvWi]Þæw5…`.œŠîînMMh³~'™ "ZÖ•&^¥Ø–G(ÖÌòF.sá}}W166Žh4–²l%Ýïþ]ë.üáÅÈŒÄM…Qì+Ú;n׈G^> AÐ_\§â¡O~ ãŽeÒµDVײ£á3gßžöyåØ1ž;„þþi»ö9Î䕪 ì:$eÕ\¿t>N¾ùfFcáÙ½ÿžüöw‰D°pÁ<¸œT¸]p9°Ù¬0™LEAÊÒš0›>sö<þïÏþKþ[£|Abr ¨`/Š£d%å^Z hÒpµµÅrmh.<5ÕÈ“oT P—?µ ¸oÆ$­wkd¼òƒä,ªœÒÒÒ¢» 8=¯XçwU–fª¹ð#<’wÚTÐï$36nܘ×Óº¦‚b›vˆ\#g…¬Í…Ñtl¥O¯;ÿþF†ÞFû+›AŒµŽ¡ØX耔¬ôrÉJº¹Èét`ÝwáèÁ³ÐÇÆ é&, ¤;ï‡_x ëï¼-ë?Ð×w—{ÎÁíˆâGO¿‰ ¡¢bV,_‘tí®»nœE"!…´[žÈª±šðeï{ðæ‰ßᕎ¸ru×]·K—,ÇÕþ!T¸]èïÀ•+!DFFPYáÆÒ¥‹`µZà°Ç3j\N;¬3ŒzÉXXy=þjûßÉ &\”DÞ‚D ~¼®Ê[¤¹Èç•TbA¹CsáôäÍ7ª¥¥E-r´–@Ÿ )û‚}N% Ú©ŠÌ;­Äš`0˜J,ÖýcP=Çh-ª*è*–ë˜Ï¬úwûQl£XSlÈ;lÌ…àÅ#í¨¬tcÞÜ9‹4þ=Ý]°GqîüD"cˆ * SÔYáêÕŒ²j<ðá{ÑþÂA‘sˆêttIuQE±Ñèë»:­?pð¹ç±j™•n;œ ,fDq¿éçøãëç`5› ˆz„×՛ÄB e1àÞ»o^¯ÇšÕ‹aµ!Š.^îÇoŸÿ5lŽE蟃A„ÃaÇ£f³V«v› ‡ »v›‹F£‚ @¯Z׿p¿Ø?±Éàc ' ·£¸ïè‡& ÜÊš gq´U%ˆ-%Òçä2ZÜ£ó…&z”c°ºZ›eY5¿w¡8 «“¶AD/­O„*$Z§ÓébiîBéýN¦ß~…ІÛ(Öíf7sáÃ/QÂÏþ3üæ7X¶lV®Xë—.ÂõKˆ—hœ9û6‚]Aœ:u #ÃaˆÂ‹‡þ01ÙEÇñ- è³j’„‹c|=£¬%‹®_Ž ÇÏ@¯×A+ßyqõµé™ ¿új'–. ŠÉ§`Ýyû ÜuÇ üî…×Ñuö–.ªÄ…îP!Š5 ¯îxÇ2é³èål˜óœøDÃxåØœxëuܼöX­fX-X­ñ/›Í ›ôØd2ÁhHÕ­O,pò ~{ç÷åÇ&+:#ƒ8æ­J•UFñßÑ—ÛV%”;-ûÍ…§LDñ– ’©‘ýjò˜UÓ\JTkA¾Ð²§ øóäÓ露Û/Û(Ö­X“¹ðÑ£G±ò†y¨tÛ`·›a6áò¥—ðƒÿ9¾ðl63ôút±a‚¢(Àj`2™a1q¡'„PxPù'[KäzUSV¿¼`Ñœ{-†˜CL7Ü-ÁFþÌÓ1þñOÿnû(Œ ¢A¯‡NŸ\öî;WaåÅ…8úÚ寊X“”UãY#ŒFq⳨Ž_¿eÍR,«Šàç¿~¸¯v» 6k<‹Æb6Ád2ÂhŒgãè5ʾtø…#xþ÷Gäï#ƒ¹YÍK˜"PlEiÁdŠõ‹æÂ…q×I•UÓÌ®Z’$¥EIXŠù½ ŠÓ”Š˜H™5yk…ðrcÑï¤xÚb[þ¡Áð,nä25î뻊˗ÎÃ` ÈÙÀ‚yN|ä¾[ðñû×b$Fl|&“6« N».çÿÏÞ›F·qžé‚jßPî²Dš0½H¦LI‘mYÞ"z‹-»Ñéävç¦ûŠ™éN/§çZ7¹?·Ãž™snúL¦CŸ¹Ý3íž´åt;Ž;¦÷]¦lG‹ej£HÛ’L¢6.â$Ab™U(@@²P|Ž Ö_}ßû>õ¼Ï+¡DÓÿ:2w¢Ð,ž+Ìd*ûóðú:?bŒ‚X¥®éOüõÍc^B;œyÕ:/Êš4^5­…¶²Ø!“·[Šï†9FÌ…3?-Øwvèq RH€ƒ>ší] FGGÑÖ–ÄÍ´ʲž¯7vª¹°SAüNÜB¶Ù BÖ,Y› ?û«ß ¢`Œ‘ŒêɤÇLD¿û­»°¦Ê‡H$ ¯"À§I(ñÉði2X–ÆñSçÍ׋Îâ)ò3èØX¿Q€X Im¬ÃôLÔ œ™8Ô‘Ñ‚Áq¼öúëø0žÏ1Æ|Jó! ¬õ¦Ï?Y’ªæ¾{o†(°ày]YCÑžÕU²ÌãÁ{ëðê«¿˱à8,Ë‚aPÔ\ùTêóŸáÕ$R,<‰ï‘$qÁDñ¼ÒÀb‰%?Ä\xiØî5::šÎø•`åpÐg1Oº¦¦&ÛÖ÷”P{É”Èn5Î'ˆß‰»AÈ6ûAÈšÚh35>p¨ã£Á±Œ®¬1®þ§KHï¹ã&4Ü\¡¡q(Н"@‘y>Úc>ÆCá"H-{âÆn 31Çñ³'ÿ <3Iä!œ®¬¡i“¨IÇq4Ô'±Ó›ð½[¤„êqçí7@8ð< Æ,ƒZøÉ²Ì£TEçɈ'¾³‹z%yÕˆxÎ4ÎÍ‹¹p (TSÓ|cÔÉsŒ˜ /=FyRÕô’ý}ùH! t.š ]dMkk’Pr/™+:·ˆª&¿wƒmöƒ5+Èeb.Üwáöí{^ºr€Õ•©žVÔù+qmM®O€çð<‹ý¿ûlŽ˜ˆá§ägHQýä2ºfÎd¸û‹ExàPZÿï„Wš€"ñ%¢ÀfºT’J+äS]ã°;qãÁ¯n„"ñE¼åÜH-JEC} ::~‡™™D£†¤jü´õŸMU ÃzfÃSø!I ä÷ÃÝ G£sŒ˜ g†²¦•LÓåâ$qRB½Æ… MÓlS¶¥¦{ÉìXÑu5©á8ñ;)8²Í~²f…ª¥Ì…û.\¿>ýoPÄ0DÓ•†gM:OŽÔdôêÈ&§f08DàüõÏm6¦þÄ–Eôri}Ý70á„ÍÖLŠ»è Žã©ŸÿÞïÈ|Š,@QHgÁ0‰’ºÅßèºÚŠ´s8hIø4 ÷Þµ>ëïbžëËÑÞþfgg‹Å7=‹’Çï_~þ˹ŎÿƒƒÉÛ“Ä4‰" ä—sB;¿E81vØTÿ‹¶<5Ì´£Muš2§À”ÒØe,œBÆ¿ BÆ/N4v:ˆß‰{@È6g€tƒZ¡ c1sá‡:ðÞ{oÁ+MC‘Äd%EeÔñèáûðú»Ç …ç&+…SñXÁm¶fô–Mw­NuŸFlrržÚù’H›;þX átàPŽ;†¡ÁË`<%Š,@UD(²QÔK h†^’øEæ­7}yüMUÍÎ6çô]¨ªPqäÄyÌÌ΂eYӳƊ§þõ—ŽëÄÍxÂ3ÓñŸ$Ñ’¶µY¯@¡ðÈ[çz YÓ^ìsŒ˜ gvZp¢@“ió<´ƒ¬I94ž¶—@¥Ì¯½ X6ˆ¹pv ~'î!Ûì!k–‡EÍ…ƒÁq¼Øö:.œÿ ²ËY ‘@‰&ã•7™·ã1üœüÉèìü !¾c#(“fP"/üØ‘)ô„òÑÍ òàáüËÏŸA8<‰‹/‚cgASq, A H<E€" $Ç‚¡)Ð’uµ•èì¾`MØòqõ¶Åœ×>÷µ>§ïbEdv3áð<š¡á±´mOUÕÐL¼5q¬ íIbš@¾¯è›ëµ]W²ž0sáÅa»oT‘$Óæ¸ú|«ÏŸ:”4õÙ½¥!ãÛ@°,sáìAüNÜ B¶å„¬Éæîšj.ÜwáÞÛ÷!zgVD ‘Àõ×UáÂ¥áBO¨üËšÐ,ƒ?ÿþ÷P^VŠîÏÏà³Ï¾ÀåK15Ò‡èì ³²3ªkp}U|j*£÷;¬€3_t@’8È †¡Áq4ž…$ê5’áí"p ÒÊxÉÉÊš|ýƦª¦éÑ[爚,¿‹uµå8qò8îÜ~'â, PqÄãºÑðû»ŸšªNÀÈÌ4~D’ÄEEȯ,9pê#æÂK‘]-•S̽ ñôÁf"Ú¡m»Íø±¶¶Ö…YßW}'ªš @üNÜ B¶å„¬Y@®´DË¿}Ã##ÆÄÄ0hÏ4ŽY%D‡Ž$-r…*‘6£–ÅJËÒáÀ¡”——‚¢hx( Û·mÅWï¹Eáµ7ÞGg×çP«·yæy§Ïô8é»ï°.Œâæ×B’xÓXZX‚^B'ð¬Ñý‰²´©Î”Ô¨L4Úˆ–ÄAY©‚¯ÝwKÎßÅŠª ]p{4jøÖÐðxtòô×/¾f>nf? Iâü@>¥+ æW ùv`’8ï¼'æÂΣ4Wé q·•$[eέ<•@âúnëùšf]#dM œàw²aÆy÷sáÜAȶü€5+t Bǧ€a(° ‰§ÁqŠ)!89Wº®D:g]ôñ]ØÔp³Þò9¥+Ò×{;î½ÿúÌó ªW,KuÒfk~˜ºk+Å0;Ee¹ Q`Á Ï2` 4CçT.¤äWYã‡EUóMw€7Tf¹|—Tˆ<Æ sá8OR«n–ÇÕÙ°ãÏۃΔ@¾½×ëÚÚÚ|$‰Žb.ìÈ1*Äs0iLíP“8XÑe®ñ¤j‚HŸ=ödÄ\8{Øíwb×~_ˆ æÂÎéµAÇí_©ÃÌL¢ —;iªŸ&£Ä'CÓ$x½"ä$ŸšÜÔ‡>=[ â>@ á㬬<ÏeY04mŒóÜcTÕ‹=ÿËŸ`íš*ÌÌFPZâC,KK–ä æÎ?1ÆcmÁÌLå$rD]UÃrziT®äFeE’¤p‡Íß±%qPQæÅC÷ݲ¬ï’fsA<3;A8Ô‘¤ª™ ã[$ILÌ[obüng’Àée?Ä\xqøas¹N‘$~ùœwNQtÙîW“B*Qã·û ‰¹pvȇßÉÚµkÉÀ¯ ˆ¹p~@Èš ¾¿ì؈Á¡qx½:YS¢IÐT ^E€,ê¥,VÅG¶IéÁ#sDǃ¾Ý’.‡¨¶îî»p ÇOv£¼¬σçXÐ I$öï=ú4Õ‹á‘Q}NÚl‰ƒÎnýsí|p:»ú@3:AÃÐ4hŠÊÊë(Uj>ƒ)SU󇿿}Ùß%S:a þ¯Ö9U /á„ ’ Û“Äöööb¸êjk ïpU 1΂T°Ë7*ů¦…‰-y$)œ2ïÌ/¾yóf[T EâWS›Ç¹EÌ…3€Ý~'PYYI~…066FÌ…óBÖ,s³­,W!Ë<ª*T<þØ­8}ö ™‡,óF‹nÝLx¹êDò= ÝWèÜÆ›3SÕƒãø÷ç^Âuµ5$¢(€ã9]Y³)öØÎûqux—.÷[ïÎ÷fkfxýAóÎGØ„Ÿœ1Õ"‰ò®å•åjÚù¼ÊhI”—yqÿ=õ+ò]¬ðª¥æñÁÃ8xø¨y;<‰=$I,Ú@Þog ŸBÖìwê#æÂKQ c(L¿Àr‘«ˆ]v¯E.<ÿr^ßíñ«Évûüä'?!ƒ¾‚ æÂù!k–ÈÕùçX[Yæqß½õøüìe° cü£@ÓËWœìî+ôÍ6iÃÍDU ŽãÿùXÓõPU^E$‰àXÖâY³0þè;ßÄ•þA'«ùþCÁ¤yUꓟB46çÇ2¿š4sTUªùømMUÍ×î»ÑX±ø. ô‰Î½PËÿñæ±äÅïH’¸À¤+¯ [ƒy‡+kó˜0sáâMüÌ1­­­µEQBÈšydü~¦Ä\ßíºÈAÈšÅAÌ… }}}¶¾1ž1^fBUç¯HN‚+T\é÷bhxëÖ”¦º#w¢& ã\¯£H…UßpïºóÖExàPötëo¬ƒOóBSUx½ DA˲_ …½«û ëÍ1‡ŒÁŒ2˜žÀ€IÞµíF¼ööq4Þ³ô2:&% ûÖ\°ÎçÕžS-‰ƒ†újø4 ‘H4íå¡WDYsîü N÷žDg×QŒŽDÐýÙÜUœÉqüIçctt4dKã IDATµî¾à×–<(kœ6¦Ä\ØacDüjVgms¨¢„øÕ¬âúnˆ¹pö æÂîA:²­££ÃÖÏ@Ì…ç@”5Ë :6ÕÏ7?Ú|˵øâìDÌÂË{³UM¡¶ìNWmeMß…Køië?ãT÷:QãSQR⃦y¡(xžÍÐðx–žÚ}.;1‰0?Gh2œô†¥0;µ¨krGŠoÍj_âôâªùî·îB‰&c6E,_öwI 81‡ïÝ„päèIó~^Ä‹.:gò™HÅÚ’‡+ú£Å<Lj¹pAŽ‘ÛæS]ÖDÒŽµ¨Ø”“v`1Îùð;!æÂ+‹÷ßßÖ÷#æÂ–ü AN0¯ŒÔÕ¦7¯ªY[‚Ëc¨¾¦4‡ÇÄãË÷«Aa3øfä²±~½ygÂ@øË/ðPTV”AQø4¯NÔ¨^x½2AË2†òK–AJVÖ8e³ ÀèÐt²» 2ð¦º5è ¢f])š‚^>”ÛœR$>m½JhI4ÔW£¡¾ýƒAôžÂMׯ1Êsÿ.Ð?„ª ( oïëÄàи¾À±žÙðTü‡. 8mM‹ ew¶Žëèè¨Syb.œ©'sá‚'kˆ¹°}ç^Šy|ÁÏ­<`Ä\8sawcll ï¾û®­ïIÌ…ç@Èšel¶ sáth¨¯ÁëïÇš 4íg¥=½ÅÈ–6ÒGuâÓŽ˜šƒg9H²MSÁódY‚¦záÓThš ¯W†(àXM/Yþ”@W×éT’Ä X +êü•xçƒSX»Æ‡X,ŠBÎsÊ굄ÕUÖø‘¢ªteOgw"ÑظîY³qãuãæõkž‰à·¯}jÞOÑñÀ¬ûT5yª»o/ô5Û.YtJòpâ³Ã\Ø¥æ¦Ä\xu@Ì…m&kŠDU“Ã%œ3a·ß 1^Ysáü‚5Ëä–2iÕT½ÔƒehÄ©8r-µëì¾P ®?)b>X\ÅÚj?8Ž˲ày¢(À«(P½ ¼^Š"AE“¨¡2$j]±ãÀ ·À``p¾EyêePñxîsŠJ.[Íè¦%qPÕ$ KË\ u},úÈ9›8Á ¯,ˆ¹p~Aiª®âo:OU“@(4møïäþýƒAœî¹MFñîþ.óo4o…»äɶ&‰iüjF }m!m»‰_ÃǨPjb.¬š¦²fÖw /žd…:®+ »ýNˆ¹pî æÂÎ!k–t,äW3G:Ô`pxÜ4„Í%)í M ”™EéŠôR⦅nGYY ÊËJQVZ‚Ÿ5Ñù‰cAç@Ô8”´ð8©æxAƒá¹…X[óüK‡PQ¦BàÙžÂÞ¹s¡z¹)Ib±¸©ÊöK…Ba¼õþI¬­*À³h{ã(¦ U '`df?" MÑòIk‹Êš”q 9æªýËb.ìúyçPE—íc`ñ«)ä¹e.êv•sáì¿b.¼² æÂù!k²Çœ¹°i󪉉pRÙJ¶8Y%PIîõµsíÐe™ÇÃ7àƒ}oBQ$(ŠIÁóùäw ) Ä<95Ð•Ü ÊiI„¹ù§š ǧrzÁþÁ ~ñüïà•ȲIâ@Qž´ í ¡%qNUèÊ¡X,nxÖdþÂoïëÄÑÎ^¬©Ô ÈYÀ;œ2ÿÎò¸ ‹ªÇmóŸ$‰+[ вÆIk‹ùåí2vá•ý-v&~Ä\Ø–quœ¹0QN®(üyÎbl|šW„O“02:Y,›BÆŠ¥† k°ÿ{øÚC;Á2 (J÷;ɪew÷i''TI¿õ¹ÞAƒ´ BUP Ce’Èc×ÎÛàñè%BgzúQV*ƒ¡i0 –¥!ð ƒ(°¢ÈAàYpšJª‚\©K}-s¿ezUMÿ`ŠÌƒ¡©9ï! õ×bÓÆkÑÙ݇“Ý}àyË€ã¼AÔˆ\Ò÷ø÷ßüÎ|]«j’’DrEEafÜEîg@ˆˆÌÆHßèmðôˆ¹° D…ãÌ… ¿:ç,!Áœ b.ìn²5® 8²1~üáí¦â­÷;19=xžáÀ² ¦§g03$óó¡ébÙpÍ®ªbqS)Yæ1|¶³‘¸h4Mem0|*Ù\؉ã:šJn¼·ÿn¹¹Ú 7æwÀºgûMøJC-^yë(ª*5H"žg!ò,x…À³ày<Ë€a(Ð Í·\k}›Í+ô;.©ªyoÿ)lÜP †¡AÑÔ¼¶ë õ5¨«­ÄkðÊ"$‘ƒ$r„¹ïñáÁ/8?d>/<‰&·¯-¤õ¨»“$«Ilc.5nÌcBMÌ…‹„¬!D©{×÷”q €`I¿wƒmÎ1ÎaSÈÄ\¸³»åej’âëoÁw¿»¾vX†ÆXp<Ç ¤D" ð*4U„Ï'¡Ä'ãrÿhÑm¸uµKm42™™YDc±¬; ÀƒnWó’ëçQUá— ZèD¬ä'È2ïüþ¸:<žg zE¨ªU¡¥OÇ€ahДi š—«®i™#\Ò«j>>|U8VWþ04µàwùƒÇïÀÕ«` ^ÃY–xˆ‚® úuÛaóñ¼ˆ]<‰üêÀ›KnÛMÌ…=FÄ\¸°Ç5ŸÝ°Ú‹!v$~5ùñ;)<²5®Ý21>ýåhª˜V !Ë<¾±s+îÞv#B“3P$^'iT¤ñi‚ã“Å’Pù­ U&åeñجNÖD"ˆÇôV[ñ,‡› ÏKôNt÷ASE“à ) £ívº-èÛ»¶¡'0h”jŽÑŸk”:Ar]29¶œ(²K¨jz¼:M•æ>OßåËÀX–ÇéeQ,CãµwŽ'uJ OᇅÐ9¡°jk¶e-56ÍË#æÂK£HZ+Û:¦i]íN:÷òd.L”5Ž®åÄïÄ= d!k jSXÊ\øxg/4U^R Qç¯Ä®[qñòT¯M“ ©4¯ˆÁñbI¨Ì@¦¡¾:£'(2ƒÙÙYD¢QÄb±¬”5]É%PcpYƒ8Ì2&–aôÒ/} [ðÉÜ¿ Ç:{Ay< ( ™+7š›‹Jrç­åD‘-Öß1•Ðì à“£=¨(õæô]:ŽŒE˜œšÁs/4ÿÎ ø{—Ÿ#¤Má'Šy޹Ð\ØÀŒòI©JA¬m'È` …­œ´õœ%æÂÙø¸„lsY“9vXI–…ÐÀéž++!d™Ç®[qö\?¤„qªÀaxt¢Xª¬:l%‰DÆ EMælÍ©dsa'o¶æg¼:IÒ=hÆ ^¨Å‰fYæQ[]†Þ¾A“ÐJÌ=ëLó\#ÉF,¢ª9ÖÙ‹ÃG{°¦Jƒ$q¹}—š2 ‹Çñò›Gš hÆž™†›u“~ä×\˜\u-|‚‚̱,æŠ]æÂE’øåÓ«¥ÝicådQxÚqΦ¬ï…ì1µb ~'î!ÛœBÖd¹Ù.f. …±ï£Ï°¶ª$+õ€,óظ~Îõ‚¦(04…®Ï/&í¿Å0¶™”—Àx(‚X,Šx,–Uù:|Ô‰Á\:˜WÃÆ‚“%§—¥ªcBC} .õ!‰!‹!‹§{+€–ÄÁöÛn0ÇþÁ ž}ázû®bM¥E ÈBÎßåÌ—W0œÂ+o3ï§™x+Ü}åÐvsá"2Il$…ýsŒ˜ “ÄÏb.léXD[«³®Ú™ ~'î!ÛœÒ *ËMa!sážÀ~z7ÔU椨óWâËÀ&BÓ`YƒÁbI¨2R,Y!Š"âñ9=M¦|Í+¯½ƒwßwM«T3ê A8°£wO¢2/ß\ýôŒbÝÚRÐ4ÝßgŽIQÖäI6ZÃïï¾=œèêÃÔô J4’ÄA‘…$£ã\¾K‰OÆÿ÷oû1i¨j8c3SøI¡¬-vœ£££nL¤sMlmUíà+ÚÄ\˜$~ù€yÒ¹¹°¹?æÁ·(”5E¬Úr ˆßIámÎQÖdÈ¥S¼½¯G;{±vMɲÔ5Þ‚£'ˆD¢I橼1˜;le¹šQ;tøâtúÔÔ)-5®¯¼öþîÿï8y|?®»*Q5ÝJÏö\CSf§L·Ÿ:%.\Á¬Q6–ª®Q–¯¬iIÜtýìû° '` å¥ E'iT¯Et“crþ.œ1oÏLaÜ_ߘÇ$ñ ¤º3æ1.ÞÄ/ßæÂÇ4š¦åƒ¬ ÃOÊËœ âwâ²ÍÙ Êš,7«áà‘³8w~ª"ê‰éJ¨4ŸíI›° Ì$¢acf%P¡P‘È F»ðÔS€‡E h¼ïk°žÓÞF†‡10p4&Á±À`2Öë‚@&Ã@o*< Š¢²"7  ‘H1–1ÔHq$Jò*+4ëCwäðû™ÏÙºÙÕ+›< Iä!K$‰×ý˜¸„Ú,ûïòì Ìc–ÇÕÙ0ö’€“òN (Þx÷,b.\xk›S]~;Ç€“;Ò­ôÜÒ³cl÷ïß_ çìŠø¸?úÑl}?B¶- BÖd3! Nâí}ziŠÈ¡¼T pP$Š¢«j–£¸kÛøçgö]Bu}mEFOè8q kPêS zEˆ‹p8‚ŽÃ¯áì¹~ š¡@Ó†Ï2à9‚ÀâÔçܶÙO̽Àù!ܽí&äÂ1s,ƒÙÙ(¢| L,PÓp8S5Óh1¿ëªPY®íÂu¿&QÐ[‡‹ gÁçÄ\+ûÌߨ'0€÷÷w™·gÃø“˜ÿ~ØlüZŒæ“Ež|Û>Lj¹ðÒ æÂE3ïòIXò…¾|wØ*ä¸|E@üNÜÛß“m ƒ”Ae±)p,ƒééYÌÌDàÓ$¨Š¯"BSõ^£Ìc9êº:Q, •I‚ej.|y` ,C'µDWwßqš¿s/TUÀl$ g!K‚Ñ]D‰OÂÐÕ¤vèí.óêüÀ`¹Š™ÇD(Œh4Žx<>Ïã§²\M›äf ›¿ßûN„BÓðzhª„£ ½W ‹¼N^2´n¶íÉþœxê˜Ç¼„Ú imÉ“¹p!¯-ù46m/Ö9FÌ…³ž+nPxºñ<^Œs+…Œ/dBÁW¢„s&ˆß‰»qéÒ%Ûß“m ƒ5Y»åe DÕË,$€O•àõŠºO ?GÔä’”ÀøÄtÚ„½P7[Yâ32~{_'ª¯)Çê^@éZ¢?úÐl¿õzLN…áUhªŸ*AóJ8ÛÓïÔ„jÁø3q004–ó‹4Ô×àÒ壅w|^­ªÊœÔ5­‰ƒûï­Çm_¹[jqe` ŠÌC–õò'QàtE Cg­2K ³»Ýsª¨ð$öÚÚb—D¾Hʠ̵¥¶¶¶ØM=I)Š³Çˆ˜ ö¸š‹1^ùEÌ…óâwRxH)§\u²mq²&‹@®¢L… °PU>MB‰&ë꯸"êB¡ébØ­dÂRè <3 Eáõ䟥AQž´-Ñëü•غÉÁ¡ nø¬ÇäԌۙÀaq!ç …Â&I“®qVŠoM&ÙJ3,WM¿ûí»ÌqßpÃ5ô eãŸ^’FåHÔÉ^5†ª¦½ÐλȚ"éek ?::êdŸ[ç1& u>ÆÔÁŠ®|z! tnùA<¦b.ì¤#Û>ÿüs[?!Û!k²:¾þÈW084–¡M@–xˆ»lõ€—®$‰i UYÓ”8¸óö–$Žë1=Qx‹÷ÉBæÍuþJÜ|ÓZ\¸< ŽeÐwiØúg·\ñ ¤ŽC.èé@ͺR½ü) [“â[“É%ЖÄÁý÷Ö£ªB›kî¯ÄädØl¯ “´ÌíœxoWªª¦‰$4¹!MùE¡¢ÑÎ@>e\O9檤&ßæÂí…7±¢«ÑîDrtt´Hs\í*&æÂÙa``€˜ »Ä\ØY dÍÒØa%¾½kÎô\Ï1à9œÑž{¹ê+¦Ã³…¾1ø`Qf,¦¬ …ÂxáÕOpÍšH"!QVCÓ&Q³ÐxëÄÁ &'Ãèúü¢[d3ùëéÍÍðkb ’G‘ø´Aöh¶&7 U_»¯G;ˆD£ˆÇæ{ädƒgcQÕˆx…sµÐ›_Sù >ëšMÌ…‰¹p¦¤1^q-âsмðaG TR¡P×øÆ<Î-b.œˆß‰»AÌ…BÖdpÈo*¹Ž?§€¥äiùDMO` uc(D˜êˆÊruÁŽD=<÷ÛC¨­)‡"%Lj¹pÖ‰_; DÑ•2v¨‹Rο@Î-[Éx€˜ g âwâ~²Íy ž5‹#É\8 õ5è»p‘H ±XlYFªæB—£/‰7Ûu×”b`p ±X^¯ˆRŸ¯"@õŠÐTýŸW±5ŒN8dë tèÈY7Èfpp®w0«'vv÷AS%p,†¡@Óžy-徿·o¹%>95éMEKâà¯nÄšJuÉ÷÷*f#QDc1Äc]“Á9òì LU 'blf…¦‘ôÃfãW (ŒM͵e×®]ùHÚ‹yŽsar¦Žk‘{ŠØ¾Æ[(Àyå‡Å ‰˜ ;ÄïÄÝ d›3AÈš «¹ð¼¤=˜D‹Æ_¶æô—W¬7 ñê·™P=úµÍ˜…Á³4d‰‡WáS%ø4>M†×+BNò©¡æ‘ K¡'0êÔî²ñ…Åh:Å€zA„Baœúì4UÇÒ`Y4EÁ“¦ƒV¿e%JjPdE3–è•v­ÐÐwiQãÜÈäôè âå7çT53SØS€çíæÂ Ì«BC³<@Ì…Í̘ g;Wˆ¹ðꌫãÌ…íºjŠ&vܼy³->@¤*{¿wƒmÎ!k2Øl­æÂ©`³3D£1Äbz×›\9›Îî>ã5 vs0K d‰ÇÎ6¡ù;÷bb2 žcu5&™ŠYäÁs £5z¶DMbL-xÙ¥ãf΃âiA¼ôú§¨^[ gÁó,ÃçÇ jæOö†k­7S£ –ÄÁ;6.H\¦¢ªBÅÔ䌡:ËŒÌ|ö…¹VÝ,«öòÚb××”@¾»Ìù­I¢]~5‚bÌaë5)EqösáÂWÛÛv§¬ñ…8¿šÍƒæf{/b.¼(ˆßIámÎ!k2äRÍ…­Ð¼â\©G¿€ò2/d‰‡$ñD¾PÉš&X$çî¸eÁ>Ôx ö}Øm·ÖéÝ‹<¹+k\Þ²;m š ãÅW`f&EA–8”ødˆ QäLÏIä Ü\¨ìÇpOâ7“$» ØB(å¡ñHãhF)ÔG‡¾ÀùKCˆF£(óiðx€«Ã¸xy}‡Íç†'ÑT k QÕ¬šÍ›®º¶µ%q¿mÅ<Lj¹0IüR Š"7Nñ¬Y6L2~×®]¶•@sáÅAüN „ls.Y³D ·˜¹0œú¼3‘YlÿÊM¸yýÚ%Øc½¸xyK£²B…(pPC Q¸Ês³}`ÇÆ%3‘fg£sŒrX{;»ûÌÎIÆãq×ûŸô&È“+c¸¶º Ë€ãüQ# ¬©¨a“ÊŸ–&½®«­À¹^S¹ó³ÄÁ7þ dC=–éOñáÁ/Pç¯0ÞŸ‚(°øêàñxpê³>œìîƒ$ñ¨(óâ­÷;Íçñ"^ O´Ü¸ÑÎ$±Ð £äGÓ4Û®ºsaׄ¬qù˜ºTÑE|°øÕØEÆÑ9»¢ ~'î!ÛÜBÖ,t,f. …Qêóâ+ µ8ÓÓ—ßè€ ²$<£+úƒà9ƒWƒŸ˜F‰O†¦Šà9‚ÀêJ™‡"ñy6•˜Ø÷3ú°øÿdâ{rSÝôQ³®ÔèŽϺê EUã·0' ²&49c3‰ŽO‰cžgÀ³ h†ÊÚ YIC¢I"‡ß{xKVDM(ÆÔt,Cƒa(д'I!ÕP_ƒ†ú¼ñÞ t~ ãSæsÃSøa±¬-v]!,p˜Ñ{SS“-W±@ªÿHQ+kˆ¹pÖ‰_{ž‹DÑ5sqÏ“²Æ‡Â(…j†AÆ×ÖÖÚFÆÄ\8[¿÷ƒmÎ1NŒÌ…:oª¶m­Ãã݆¯m+6øq©GOöbxdƒWÇÁ04ª*4(²Õ+BÓD”ø$hšUÑýEXŽIíÊSúÙ–ÄAC}uFÝ„êü•8á*"‘b±ÜÚ¡S Á±Ådxwßq#Æ‚“ÏFÁÒtÚ²§l+?S•5Û¶ÖA8dÊÖ||ø4††‚ðižÏ1` ÏšT/¦P(Œ—ߘûh&ÞZÀI̼óÙn¿š”÷+í©Àns¡±IU3::šÚ²›˜ Ϙ oâ×h..Ä\˜`…ãÇææf[ËɈ¹ð’ñ9ñ;)0²ÍÙ dÍ"ÜBäBO`áð …_R=ÿáñ;pep 4å, $¢¨û‹p)&°k*Õ´ŸÅ…h†EUóýÿt_VOŽÅâF TBY“9ks¨ðJ ‹ ·³û½Déd×yÄâ1 ŽœÔ4VX=kd‰Gýúu?÷ãçÑ?Di©’ÈCHf9V2yôì LhšAxfŰr7Ú™$Z‘&Ðu»j¯5q°cÇÛJÊRJ záM„W¡(ºrLàY0L‚ŒL~î³/0YWá<ßÕ€y6N xÝLÖ´˜‹µªš4%P{<ÇìHš]˜ÔsáUWb.œ§“¿pÖ÷=‰uLÓ4[Éø4s‹˜ gâwânØ]²-[ÖÝ ©æÂÇ:{ñù™Ë¸¦JËH=²Ì£Ô'#81…Ÿl&²©m©ëü•8×;hÆ>p—:¤ –«ÞßýÖóŒk3ÁðH(«Ç÷ñÑ¡tqÑzwkÍOS}Ò0UX%šŒÙH,C#Nű%ae¹Š7bt,„PhMC–xœëÄäô †‡'ŸÂÈX¥>e^EÒ ´½²QÔILš™ß‘ª'0€÷÷w™ï7.øVÝÖDÚÖ$1ÖäÚ­ÁüXõÖVûNñ½{÷&Å7Lm5NIjÜ’4›L1^Qsá|ŸüÉãîÖõ} €›‹ýž=¶·>'D ó“}âw²²¸xñ¢íïIȶì@Èš‚Ý„¹pÿ`ïí?Y°¦Ro½‰z`!ܵíF¼þîqì¸kƒnJì™ÿÜ;o»ÁšÐ6ÁҾР©™Ñ4ÔWc×£·fý"œEÅšõè:â£øYÜu{õ¼Çõpáò†F¦áõVbpxîo 㱂Ûhà Â&ŒR/ؼñZœè:ͯ5üâóÀLQç¯ÄC;nÁÁ#g1==ƒ>îdzx¬AL24…ª <ÇBXH’NÖ$¼˜ŽCS Ó´ê˜Ç¢‚®©‰¢PÕØž$fÌ7ºp }°¨jvïÞmëX¦5N$‚I)Š³Çˆ˜ “qµk}׌¹î¶±iµÎ%»U5iæV;™YÉ ~'…‡sçÎÙú~„l#dÍŠrš*á•7bb2ŒMÖRY˜ëâ´ˆz`)hªŒ™Ù¨Y>¥?oîÉ›êk K|Â{¥Ö†œ¾iø +€Ìò§ÿò;sz¡Ù(‹‡¼å¥Ð4ƒCWqôèItžê†$DŸË ðª¼ê ¨+e <~ñÜksJ ?-ÀùiFÝ}æ²Ìczz‘h ¬Q6–ë¶õýÝ÷¡ãD5ëJQZ¢@SE?u. ÃëeÁ248ŽÀ3]]& zûp!Ñ>ÜðpJ=':»ûLsd˜šÀ_ãÚ’/²&¥<¡:¹pњ닦i¶ªjŽ?žZÎâDµcc‰ˆvr-©@Ì…—˜v­ù;vì°ª']6çZ`QM¦ãù"k˜ˆß‰{Žlëìì´õ3²-{Ïš‚Qäà¡<(/U (:I£zž‹«–ÂuUè=?„H4Š˜a k=}d™ÇöÛo°>¥Ùc× ‹ú¿üÅ#‹zž,„P(ŒHLCÓ i”ǃk«×â÷ ÷·ÿÕ×n@eU-j®­Ce娪%%½0<œ¤0ß[€óÓü‚ýÁyŒF£†ÇO|Yo2‰‚e lšÂÝÛnă;nÁðH^E€¦Šði2|šM•àõŠE^7Ûfh³,p1¯^ ×U«¼“5>Ÿ/µ«ÉEã·'5·SŸ’8ì‡3I.BD,q €˜ Ú¼sª¢Ëü\££öU¾55%-é.›CfùÓO<‘_7€˜ g âwâ~²5nƒ™ T_S ¯"@õŠð©4U„×JÔ0éÕ™ ªBÅÕáqD¢1Äb1“°±â¡­7wÃâyá@ì5>#à;·âÎd²)c|x¸·Þz‡‘ôÓð˜Ý²t|÷Ç7›vbhhšª¢´Ä‡ò²R|°?I†ù ÓÀ ö†’ÉÕ+ó)ûVçV¼½ï$*˽à8Æ,{¢(½¥ü7» ¾!“¸ô*™‡˜0ÚfèÉ˃GÎ&©j“® ]›$.„æææTÄ hð³Ä]»v¥&%«ŠÑÑÑT²f¯C“b.œ!©@Ì…Wg\íXÛˆ_ÍÂHYw9mov˜ªšñ„§&ðƒb^[œ@Ö¤Q×ì…³®¾nI]cž~úé¼ò)ÄÖ3p.ÑhÖ>åÁ8—˜ /=Fídm[ñ1ur»xó÷¶[Y“fÝzÎ*wM5æšµ{÷n[»û-b.œˆß‰ûAÈ6w€5i‚Ýõ7á¿ûm\è§‹Ç8Lߎ•âÿ†GC:IƒÅu(²Ìã¿ýpd‰OÜ• lì¾î7Þ÷%Xê‹wíÜŠ{·¯‡À³F'¢Ì_ðw‡Ïâȉ«¸óÎûáÓ¼ði*¼^’$‚eYP ð¾ —ðëçÚuGgñ£"˜§f80¨ûhô‰GðÖ¾xûý“8õù„Bá´ÍLJNã•7â½ý]àX•åªa¤­“5’ÈÏÀ@[–yÌÌF03ÑKùÒüð¡P/¿qÔ¼M3ñV®oƒc’ÄLÐÚÚ MÓR×'6MÆg©Í7QÓÞÞž¼ïuz¬iü~?Ij#b.¼:ãJ°$8WlAsssêˆß½{wÞÚt/2·ˆ¹p ~'î!Û܆ ArÀ¡zÔTë“iÓ¦­è¿ø)*ËhPñ8h¯ a3:Êø±uþJüåÿôþÏÿñ†5¹z À“Ð%®«™û÷Hº/‰~ð—;Qç¯Ä ¯µÕåð*BF/xðÈYô…q­ÿf¬ó—çyQR⃦©P σa³g!…ÜOöÏsD‹þèlA¶ë^0ì >;} wݺ¥F)S4ÃûváêÈY@x&`‚ 7W”)x¢ÈA–xSQ“ìU³ø¹©n úƒ¨Y[j(ÏâIçGÛ›M† ¢Æž™Žÿ¤˜×–|› [áóù°wï^<þøãæÇ3Ȉfä‡PóëÌÖ;óEÔó®Nïwpr˜Ou1Nb.lËÜs2HýÜv«*÷îÝ‹ÆÆÆ„9z‚oÌã\ÜKW?'5.›[Žñ;q7ÙæeMJ°»±~½yç]ÛoEÿU ‘H4©ËÎrÑ?ÄàÈ^}·¿;tƒCã‹¿úí!\¸<‚o}c8.‰_{ Z°²-}FÒÖà\*Q³ý¶°÷|wÞ~¾8Ó{î~”p=W¼ýñe´èEçg}è ¢'0€Îî>||ø,ÞÝmo-ÔbCýí¨¨¨Di‰†ÒŸ¡ª‘!Š¢Þ2šZÜ«æÀ¡ŽTUÍŸÉ\5ƒÀÐdƒAÌÌFu‚ÅPÃÈ]nÅÿüG;°îšD£1£ý¼YâÍÖÛš&Á§ÉfnÉ0Ñ^ª³SuþJ\¸x‘hlžïRÿ`¿|a®:'Ä€âSÕØž$fƒ¦¦&<ñD7²Ë8çýv#86?Œ¦iøàƒòFÔ¤QÕ´¸aÿ"%PK!V~m#æÂé?îóÁž ¿eKjiÑfc̶äažO%jž~úiÇ5i~£v’%ƒøÙæeMJ w×·&ý¡ºÚÙH,C#NÅÍ®7ËÁg.aÇõ(õ)P½"NvǾº¡zEÝÀØãA(4X,Qâ Ëx½d¹ œÄ@Ö¬ã8ˆ¢Y– (24Õ ¯W¢HEË€¢éE‰ YUÃK8ž,x¯+N^yë¶4\ –¡Á$K¢dîÙ~¾ÒP‹¶7:°öŸNÈ𬮪XžgÀ³LNÞL², "gÇÍßìÙæL…YW§&ðOž¶8¬ôr¨ÑÑQ<óÌ3©} V¿óQ£ñ>IëÍæÍ›ÑÖÖfK9ÏBp‘ª&ßDD;9‹–¬!Š®%>rbmËYÀ$»¿÷½ï%îªp Àßëûj^@I»¾×ÖÖ¢­­Íqû!QÖdâwâ²5tÜbQÖÀWïÙŽßüº7^G›ŠƒxË*…º<0†ò2/†M{°ý¶pÏö› Íàßa|bŠ,€ah0 –Õ‰AÐìÿõ¯Eljž{ñ &§f¬/½#ecìµ4í)ß×g9Öû¼ õÕØµóVÜyû É'zwÖoh˱`hEÁjª×âO¿÷GÇñÔ¿þ4MC‘%I!Ë’IÖ(²I!ðÁúë½P½¢NÐð,8–Ë$æ6µh ît˜™‰ M˜ ëLýƒãx—ù˜Ùpѵêv YèryŸÏ‡'Ÿ|2q—ý*è#Øn[Á Þ]I³_@WÓìÙ³'•(±.SÕÀºæ""-ˆ¹pá‘5n˜wí0Ô‚)eqù&lýâ^³AØì]ÁõÝgYßçÕý>ñÄhii±E…•-ˆ¹pv ~'î!ÛYã6$™ [¡ª^Ä="‘X&†XÌc(rÃLJO£úšR=Áf oãõ…Ç£mAÿ`oïëÄu×–ƒãS ÁóŒñß׀ƻ7àÈñsxå£ñ@ßPºUk Rwdó9ËK½ñ»ï¸ÑóàŽ¨ó§¯1 \œÂªÁ±¬á1C%ªêÅ÷ü^{ã=\AI‰ŠAÒȲQ @08Ž¿ý»Ÿš·•¼=1Rt’ÕöÄïéô6Û,†NŒ_ú'}ûÛð›—?ÁWïÚgÁ²:hUÓÙ‘¢È!It5£ÿðOoÎý]A×ÔDQx 9"IÌ­­­hllDsssÂã ±~ýwnÐÛÒ¯@Kúh,†hTWÖœìêéÏ.˜›šÀ_‘µÅYæÂ ¡©© @---V•  +mv#Ù»*‘±¦÷‰¬Í·PàîT’ÐI«” ¦Ù-sŒ”¢,ˆF;ǨÍ…í8]¨¬…¥d¹½½=o\‰¹ŸXß[[[­¤< û•í²Ü>a™·íéÎ%dpp×®]سg£/T¸tnåÄïÄÝ d!k\›PmL)J ¬¢³3çÅÀÄâ@Ž¥P/½Þ믫€À³Y£—ž¤SêÈ2Ÿ¤„àyœ¡ž hÊ(w™d×ù+Qç¯Ä®Go* £§w€nöÚo´y¾xy•å*Ößp xŽªJ¸Þ_ t¦ß£³»^Ÿ¥¥åD<Ïf˜E —Çv>€×ßÚ‡K—úÑpËp<ŽeA›þ4X’¨yëv¼õî\Ü@³ñGf‹Ò´ÖLÆ‚“œE™´d™Gͺ2 ±îš’Ìô02BU¥f¶îþå‹s¦Â†—P{¯-¶&‰+ŸÏ‡ÖÖVìÙ³­­­Ø»wojPŸ.Pß•U†·y3š››ÑÜÜì(9|"‘±àIÄ\8‹1"å:+¿¶E×¢hO5mmmy%khiiIZ߸¾9R&ÝúÞÔÔä>Ës¶˜c–´ ~'…B¶²ÆµdMª¹°e¡B42§È…¨yþ¥C¨ªÔLCWŽc Ÿ—ÅKOæ)!èÌJVd™7€,÷îøU4U„$r`˜ìÒõžÀú®DqÛm7B–E]YÃq`hjq1ÏcÜgŸ{ ·l\ñÙçþ-> Áà8žøë›·•|91‚ÿ^¤sÖŒ,.^À³ñ—™:¦¡¾o¾wUª¥ô,·2šNš[VUMxÒñª„‚JW~¿­­­hmmE{{;ÚÚÚpüøñÔ„)#ìØ±[¶l1eøNô+ZÖ ç{Õ䛈h'çaÑ’5DÑ•öÂð­yùå—1::êˆõÏçó¡¥¥---8~ü8ÚÚÚÒyueLÎlÙ²hllt AS„ç슂ø¸„l#dMA·, ¬…Â%ÚÇ“ºÞ,…P(ŒWß>M¡È<.]Á—çððý  èäÎ= ‘. )!r™æ¡É°þdÛ‰üºº ›nÓÍ¢(è­¶iÝ\x)|ý±ñbÛøæ®`YAYóŸþµYþÄñttb$ú`ÏÙ$5Ñhpk×”dUÎäÓ$Œ§PZB›$O<ži …Ñwe ÓŸôbë-Õøù³s/âÅðTÑ=®%k¬Há 3ÈM"yÁºõØéhmmMMTöÀå+Ä\x‰¥Ä\xU×6¢èZü£C'~kÝÌ}ÏgõCHéf<1:jŽw¡§[7* IDAT¬ïK˜ gâwâ~²5nÂæÂ Ä¢aÄGrrQôp¨ãK”údÈYâqìd|üï¹’ÈÙ®„È…Èì bßGgpÓ†¯ ¬¬šê…¦z¡È’aÌÀcøÕ,õúªêEEy9¦Ã3`ä‰S4€… °¿ýß~šÔýI­ˆýåÐ…¢7€ÛŸ˜»ÃèY[Šl|gî¼ýìû°·o­M{àñÐYÏ©ÝðWþŸQYY†Ÿ?ók › Ou(Û“Ä„¬ÝXƒt§{d‚4åO/C7TvMÂLJQ–#b.¼:ãJ]Kb/ôîKf‰©£7.ŸÏ\×°¾···¯êç æÂÙƒø¸„ls¨"ÿþKš À''1<ʘèè â¥×;p¸ãK”•(%Š"@–y\êÅäÔ ^xùSU“ÉËV¯-Áå1D¢1³Er<žý>ÞÕ‡žÃ•þñ%-œÅ»ûÏàÓÎQ4l¾eeå(ñ©ði*¼^’$‚eYP‘ª&¯Þ³ û?:„ÙÙ¢Ñâ‹h|žáUüË¿>gÞ.]ãùÝÐ…øSäÔ (N}~¹S4…ÙH±höD$Œã`9SÓa¼ùÖ>ó~QÁÓ$à±7IlkkÃÞ½{ÉY‘ššš¬åOc€kÊ÷H)ÊÒh´sŒŠÑ\˜(º–Ä^k’”Ï6ÞnÞ={V}¼H Tö°ÛïäoþæoÈ ¯ Ùæ>»²fIsá·ÞiGÃ-[q:ð9Î]8 ŸÂ¢¢Ü‹ëk« (<½¤§wÀ4ò¥i^™‡ª¨E²ÌC‘(¾‹Ã€Wß>†¦ÇnEU…–Ñm¨¯Á¾»±¦BËY qðÈYüÑܺëüø²§=—¯¢çÜYPÔ88’(†G§13 T­©AÅ‚ÀC–%hª>M…ϧBQ$› §A%õÔ\8nESs3U±û«Èö2Ó .Ÿ‡ÿ½~=Ö~g-&Mž¿?]Wá2Tx=:|^>Ÿ ¿>Ÿ¯G‡ËPQwê|Æãï§[žÛÝïVQd»"aÂ46êDu4=Ðíµn¸îj|ç[_ÃÕK¯À…Hn·~¿y¡ òC(,ÈG~^Á >Ÿ.äDgÙíæ‚?jëN!OÀ4ÍŒ‰P© &ÕPXÓ$_n}âí*«†Y‡sÂZßôƒÄã¦=ÍêÿT¨?¼t×]÷A†Ž'·lE[[{2¨"Ñ `„>Ja `÷DHoI=«ªªrIÛ`7OØ\øâ2úF1Ðþc+ºúÿ2’Ç` ÞÇöNíWÓ§O¿ä•¢l.<0£ÑïdÊ”)|ã‡I$ÁÃ?<¢ÏÉæÂ k†íd·§æÂ¿yâÌŸ7ªª@‘SU$¢S}PK,ÀäÉSávxtó“ÎmІs‘|›$óØ2Í…³N8QQQÁžy¯ÊÊʲ —cü…Œl.Ü·²‘|&PsaVt ò¥Àî]c'7«W³ 2+¨)++Ë<9jt…~'l.<¼Ž=:âÏÉæÂ k†åd7»¹pmÝ)¼±{&O*‚aèÐ4Šœ 8z~°ë¯½ ³æ,EÇ šª@S¨Š E– Iv¸ñnM£sÍ…v~5øÁO¶`p=€Jˆ×Á噊P0Ôï×âóyqãuWãÈÑPUªf÷¯‘¤®g8¦Zf×kùÍïžÁ_ÝÑ=¨9ºÛú"?¦½rLmýû²5µtôë~íí<^¹“`zÉ,x›Õ ðùŒ~WB¼úú1Ä…3ÀÈkY¸`Âá6„Ãm©£crÅ' KPS[w †ËüÇ=Œo|ë»NP£ë Þ(üˆAMßçξ1ˆ&ÃÑH¬_ûг/Å¢+®G(/¿~Ÿÿï?qFÚò¤4:ýj’ƒ€ÀžWÎ@ŸAͪq|‚Ω(}+©AßD kXÑ5¸\öŠs€-[¶`Æ jzjFá÷'+kú0ýNØ\xx½ñÆ#ú|l.̰fØN:RÍ…<Œ?ðKÌ›; ~_ÚôM…,Kľ÷¯O•ï»`OUJKT²úÒl€újëŽÂé‚óêÅm.Ø´wDà÷ýzqxébaúôÙƒ~-wüõ'ñò+¯#‹ÁL˜°†ñͯ­;`À5ÿô]üÇuü5MÂU+÷xÅú:?ž}ªîÚ¿üÍíÑd` mwØw°Ͼ°•[BqMÇKÞŸÏ‹P0€€ß‡cÇ«ñæ[ûûG;±Š›bt4=œl®K° œ•Wzj6ã—Å©(}[2ŠïQU®Û€ Z%Ò¦C­Y³fÂN[½XPÃæÂcÏhô;asááÃæÂã×D^ºÛ9Ù>m *ýš›[0wÎ ü^ü>x½¸\E(JÐwÀáóy1cÖ´wž€,KD ‚Ð-¬éj[c•†Š¤†óõ‰Àlà÷Ñn}®©.C½èóï;X‹£ï†Q2ór„Bù|ƒ~-PÂÙsM˜TTIa‰kÈÕ5OU>‡ß>ù,"Ñ®êŽü"Ã*œ}ás¯>i=ÎfÿÎe»‚— úÆW_?(…xþ•xtùy>t^ˆCVtäçaÊ´hª ]×àv»àñ¸íÐÏçÅÿèÚ<š {#,N3jÍ…“Ä ÉÕ°qãF”––NØ*› 6`Íš5Ù_ïA §¢ô­l$}› Ðñ-W¬N¾—K ¼¼UUU#òžŽ™“—d£÷¬Õ…ZøGbÿbsá~'ì6¿&jeó[@×5<û‡— @qñ>ƒøý>x<.èš–lÈ+ô{ ÐÇWÜŒ÷êˆÇÉ•›€·3Àfü–˜z¹y?_tFÛ/n;€¯~ëÝšŸojí±âDu^Þ~¿}z?Z:X°è"ô#ð#ükYñÑáÍ=û‹Å»U F8ÜŠýîýxô±ÊŒ fÊL9råŠÈ²ƒ¯2¨çäbßÁº}cSk¾ùCø§5wãšknD,áAñôù()™ƒPÈžî ŸŸ‡üüòóCýعkví~ÛyœHXºÑ˱eš ïI8#ÇU«VM¸•Gš››Q^^žÔ´XŽñ?eSQÆØ{ÄæÂ#z|ˉCìéPNÿš²²²nÍâsUee%ÊÊʲƒš°«ŽFdÿ⨋ ýNØ\xx±¹0Úq{²{Ù¤BLž\¿ß‡PÐïLõðzÝ0 Š"jõ#Eõ#OÀLØMtÓ› gÿbx»Êª™¾Èš?k±îÔé¿[ÓˆU_{Ûß°Žõa$?^Ú~ϾpU¯žÄ‹¯œDåÖ#8ըšE‹®Á”)ÅÈ ‘ "ðÃãÚkQ‘hÔ^fÛ4ý¦o}¾ 7}ìsxðáÍ__üAaÿÍ_°&=ÿˆù~$¤l0ßôÚÎãX¼ø}Ðu ªªâÖ}ÿð•;ÑÚÚ ÃÐ ú‘—BAA BÈÏ !”\ºýßîÿ±ó8./ž›òõºMFb0ÓKÅCsòçÈlÖ­[7!6@ê/Ô[¶lÉ@—åÈþÊ©(c,¬asá=¾åŠ=ÉcÒ„ lÖ­[‡Ûo¿½§i©«Ó²¹ðØ3ÒýNØ\xðØ\˜aMNt\>Ž]ArÂTP£*2DIÔêGsçÎC,jW£œihÉh.ÜÓIÇÛUVÍŸ•ÌZ*¼—úZ{G÷ýûüà'[±}W5nýØ­Xóµ¯áê÷}QÓƒ`þtÌœµù…“{­„ðù

õÙ/aË3/ÀðaÍ׿„ÆÆó0t­ÇJ]× (Ê ¦>¥[¸`NŸi°§AYÐGUÍã¿{Ÿúì]ø«;îÂožx&ã¶©34¬¸KÜxðUkRÅÚAN Ön[q%Ün­Ï æ÷ÏÄõ7Þd7 v»aº=5N3Nÿ×ïÄ®7߆ Š$ ’$bÃrª¢dEˆF:ÁeÕ{Þ.£Õ\¸·ÏR*°qæíÝ»K—.͉iQUUU())ÁªU«²Ëê÷X »árN˜9¥Weé'‹l.<üû°KØ8%(--×+E¥ŽÏkÖ¬É>>oL¾Þ==}nÙ\xìasáñͅ֌۷ۅysgv-k=LáFŠ$»`Yöªð‰Ü ›ÌûoþbtÖ’åÂqMïZ´ëô™|ë;ÿ —Þ„{ÿ׿ãCe×aÿ;GXpgUBH² q˜^‹ –iö:ýéÀÁÃø×ïÞy‹—aõ7×u«¤™Z@ÙçÄWoúñÏýÌdSÚ¡YäŠ n—†ò]uÑ;Ÿ¨nÀóÛŽáýï/ƒ×ãIîïtM…¢ÈD±[Ãék®º»ß|¦i¢¥¥5£Ï(Y?Dî6ЖcËH4Î:‰¿Øq¥vuIFýùúõëQRR2.KîS•4=Lyj]M“KÓžÆÊ€™Í…ûþ²¹ð¥Ù÷&Âvö$÷]'­©©ÁòåËQ^^ÞÓ´×1Ò”••õt|®Ýä}uŸ“ѪJå ³Ï÷Ù\8ç°¹0Úq{²ò{ ª TM…ª*¤á 7 ‹Á²0àÊš”е‰ê½¶fßú÷Ö?—–é=mÙîÖÖ6<ôÈfܼâóxªr+¾sïÿÅî·ö9•¢(&+ƒ0,¯ÅJõª]XS[w ÿîiÜ}Ͻ˜·xn^ñy<øðf„[Û2¾¯xºúoâÞ›¾Üº¼j³ycÅÚD5?vCRàÞÔ•»î\ÞkUM{{xñŽTǰxÉuðz=ðû½Î2öºŒûÂópöÜyDc1<ôÈf´&·«$ ‘è°kXÏÊFq0ÓŸÏÕºä‰rMú``ÕªUã"´©®®ÆºuëœJš¬AT$?rxãT”1Ö°¹ð¥1A§©¤*!× mZÔ–-[0cÆ ¬\¹rLOaM­ò´|ùòìíØÕ4¥è½Jj´Âš*žºôÍ…Ç6Î=òDk‚.‡Â’ÒRÀ 6†'ܰ?0œ=AGgtH'Oþ ñ½;ïÃOf_oÛi¬>²ËÔ:Òxç`ç.»ûÚ÷-Åõ×]E æaZñd,\0oH¯ãÁ‡Î üô¡GqüÄI:|,£Qp6ÃÐ0û %×´=šÔöŸkMþ2>ëR ó}¸yÙÂnw8QÝ€wŽ6 nj˜9k)Ü.^¯Á€~Ÿn· š¦A–¥‹.ã¾ì×bÛË;ðpE×jê²j­OÄYU3Ú'›ÍÍÍÙeåýýŒU%uH«ÐJ…6ëÖ­Cyy9V¯^="²þ4•••Ø´iSöT“ìf&F);§¢ à=b •ûÝDœ¦²v/—MH«hª¨¨@EE–-[†•+W¢¼¼|D¦ùõµ­6mÚ„ÊÊÊžtÀ®ZÙÇ6‹Sˆ)‰Í…Ç¿‘Û¦NÚík ÛÖ ê¤cÖd*û.\Y’쪚az’ÚºSÐï­Ëþ¥5(ÉÕ’¾}ç}Ñï/ù0VÞ)®m­¹,ïÀÞ÷ºÝwÇη°cç[_óy=¡MñÔËP\Ü5Ÿ0nÅþG2®§B þ0 3æºQ0¿¹±dqüÇ@|SÅZ³š±aUàÎÔ•…—ÏÀö7jA@GGU„[£ÈË+Ä”iK ë\.^]Qã÷%«j ½_«ƒOŒ¯|õ¢µ­ h8éÀ÷¸ú>¶¸¤½²N6÷â!Ö%ëÒ÷©ššlܸ7nÄ’%KP^^޲²²ôvUUUåü»H@Ó’üù7L°Ü²ì÷êRÀT»±dÉH¾G­¹pII ÷»‘Q »Ê¦,yœv>ûÛ¶mömÛ°jÕ*ÜvÛmÎqz¤öªª*TVV^, Iï®ëçgÂÙ¿¦OŸ~É÷/66ß¶1årÊþ\~9ZÚ¢øôÊÕ(]Z MKN †êšÊ§ÿˆ§¶ü õmسÏùe¶ia‡êÎû¤²ÎVÜUwØ*WO6N=‹Žö #—Ì·7Eáü¶ãSç ÏØÄ¦Á—ö)uÂvíû¯Ä“ý ÏüáE¼µ÷ òBPª*CQhš—K‡Çí†×ë†×ãÇí‚aèPU5YUcÏ‚ìm_¯­;…÷Ýø‰ô/­J©»€¦Qzî Ø¹ôG9y\Z‰d¥M)Á²e΀ ¤¤dÈΞ={œÁtuu5öìÙs±p&e/ºþê<Ñ*¼J¼5ŠÏ?c?+ðçQ|þ`Žî—UéaÁ[´ŠÒ ¬ Y¡M¶éÓ§£´´¥¥¥ÇêÁjnnÆž={°gÏTWW÷ vˆ^‰W:®CÚôîÔ’üÝM郤¬i4úÓŸpË-·ŒôÏÐ}ÀÊÊŒAm¿ššš¯”®®®îÖ šÛaÍ€Ov5EÂݽP áÛkÿ†¡CVä!­•òëÇ+±xá|¬þæ½8xèØ%ìÞyŸT ¬¡Æúxø®êh àüi ïu 3sÖ€¹Ý*\^¡B¾©qøòq|ê\á•ä \ûÐŒü ä·¿þ)n¸îj‚€p¸>²“ àñºaè: C‡ËeÀívÁí2àrÐ4 ª"C’$‚Øg(¹êK÷`ë UÍ…ÚH¦q3ŒÉAâ OŸ–ìFÄånëï7-[Ö5vݦIdÿ•´‡^ý h6%ùX³À#£ôÜãeP³ÀGé¹k`Ÿ9yþ?ŠÏ};º–w¦®p½iS‡.Æï÷g—³CœT(“>кHÅLO¶$·Ñ`CôÊüÎFÛÖkŽzì·´´Œø2ò=­ÅÁ>·ßD5ѦA9¿­ ƒ†óÅXÇyD¢Ñä’Ý" ICz’p¸-á6ˆ¢Ô—°Dºbm¢*ùøëàÎûZJ“¿ÔK©¤¥óÃç,]Ñìñ3ïv?÷ ]&@Õ3úDg Š…6Ý]@¢À ÑÌþ3£f]êµï[Šë¯íZÊçóâž»ïÂæÇ+Ä0eò$¸]öÊ`†®AÓÔ®jšä’ôÉg¯OöÚŽÝNP‘ü-7AŸ'ÐÛF鹇ë3Ùœ E6!3¸)ÃE*n²Ã—-[¶ õçØkoP…‰YAÓ×àb4Œ—ŠÉf¾G9ulËå÷u°ªa‡5«“ç´©ãt¯K¶´´d§˜g«IŸ‡ë]=JûØ&îN}óûýðûý£ú3p ?¾· qÿŸ`¯w€»à†ÅE¸áŠI€“õmXùÕÁŒ™%Ðu², iE¨_þê OFkk;îúgù9–[Ò`•x*ueëÓ¿Ä‹.ïqÿÜü›-˜7g& óa:4Mƒ"ÛÕ4v3ᾃøÔgïr–_×\Øé@)7ÄVšüW;¼)A?ÿª{-ÉXuò_Uò:Ã"¢+K;>—`x¦®íMŸ÷¤ý«æ[»zZMhÔ« k¸ý&0VÖ˜VäÁ®7v¢xZ1LÓ„iÐ)VmÝ)´wvBUUT×J¿‰¢Ár¦¸üÕí+°háü^ïø¹¿¾ ?ùÙ/QþÉ@‘e(²œ Å~÷bzmÇn'¨€HÇðõY¢qkO/ǰԠ ý›JWgÜWódŸˆhØU¡çJËìãrY/Çøæ¬Ç¢ Ha, ø9Ðçö›è&ZXãü•¡0ddÜ0ˆ'vS+˲×ð„G{ K—,„®k8ñîIð ÑJ¤U0|óî» ô%þÍåxrËV”â#É&m€šfß}OWŸ?—Ow´rߥ^U#3xá¾BD4¶dퟅy8w¾ “Š ÉK`õØ<þ»§Q÷ÞiçzG+¾ÎÍ@DDD4±ü|¸ýhô‰èµö8ÊaY°, –}qÀ6üçÏQX` ¯Ç ·ËÀ®7ßN¿ èÕHVÕx½ÜÓªš”ý^~åuÄbq˜ V?ó¸ÿ‡8—5O€ÓUˆˆˆˆˆˆFÜ„¬¬™Vä¶­­;…_?V‰Ë.+BÀï…ÏëÇãFÍÉ÷ÒïÖÂA/ PèêóÅUw ð h:SA~Þ€V9»ÃNU¬±H§õEn"""""¢‘7!ÿ's ÔÉú6|dÙœ=X8ÜŠ§~¿-áVL™< >Ÿ>Ÿ^¯n—'jÒïΪ¿"4ÌùIDAT¨ÕH.—ìõzp×>?àÊf”LEmÝ)Ì=¦,Cíêšž#nŃ?ÿµs]”¬ ÆUyˆˆˆˆˆˆFÃD kºš gMƒjj‹ â—ؽh -X„[?vs¯rààaìØùΟo?àE~^·~¿¿^¯†¡ãð‘éßVÅ] €Óåwý¿Ü¿ß7à¥ä.˜‡Ç~û{Ì,™Öç*g?{ø×·¶ÙYˆF/Xßçf """""%¬)M¿’ÖD"&JB1˜õ{°¯ñTýq |ùEùS ©* 8S߀€ß Ã00ù²Bèº·Û¯×¿Ï ŸÏ·ËUUqðÐÑô§`e ĺԅ©S.ßùÛ'Ìïóö¹ÊYmÝ©ŒªIµÖÅ㬪!"""""-.¬).ôdÜp²¾ >—bO1UŠcª/1Vƒ–æ(v¿³“g\Ži3faê”Ë ª 4Mƒ¡kp¹\ðx\ð¸]ðxÜp4]…¢ÈرóÍô§aXCýUàÎÔ•{Vß…¡4t·¬¾W9»ÿ‡8U5Іs‘|›ˆˆˆˆˆhôL¸°¦0¤gÜpæ\'ŠBDD»ð 54ö»UøÝÀÉÓûðVc=nYñq¸ †¡Ãå2àv0 .C‡®kPŠ"ãCÇÒŸ‚Í…i 6¥.\÷þ+qÇg>9´G³pÑUÎjëNá7O<ã\EðMn"""""¢Ñ5Q–îvš¢´)PÕgZáÒeÈ’I!: \3+¦y0ÍÛŠç*ƒP(€‚üòóBø}p»]NX#Š"¼s$ýÛYUCýU†´ÞJß\ó•Kþ„ÿºþßËŠ†sH ‹ˆˆˆˆˆˆhtL”°¦[sᆦNœ9× —.A–DH¢`‡5½<€¦J˜•—Àý n·Û™þ¤ëTM…$ËE‚ à`fXSÅÝŒúi]êÂuï¿×_{Õ0ÜÖÖëm¯íØ­/tíž±>ÍM@DDDDD4ú&BXS’~¥0h MàØ{a½*Y„,‹$¢@è±+;°Úkñ§­ÏB–dȲ Y– ‰©ª{Yä×¶ïNÿ6VÖP¬DZ¨xÏê/ùÃáV(rï3ïÿá]û¶ {Á`‘ˆˆˆˆˆhL˜aMFsᆦNì>r M‘ *TÙ®¬I5¾˜Â ÛžG}ئ™üªý=©F°œE@ZUÍg>uë°TÕ¼¶c7æÎ™Ùãmzñ/ØþzW¨éÀjn"""""¢±a"4vÂQðîéV<*tU†¦JÐÉîY#¦*cú~À˧{ñè¦GðßþgȲAçµU55`saêÛjÓ+_û¢³zÓPV‚:|ø0~Qñ0–^y5 òó È2šššÑÐP_ýöÎý4ª"¬ª!"""""+&BXS–ºàÖex] tU†¡IÐU ª"BN5FÿÆÍõïâB$êôª±D ‚8x8ýn¬ª¡¾”]U-ÿå¿ÅäËŠ`Yý {S[w 'îÃt û_Í­hªÝL»þ|'::£Î}#XÅÍ@DDDDD4vL¨iPù-#¨±«jDˆ©)PO iØü裈Çb0M €˲°ÿÃMü *2>÷™OÂ4M§²f°ž|ò÷ˆµÕCÌ™êÇ5—À²,"ðîéVç~š'Àê/"""""¢1%×Ú’Ô@&…\™AœZjàU š*á왓ˆÅãH$ÎàúÀA®EýVŽ´¦Â×.™ÝБ0MX–‰Áæ5¯í؇޲÷mÑnœ­©®[Tˆ÷:Љd±H'¾ÉÍ@DDDDD4¶äzXãTÕ º C³{Õd5ƒ›oÒnB4CÂ4aZ,‹Í…©ß°«jØÍ¯çNÏG<G"ž ÿ¬WØÔÖ“¿ÙŒxû9{¥3)¹$½ 5QVU#JøXUCDDDDD4æL˜°¦ ¨Ã¥ÉЊ4ô ¬X›ÖÄã°L ÛwìJ¿¹@3w1êE%’U_š"aÅõÅ0- ‹#a&`šÖ€+kÂáVüøÇ¢µáTE´Ã15ÍØ}¸‘X ɈF/àûÜ DDDDDDcO®7.K]˜rAUR!ÍÀ{Ôô&‹!žHÀ4Mì?Ȫê— H›þtÓÕ“áw«¨mŽ"O5ve úÙôúÀÁÃxðg¡½ñ˜]=–\’^–ì©PÑh»uî/Éøa"Î0‘ˆˆˆˆˆh,Êõ°Æ©¬™”ç‚,‰öòÜž âñ »!,W‚¢~X àîÔ•E3CX43æÁÄÔ§Ÿ?ò+¼¹óDÃg «²Ý“I• È]U5/½yÚ©ªQu4E/àÛÜDDDDDDcS.‡5%Hk.\Ô‡=¨ÓLÀJ®Þ“Õ¯¦Š»eY à‘ԕ ›®šìܸÿÐq\¶}nûÄGú| p¸[žþ#öí} çO‡`F2—¤—í%é%Q@¸=†ý'Î;ß½€opS]¹Ö8U5E!œUÒ/q(°,8•ß9š~3+k(ݤUÔ |îæYÐT p´¶AÍÂë/Ubï®×1{î\øüAÌ7Çé«·¢é\#Nœxuµ5h;[ Y¡Ê"4Í®¨I_é,µ$ýŸwŸr~EùX¤«±1="¬ÑT Ó‚ „áKlÚ/$püD5òó‚x}ç[é7±¹0¥”Áj–¤¾ÔÀ…hAŸ·.ÃК;óÎÔšøós›ÑÚ‡"ÛÁ‹( D²$@KVШŠäL}Re1c¥³Ú†6­kqž'Á§¹IˆˆˆˆˆˆÆ¶\kÊR ü::"1x ¢e5Ã1ª5ÜŠ'6?‚W^~ ç[ÓobUÍÄP`5ÒBÀ^¢ûSËJ2‚š–ö(¢qR2ˆ“û¦¦JX:'‘hûßmB,ž€*KP$Š"&ƒª,u­þ$Ù5©•Î^}»ÞyÍ…½‘NÏ#"""""ë&DeÍâY!œ:Û‰ÙS˜ÃT]s²¾ !¯†¼€W¢o?•~3Úñ-¾ÿ àþ%Éÿ—ôt§á†+&uûúw›0)䲃±k¥2!-´¹j^>ŸlA¸=¯K±W{RìªY $C)íû÷Ÿ8Ú†6çy"XÉMKDDDDD4öåjXS‚´æÂ…Ag["ˆ'L»êÀz“á3ç:Q2ì hlîL¿¹Š»Ö¸Và©áz°E3C¸áŠ"øÝj·ÛŸlGW K$©kõ¦žvÏyÓühhêDýùNøÝªSM#‰Éj±«v$šÀ‹»ºD—Ow´2D$"""""r5¬qª"Š =Q –dÁXÖà§B¬oƒ¡ËÎ;7ÑØ|!ý.çÈþ3XùÝšWìÍ õÒ@CS'ZÚ£y5(’hïO‚l(ÜóÎY4ÐÜE¸#Š¢ ’(B’RS§ºBÈWöq–ê–Ä:Zñ·Ü¬DDDDDDãC·5…!àÒeÄM ¦eÙ«7%·‰&P×ÐŽ¢á,ÜØ”Ô°¹ðøW–ºòi–¦H°, ‚˜ŒQ‘h¢(˜²$ˆ¢( àQáw«( ( ð»Õ‹î\ M8ö^!¯fWÈ("d1­²æ"ß=·Ø½ÇΣ(˜¾ w5'ëÛ°ûÐYçþ’‚{ã1î“DDDDDDãE®†5Î`»(h8_4M ¦ {¹m ®kÍ›GÎ"äÓìf®ÉUwêÛÒïRÅÝjÜs¾OÞ8](LÛ‡RV7£0¨‹†&CSD§WL¼}ì<:£q<*´äRÛªlWÖˆ¢Ð¯ýrþ4?޽Ƭ)>H¢€ô=ú¥´¥º Nu¶á{ܤDDDDDD㇘ëƒíô¶eY°` úA·ï¯‡[—Æ®Š$@’œmá¨R‚¬~G=iïˆø[Ú£øËÞÓˆ%Lx] tUv–ÜV䮪šþĈš*!‘°ì¦eðêÛgÐÐÔÕ?©³ ·r“/¹XYÓã`;MØË%"«‰DØuè,ܺ »’"Y !‹ M krH·~GÙZÚ£8×Eç»ÍxTÌšâ…K—{ÝwNÖ·!ÜÃ…X^—ÝXWeš]MUÕ$«sÐÿæ×ó¦ùq´.ŒÙS}°DMxu_×RÝþ<ÐÒÈý‘ˆˆˆˆˆh¼ÉۦÏÁö@œ¬oCÍ™6øÜ©å’“ÿd»ÇH,n"ÜžQeQÅÝ*7öŸT¿£lÇëÂP‚`¡íB »œ…*KÀH®ìÔÚEÂâ º*A;¨‘EhªÒèÉ)P²SU3°UÊ4U‚(ØÓû:#q<õrµs›Û'œki´¾ÂÍIDDDDD4þätX“>Ø>ÛrïíÀÜi~¨RŸ²ÿÄy´vÄ I¢³L²®JÐ5 š":ì³ç2–ìÞË]jÜ+K](êm Ô…8 UrzÌhŠ â1§Ïµ#èÕ J"d04 ’(@EȲM±MíªÎ’D{5§Á¬N&I"¦…moÎ noscG¹ÖtlG¢ ´uÄ È"ŸlÁ 1 —.CQ$øÝ  óB,´wÆÑCSEèš E &غ&AWìþ"’(@“ íéÏÍ)'ãß²Ô…â¢î•Y‡kZ k"4Y†$‰{f 1L ¹ €( Áj’Ër+’½ê“*‹vƒjILÞýnNœÍÐ$¼SÝŒƒÕMÎ×üxàlõnJ"""""¢ñ)·+k’aÍ»§[¡iI„(‰$L ‰Hµõ­È°—dDA€ÇP ‰Y„ªˆÎô'Méd§ú‹4²_MNî;š"ÁïV3nŒDhhî@ž_‡¦ÚAž(°`OE:/Fà6g?’¤dX“ØÈbתOÒ ¦>ekjàµ}gœëÞ<Ô´4‚ÓŸˆˆˆˆˆˆÆ±\ kJÐCsá†æN¸5Š,@E ¹&”eŠ,BW$@ÄdE„”PÛa=]%}ÊJú »¾)cÚñ­ÇUÄRÞ8Ôˆ‚€C•ìð/Ù`Ú^‰É‚ß­ÂëRº‚¿ä¾"&ÿIB×eAÀ€š ÷$M êÍÓˆÆMûì"Ñz®ë5Ñø”kaM·æÂ{Žž…ÏPaèädX €eÚ‘ÇPà2d°«!DQ°+ $;œQ$r²™°˜œú”dG¢ 6ÎÑýgZ‘;ã†íûëáw+vs`Í^rÛkLË‚À¥É€ÐU¥•šâ$¤ÿÃÔlþÓqDb çkBaùÙ:«™›‘ˆˆˆˆˆh|ËÙ°¦0¤£¡©‘˜‰<Ÿn/‘¬Ø‹eYìÿÛ:ciÕöàZJNsJMcI…8¢9ÈΪªasá\ÚÒú½yä, M†®Êi+‚‰$Ñ c,Ë‚ÛP *"8áŒs™ûÎP=¹­ iûßÔy¿ÕfŸ"""""¢\kaMYêBÈ«áh]~Ýn ¬JÐd ¢”-[ve®Jp§ª! @S‚3•¥·)+µõméW9jüsš † 44uâh]CÎXÁI‘“=hì²{¿€€OŹð 'œ0lMÊsÛkQÛеïN^¨;l}››ˆˆˆˆˆ(7äleÍ™ó˜q™šš¶Trrõt– hiKy;ÓU’cí‹õi`sáœÜwTEÄ‘ÚÄb&¼Éj]MîCŠ%Õ`:c¹mA†£µ-˜r]’0MàÅݧ°ÿÄyçk“g ÇO³>ÌÍGDDDDD”;r)¬)AZsáé“5j?Ø‘èÀ«!Nfö«asáÚ&ç»áÒe¸t†&;6Î~$ô>5®0hàhm˰ýP»5bó ÇÔM ¹Ö”¥.õäô' ²3m¥çöœbvðÒ/ œ•k–¤.LÉwÃm(piöô''¨‘.Ô uŸJ×ÒÅSÛªñÒîSS«Jo_ePCDDDDD”ÛrrÔey.'¨‘’Kn_l€=˜>#'ëÛÓ¯2¬ßÊR<.¯Úç²íãw«¨­oC$šÈh^Ý_»5âÕ·ë3öKE°ôá¿v>k~•›‹ˆˆˆˆˆ(·åJXS‚´æÂ“ó]“+?‰ÉÕ.fÎT?öŸ8E3Cý~¬ʚ*îJãšô hŠÔç²í}Y43„]‡±xf¨ßÍþçñÊÛõÙ½0u–_r‹uû³?5Ÿá¦""""""Ê}¹Ö8ƒí)î~õI§©|n M( }Þ¿¥=š]ÃÊšÙŠBdIèsÙöþ¸z~AŸM$šÀѺ–CEpõ­ÂιWã#kÍfn&"""""¢‰!皢a÷à@{Z‘Çi ÛW`Óp>£ªfw£q¯,uaz‘§ß!_\=¿ûOœ‡Ï­bZ‘ÇùúÑÚ­ ãhmKÓð_/Gg\e~á÷?2µ½’ˆˆˆˆˆˆh"É•°ÆlAWDÌ)ö÷+°asáœ0=ueÚ$ϰ?Á¢™!<·³;ŸAìp¶ùB¯}’f.”bóo°~\0ÍZÇj"""""¢‰)'+k†R‘ l.D•éØ\8§8ûŽË%ö{*\Ïû…½T$š@CS'ZÚchi‹¢¶áâ+C¹]f– Ñy×[?tð}†4DDDDDD[.„5%Hk.<Øvº9Å~ÔœnÅ_öÂ3óáw«·³²&§”¥.tt˜ØôÜ‘yRÃ%¢¨DÀ¬«­ãSçâ>Àª¬X›`HCDDDDDDrà5”x 4E–°Æ´,„;#°ä8`ŠM Š$AUDÈ¢˜])!p7×*Üv©ŸDV‚bSf (,Á‘‚bá'*+Ö&ª¹ ˆˆˆˆˆˆ(c ™¯Á™Æ‰%úœr2pfò_¬§Ù\8‡öŸ¡òx$¸Ü"LÑDA1 zLNêÝ~¡Ú_€­°«°ªXACDDDDDD“ aMÙ(>7§@%wÞ'•Ø0„ǨNþ`6§ö‹ŠµV`ñ&"""""¢É…)<¥“g ó/6ä“6ÖâßÞ|Þüi× ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆrÌÿ“× +ò30wIEND®B`‚aoflagger-v3.4.0/external/pybind11/docs/index.rst0000644000175000017500000000114514507760431020373 0ustar olesoles.. only:: latex Intro ===== .. include:: readme.rst .. only:: not latex Contents: .. toctree:: :maxdepth: 1 changelog upgrade .. toctree:: :caption: The Basics :maxdepth: 2 installing basics classes compiling .. toctree:: :caption: Advanced Topics :maxdepth: 2 advanced/functions advanced/classes advanced/exceptions advanced/smart_ptrs advanced/cast/index advanced/pycpp/index advanced/embedding advanced/misc .. toctree:: :caption: Extra Information :maxdepth: 1 faq benchmark limitations reference cmake/index aoflagger-v3.4.0/external/pybind11/noxfile.py0000644000175000017500000000531514507760431017623 0ustar olesolesimport os import nox nox.needs_version = ">=2022.1.7" nox.options.sessions = ["lint", "tests", "tests_packaging"] PYTHON_VERSIONS = [ "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy3.7", "pypy3.8", "pypy3.9", ] if os.environ.get("CI", None): nox.options.error_on_missing_interpreters = True @nox.session(reuse_venv=True) def lint(session: nox.Session) -> None: """ Lint the codebase (except for clang-format/tidy). """ session.install("pre-commit") session.run("pre-commit", "run", "-a", *session.posargs) @nox.session(python=PYTHON_VERSIONS) def tests(session: nox.Session) -> None: """ Run the tests (requires a compiler). """ tmpdir = session.create_tmp() session.install("cmake") session.install("-r", "tests/requirements.txt") session.run( "cmake", "-S.", f"-B{tmpdir}", "-DPYBIND11_WERROR=ON", "-DDOWNLOAD_CATCH=ON", "-DDOWNLOAD_EIGEN=ON", *session.posargs, ) session.run("cmake", "--build", tmpdir) session.run("cmake", "--build", tmpdir, "--config=Release", "--target", "check") @nox.session def tests_packaging(session: nox.Session) -> None: """ Run the packaging tests. """ session.install("-r", "tests/requirements.txt", "--prefer-binary") session.run("pytest", "tests/extra_python_package", *session.posargs) @nox.session(reuse_venv=True) def docs(session: nox.Session) -> None: """ Build the docs. Pass "serve" to serve. """ session.install("-r", "docs/requirements.txt") session.chdir("docs") if "pdf" in session.posargs: session.run("sphinx-build", "-M", "latexpdf", ".", "_build") return session.run("sphinx-build", "-M", "html", ".", "_build") if "serve" in session.posargs: session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit") session.run("python", "-m", "http.server", "8000", "-d", "_build/html") elif session.posargs: session.error("Unsupported argument to docs") @nox.session(reuse_venv=True) def make_changelog(session: nox.Session) -> None: """ Inspect the closed issues and make entries for a changelog. """ session.install("ghapi", "rich") session.run("python", "tools/make_changelog.py") @nox.session(reuse_venv=True) def build(session: nox.Session) -> None: """ Build SDists and wheels. """ session.install("build") session.log("Building normal files") session.run("python", "-m", "build", *session.posargs) session.log("Building pybind11-global files (PYBIND11_GLOBAL_SDIST=1)") session.run( "python", "-m", "build", *session.posargs, env={"PYBIND11_GLOBAL_SDIST": "1"} ) aoflagger-v3.4.0/external/pybind11/setup.cfg0000644000175000017500000000265414507760431017431 0ustar olesoles[metadata] long_description = file: README.rst long_description_content_type = text/x-rst description = Seamless operability between C++11 and Python author = Wenzel Jakob author_email = wenzel.jakob@epfl.ch url = https://github.com/pybind/pybind11 license = BSD classifiers = Development Status :: 5 - Production/Stable Intended Audience :: Developers Topic :: Software Development :: Libraries :: Python Modules Topic :: Utilities Programming Language :: C++ Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 License :: OSI Approved :: BSD License Programming Language :: Python :: Implementation :: PyPy Programming Language :: Python :: Implementation :: CPython Programming Language :: C++ Topic :: Software Development :: Libraries :: Python Modules keywords = C++11 Python bindings project_urls = Documentation = https://pybind11.readthedocs.io/ Bug Tracker = https://github.com/pybind/pybind11/issues Discussions = https://github.com/pybind/pybind11/discussions Changelog = https://pybind11.readthedocs.io/en/latest/changelog.html Chat = https://gitter.im/pybind/Lobby [options] python_requires = >=3.6 zip_safe = False aoflagger-v3.4.0/external/pybind11/.codespell-ignore-lines0000644000175000017500000000243414507760431022150 0ustar olesolestemplate template auto &this_ = static_cast(*this); if (load_impl(temp, false)) { ssize_t nd = 0; auto trivial = broadcast(buffers, nd, shape); auto ndim = (size_t) nd; int nd; ssize_t ndim() const { return detail::array_proxy(m_ptr)->nd; } using op = op_impl; template template class_ &def(const detail::op_ &op, const Extra &...extra) { class_ &def_cast(const detail::op_ &op, const Extra &...extra) { @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) struct IntStruct { explicit IntStruct(int v) : value(v){}; ~IntStruct() { value = -value; } IntStruct(const IntStruct &) = default; IntStruct &operator=(const IntStruct &) = default; py::class_(m, "IntStruct").def(py::init([](const int i) { return IntStruct(i); })); py::implicitly_convertible(); m.def("test", [](int expected, const IntStruct &in) { [](int expected, const IntStruct &in) { aoflagger-v3.4.0/external/pybind11/pybind11/0000755000175000017500000000000014516225226017226 5ustar olesolesaoflagger-v3.4.0/external/pybind11/pybind11/_version.py0000644000175000017500000000035114507760431021425 0ustar olesolesfrom typing import Union def _to_int(s: str) -> Union[int, str]: try: return int(s) except ValueError: return s __version__ = "2.11.0.dev1" version_info = tuple(_to_int(s) for s in __version__.split(".")) aoflagger-v3.4.0/external/pybind11/pybind11/py.typed0000644000175000017500000000000014507760431020715 0ustar olesolesaoflagger-v3.4.0/external/pybind11/pybind11/setup_helpers.py0000644000175000017500000004233714507760431022475 0ustar olesoles""" This module provides helpers for C++11+ projects using pybind11. LICENSE: Copyright (c) 2016 Wenzel Jakob , All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ # IMPORTANT: If you change this file in the pybind11 repo, also review # setup_helpers.pyi for matching changes. # # If you copy this file in, you don't # need the .pyi file; it's just an interface file for static type checkers. import contextlib import os import platform import shlex import shutil import sys import sysconfig import tempfile import threading import warnings from functools import lru_cache from pathlib import Path from typing import ( Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, TypeVar, Union, ) try: from setuptools import Extension as _Extension from setuptools.command.build_ext import build_ext as _build_ext except ImportError: from distutils.command.build_ext import build_ext as _build_ext from distutils.extension import Extension as _Extension import distutils.ccompiler import distutils.errors WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform() MACOS = sys.platform.startswith("darwin") STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}" # It is recommended to use PEP 518 builds if using this module. However, this # file explicitly supports being copied into a user's project directory # standalone, and pulling pybind11 with the deprecated setup_requires feature. # If you copy the file, remember to add it to your MANIFEST.in, and add the current # directory into your path if it sits beside your setup.py. class Pybind11Extension(_Extension): # type: ignore[misc] """ Build a C++11+ Extension module with pybind11. This automatically adds the recommended flags when you init the extension and assumes C++ sources - you can further modify the options yourself. The customizations are: * ``/EHsc`` and ``/bigobj`` on Windows * ``stdlib=libc++`` on macOS * ``visibility=hidden`` and ``-g0`` on Unix Finally, you can set ``cxx_std`` via constructor or afterwards to enable flags for C++ std, and a few extra helper flags related to the C++ standard level. It is _highly_ recommended you either set this, or use the provided ``build_ext``, which will search for the highest supported extension for you if the ``cxx_std`` property is not set. Do not set the ``cxx_std`` property more than once, as flags are added when you set it. Set the property to None to disable the addition of C++ standard flags. If you want to add pybind11 headers manually, for example for an exact git checkout, then set ``include_pybind11=False``. """ # flags are prepended, so that they can be further overridden, e.g. by # ``extra_compile_args=["-g"]``. def _add_cflags(self, flags: List[str]) -> None: self.extra_compile_args[:0] = flags def _add_ldflags(self, flags: List[str]) -> None: self.extra_link_args[:0] = flags def __init__(self, *args: Any, **kwargs: Any) -> None: self._cxx_level = 0 cxx_std = kwargs.pop("cxx_std", 0) if "language" not in kwargs: kwargs["language"] = "c++" include_pybind11 = kwargs.pop("include_pybind11", True) super().__init__(*args, **kwargs) # Include the installed package pybind11 headers if include_pybind11: # If using setup_requires, this fails the first time - that's okay try: import pybind11 pyinc = pybind11.get_include() if pyinc not in self.include_dirs: self.include_dirs.append(pyinc) except ModuleNotFoundError: pass self.cxx_std = cxx_std cflags = [] ldflags = [] if WIN: cflags += ["/EHsc", "/bigobj"] else: cflags += ["-fvisibility=hidden"] env_cflags = os.environ.get("CFLAGS", "") env_cppflags = os.environ.get("CPPFLAGS", "") c_cpp_flags = shlex.split(env_cflags) + shlex.split(env_cppflags) if not any(opt.startswith("-g") for opt in c_cpp_flags): cflags += ["-g0"] if MACOS: cflags += ["-stdlib=libc++"] ldflags += ["-stdlib=libc++"] self._add_cflags(cflags) self._add_ldflags(ldflags) @property def cxx_std(self) -> int: """ The CXX standard level. If set, will add the required flags. If left at 0, it will trigger an automatic search when pybind11's build_ext is used. If None, will have no effect. Besides just the flags, this may add a macos-min 10.9 or 10.14 flag if MACOSX_DEPLOYMENT_TARGET is unset. """ return self._cxx_level @cxx_std.setter def cxx_std(self, level: int) -> None: if self._cxx_level: warnings.warn( "You cannot safely change the cxx_level after setting it!", stacklevel=2 ) # MSVC 2015 Update 3 and later only have 14 (and later 17) modes, so # force a valid flag here. if WIN and level == 11: level = 14 self._cxx_level = level if not level: return cflags = [STD_TMPL.format(level)] ldflags = [] if MACOS and "MACOSX_DEPLOYMENT_TARGET" not in os.environ: # C++17 requires a higher min version of macOS. An earlier version # (10.12 or 10.13) can be set manually via environment variable if # you are careful in your feature usage, but 10.14 is the safest # setting for general use. However, never set higher than the # current macOS version! current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2]) desired_macos = (10, 9) if level < 17 else (10, 14) macos_string = ".".join(str(x) for x in min(current_macos, desired_macos)) macosx_min = f"-mmacosx-version-min={macos_string}" cflags += [macosx_min] ldflags += [macosx_min] self._add_cflags(cflags) self._add_ldflags(ldflags) # Just in case someone clever tries to multithread tmp_chdir_lock = threading.Lock() @contextlib.contextmanager def tmp_chdir() -> Iterator[str]: "Prepare and enter a temporary directory, cleanup when done" # Threadsafe with tmp_chdir_lock: olddir = os.getcwd() try: tmpdir = tempfile.mkdtemp() os.chdir(tmpdir) yield tmpdir finally: os.chdir(olddir) shutil.rmtree(tmpdir) # cf http://bugs.python.org/issue26689 def has_flag(compiler: Any, flag: str) -> bool: """ Return the flag if a flag name is supported on the specified compiler, otherwise None (can be used as a boolean). If multiple flags are passed, return the first that matches. """ with tmp_chdir(): fname = Path("flagcheck.cpp") # Don't trigger -Wunused-parameter. fname.write_text("int main (int, char **) { return 0; }", encoding="utf-8") try: compiler.compile([str(fname)], extra_postargs=[flag]) except distutils.errors.CompileError: return False return True # Every call will cache the result cpp_flag_cache = None @lru_cache() def auto_cpp_level(compiler: Any) -> Union[str, int]: """ Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows. """ if WIN: return "latest" levels = [17, 14, 11] for level in levels: if has_flag(compiler, STD_TMPL.format(level)): return level msg = "Unsupported compiler -- at least C++11 support is needed!" raise RuntimeError(msg) class build_ext(_build_ext): # type: ignore[misc] # noqa: N801 """ Customized build_ext that allows an auto-search for the highest supported C++ level for Pybind11Extension. This is only needed for the auto-search for now, and is completely optional otherwise. """ def build_extensions(self) -> None: """ Build extensions, injecting C++ std for Pybind11Extension if needed. """ for ext in self.extensions: if hasattr(ext, "_cxx_level") and ext._cxx_level == 0: ext.cxx_std = auto_cpp_level(self.compiler) super().build_extensions() def intree_extensions( paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None ) -> List[Pybind11Extension]: """ Generate Pybind11Extensions from source files directly located in a Python source tree. ``package_dir`` behaves as in ``setuptools.setup``. If unset, the Python package root parent is determined as the first parent directory that does not contain an ``__init__.py`` file. """ exts = [] if package_dir is None: for path in paths: parent, _ = os.path.split(path) while os.path.exists(os.path.join(parent, "__init__.py")): parent, _ = os.path.split(parent) relname, _ = os.path.splitext(os.path.relpath(path, parent)) qualified_name = relname.replace(os.path.sep, ".") exts.append(Pybind11Extension(qualified_name, [path])) return exts for path in paths: for prefix, parent in package_dir.items(): if path.startswith(parent): relname, _ = os.path.splitext(os.path.relpath(path, parent)) qualified_name = relname.replace(os.path.sep, ".") if prefix: qualified_name = prefix + "." + qualified_name exts.append(Pybind11Extension(qualified_name, [path])) break else: msg = ( f"path {path} is not a child of any of the directories listed " f"in 'package_dir' ({package_dir})" ) raise ValueError(msg) return exts def naive_recompile(obj: str, src: str) -> bool: """ This will recompile only if the source file changes. It does not check header files, so a more advanced function or Ccache is better if you have editable header files in your package. """ return os.stat(obj).st_mtime < os.stat(src).st_mtime def no_recompile(obg: str, src: str) -> bool: # noqa: ARG001 """ This is the safest but slowest choice (and is the default) - will always recompile sources. """ return True S = TypeVar("S", bound="ParallelCompile") CCompilerMethod = Callable[ [ distutils.ccompiler.CCompiler, List[str], Optional[str], Optional[Union[Tuple[str], Tuple[str, Optional[str]]]], Optional[List[str]], bool, Optional[List[str]], Optional[List[str]], Optional[List[str]], ], List[str], ] # Optional parallel compile utility # inspired by: http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils # and: https://github.com/tbenthompson/cppimport/blob/stable/cppimport/build_module.py # and NumPy's parallel distutils module: # https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py class ParallelCompile: """ Make a parallel compile function. Inspired by numpy.distutils.ccompiler.CCompiler.compile and cppimport. This takes several arguments that allow you to customize the compile function created: envvar: Set an environment variable to control the compilation threads, like NPY_NUM_BUILD_JOBS default: 0 will automatically multithread, or 1 will only multithread if the envvar is set. max: The limit for automatic multithreading if non-zero needs_recompile: A function of (obj, src) that returns True when recompile is needed. No effect in isolated mode; use ccache instead, see https://github.com/matplotlib/matplotlib/issues/1507/ To use:: ParallelCompile("NPY_NUM_BUILD_JOBS").install() or:: with ParallelCompile("NPY_NUM_BUILD_JOBS"): setup(...) By default, this assumes all files need to be recompiled. A smarter function can be provided via needs_recompile. If the output has not yet been generated, the compile will always run, and this function is not called. """ __slots__ = ("envvar", "default", "max", "_old", "needs_recompile") def __init__( self, envvar: Optional[str] = None, default: int = 0, max: int = 0, # pylint: disable=redefined-builtin needs_recompile: Callable[[str, str], bool] = no_recompile, ) -> None: self.envvar = envvar self.default = default self.max = max self.needs_recompile = needs_recompile self._old: List[CCompilerMethod] = [] def function(self) -> CCompilerMethod: """ Builds a function object usable as distutils.ccompiler.CCompiler.compile. """ def compile_function( compiler: distutils.ccompiler.CCompiler, sources: List[str], output_dir: Optional[str] = None, macros: Optional[Union[Tuple[str], Tuple[str, Optional[str]]]] = None, include_dirs: Optional[List[str]] = None, debug: bool = False, extra_preargs: Optional[List[str]] = None, extra_postargs: Optional[List[str]] = None, depends: Optional[List[str]] = None, ) -> Any: # These lines are directly from distutils.ccompiler.CCompiler macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined] output_dir, macros, include_dirs, sources, depends, extra_postargs ) cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs) # type: ignore[attr-defined] # The number of threads; start with default. threads = self.default # Determine the number of compilation threads, unless set by an environment variable. if self.envvar is not None: threads = int(os.environ.get(self.envvar, self.default)) def _single_compile(obj: Any) -> None: try: src, ext = build[obj] except KeyError: return if not os.path.exists(obj) or self.needs_recompile(obj, src): compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) # type: ignore[attr-defined] try: # Importing .synchronize checks for platforms that have some multiprocessing # capabilities but lack semaphores, such as AWS Lambda and Android Termux. import multiprocessing.synchronize from multiprocessing.pool import ThreadPool except ImportError: threads = 1 if threads == 0: try: threads = multiprocessing.cpu_count() threads = self.max if self.max and self.max < threads else threads except NotImplementedError: threads = 1 if threads > 1: with ThreadPool(threads) as pool: for _ in pool.imap_unordered(_single_compile, objects): pass else: for ob in objects: _single_compile(ob) return objects return compile_function def install(self: S) -> S: """ Installs the compile function into distutils.ccompiler.CCompiler.compile. """ distutils.ccompiler.CCompiler.compile = self.function() # type: ignore[assignment] return self def __enter__(self: S) -> S: self._old.append(distutils.ccompiler.CCompiler.compile) return self.install() def __exit__(self, *args: Any) -> None: distutils.ccompiler.CCompiler.compile = self._old.pop() # type: ignore[assignment] aoflagger-v3.4.0/external/pybind11/pybind11/__init__.py0000644000175000017500000000065514507760431021347 0ustar olesolesimport sys if sys.version_info < (3, 6): # noqa: UP036 msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5." raise ImportError(msg) from ._version import __version__, version_info from .commands import get_cmake_dir, get_include, get_pkgconfig_dir __all__ = ( "version_info", "__version__", "get_include", "get_cmake_dir", "get_pkgconfig_dir", ) aoflagger-v3.4.0/external/pybind11/pybind11/__main__.py0000644000175000017500000000301014507760431021314 0ustar olesoles# pylint: disable=missing-function-docstring import argparse import sys import sysconfig from ._version import __version__ from .commands import get_cmake_dir, get_include, get_pkgconfig_dir def print_includes() -> None: dirs = [ sysconfig.get_path("include"), sysconfig.get_path("platinclude"), get_include(), ] # Make unique but preserve order unique_dirs = [] for d in dirs: if d and d not in unique_dirs: unique_dirs.append(d) print(" ".join("-I" + d for d in unique_dirs)) def main() -> None: parser = argparse.ArgumentParser() parser.add_argument( "--version", action="version", version=__version__, help="Print the version and exit.", ) parser.add_argument( "--includes", action="store_true", help="Include flags for both pybind11 and Python headers.", ) parser.add_argument( "--cmakedir", action="store_true", help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.", ) parser.add_argument( "--pkgconfigdir", action="store_true", help="Print the pkgconfig directory, ideal for setting $PKG_CONFIG_PATH.", ) args = parser.parse_args() if not sys.argv[1:]: parser.print_help() if args.includes: print_includes() if args.cmakedir: print(get_cmake_dir()) if args.pkgconfigdir: print(get_pkgconfig_dir()) if __name__ == "__main__": main() aoflagger-v3.4.0/external/pybind11/pybind11/commands.py0000644000175000017500000000226714507760431021412 0ustar olesolesimport os DIR = os.path.abspath(os.path.dirname(__file__)) def get_include(user: bool = False) -> str: # noqa: ARG001 """ Return the path to the pybind11 include directory. The historical "user" argument is unused, and may be removed. """ installed_path = os.path.join(DIR, "include") source_path = os.path.join(os.path.dirname(DIR), "include") return installed_path if os.path.exists(installed_path) else source_path def get_cmake_dir() -> str: """ Return the path to the pybind11 CMake module directory. """ cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11") if os.path.exists(cmake_installed_path): return cmake_installed_path msg = "pybind11 not installed, installation required to access the CMake files" raise ImportError(msg) def get_pkgconfig_dir() -> str: """ Return the path to the pybind11 pkgconfig directory. """ pkgconfig_installed_path = os.path.join(DIR, "share", "pkgconfig") if os.path.exists(pkgconfig_installed_path): return pkgconfig_installed_path msg = "pybind11 not installed, installation required to access the pkgconfig files" raise ImportError(msg) aoflagger-v3.4.0/external/pybind11/LICENSE0000644000175000017500000000322414507760431016607 0ustar olesolesCopyright (c) 2016 Wenzel Jakob , All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of external contributions to this project including patches, pull requests, etc. aoflagger-v3.4.0/external/pybind11/.readthedocs.yml0000644000175000017500000000007614507760431020672 0ustar olesolespython: version: 3 requirements_file: docs/requirements.txt aoflagger-v3.4.0/external/pybind11/.clang-tidy0000644000175000017500000000505514507760431017642 0ustar olesolesFormatStyle: file Checks: | *bugprone*, *performance*, clang-analyzer-optin.cplusplus.VirtualCall, clang-analyzer-optin.performance.Padding, cppcoreguidelines-init-variables, cppcoreguidelines-prefer-member-initializer, cppcoreguidelines-pro-type-static-cast-downcast, cppcoreguidelines-slicing, google-explicit-constructor, llvm-namespace-comment, misc-definitions-in-headers, misc-misplaced-const, misc-non-copyable-objects, misc-static-assert, misc-throw-by-value-catch-by-reference, misc-uniqueptr-reset-release, misc-unused-parameters, modernize-avoid-bind, modernize-loop-convert, modernize-make-shared, modernize-redundant-void-arg, modernize-replace-auto-ptr, modernize-replace-disallow-copy-and-assign-macro, modernize-replace-random-shuffle, modernize-shrink-to-fit, modernize-use-auto, modernize-use-bool-literals, modernize-use-default-member-init, modernize-use-emplace, modernize-use-equals-default, modernize-use-equals-delete, modernize-use-noexcept, modernize-use-nullptr, modernize-use-override, modernize-use-using, readability-avoid-const-params-in-decls, readability-braces-around-statements, readability-const-return-type, readability-container-size-empty, readability-delete-null-pointer, readability-else-after-return, readability-implicit-bool-conversion, readability-inconsistent-declaration-parameter-name, readability-make-member-function-const, readability-misplaced-array-index, readability-non-const-parameter, readability-qualified-auto, readability-redundant-function-ptr-dereference, readability-redundant-smartptr-get, readability-redundant-string-cstr, readability-simplify-subscript-expr, readability-static-accessed-through-instance, readability-static-definition-in-anonymous-namespace, readability-string-compare, readability-suspicious-call-argument, readability-uniqueptr-delete-release, -bugprone-easily-swappable-parameters, -bugprone-exception-escape, -bugprone-reserved-identifier, -bugprone-unused-raii, CheckOptions: - key: modernize-use-equals-default.IgnoreMacros value: false - key: performance-for-range-copy.WarnOnAllAutoCopies value: true - key: performance-inefficient-string-concatenation.StrictMode value: true - key: performance-unnecessary-value-param.AllowedTypes value: 'exception_ptr$;' - key: readability-implicit-bool-conversion.AllowPointerConditions value: true HeaderFilterRegex: 'pybind11/.*h' aoflagger-v3.4.0/external/pybind11/tools/0000755000175000017500000000000014516225226016737 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tools/setup_main.py.in0000644000175000017500000000232214507760431022063 0ustar olesoles#!/usr/bin/env python3 # Setup script (in the sdist or in tools/setup_main.py in the repository) from setuptools import setup cmdclass = {} $extra_cmd setup( name="pybind11", version="$version", download_url='https://github.com/pybind/pybind11/tarball/v$version', packages=[ "pybind11", "pybind11.include.pybind11", "pybind11.include.pybind11.detail", "pybind11.include.pybind11.eigen", "pybind11.include.pybind11.stl", "pybind11.share.cmake.pybind11", "pybind11.share.pkgconfig", ], package_data={ "pybind11": ["py.typed"], "pybind11.include.pybind11": ["*.h"], "pybind11.include.pybind11.detail": ["*.h"], "pybind11.include.pybind11.eigen": ["*.h"], "pybind11.include.pybind11.stl": ["*.h"], "pybind11.share.cmake.pybind11": ["*.cmake"], "pybind11.share.pkgconfig": ["*.pc"], }, extras_require={ "global": ["pybind11_global==$version"] }, entry_points={ "console_scripts": [ "pybind11-config = pybind11.__main__:main", ], "pipx.run": [ "pybind11 = pybind11.__main__:main", ] }, cmdclass=cmdclass ) aoflagger-v3.4.0/external/pybind11/tools/cmake_uninstall.cmake.in0000644000175000017500000000167014507760431023525 0ustar olesoles# Source: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") endif() file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif() else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif() endforeach() aoflagger-v3.4.0/external/pybind11/tools/FindEigen3.cmake0000644000175000017500000000604114507760431021657 0ustar olesoles# - Try to find Eigen3 lib # # This module supports requiring a minimum version, e.g. you can do # find_package(Eigen3 3.1.2) # to require version 3.1.2 or newer of Eigen3. # # Once done this will define # # EIGEN3_FOUND - system has eigen lib with correct version # EIGEN3_INCLUDE_DIR - the eigen include directory # EIGEN3_VERSION - eigen version # Copyright (c) 2006, 2007 Montel Laurent, # Copyright (c) 2008, 2009 Gael Guennebaud, # Copyright (c) 2009 Benoit Jacob # Redistribution and use is allowed according to the terms of the 2-clause BSD license. if(NOT Eigen3_FIND_VERSION) if(NOT Eigen3_FIND_VERSION_MAJOR) set(Eigen3_FIND_VERSION_MAJOR 2) endif(NOT Eigen3_FIND_VERSION_MAJOR) if(NOT Eigen3_FIND_VERSION_MINOR) set(Eigen3_FIND_VERSION_MINOR 91) endif(NOT Eigen3_FIND_VERSION_MINOR) if(NOT Eigen3_FIND_VERSION_PATCH) set(Eigen3_FIND_VERSION_PATCH 0) endif(NOT Eigen3_FIND_VERSION_PATCH) set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") endif(NOT Eigen3_FIND_VERSION) macro(_eigen3_check_version) file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) set(EIGEN3_VERSION_OK FALSE) else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) set(EIGEN3_VERSION_OK TRUE) endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) if(NOT EIGEN3_VERSION_OK) message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " "but at least version ${Eigen3_FIND_VERSION} is required") endif(NOT EIGEN3_VERSION_OK) endmacro(_eigen3_check_version) if(EIGEN3_INCLUDE_DIR) # in cache already _eigen3_check_version() set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) else(EIGEN3_INCLUDE_DIR) if(NOT DEFINED KDE4_INCLUDE_DIR) set(KDE4_INCLUDE_DIR "") endif() find_path( EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library PATHS ${CMAKE_INSTALL_PREFIX}/include ${KDE4_INCLUDE_DIR} PATH_SUFFIXES eigen3 eigen) if(EIGEN3_INCLUDE_DIR) _eigen3_check_version() endif(EIGEN3_INCLUDE_DIR) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) mark_as_advanced(EIGEN3_INCLUDE_DIR) endif(EIGEN3_INCLUDE_DIR) aoflagger-v3.4.0/external/pybind11/tools/check-style.sh0000755000175000017500000000261714507760431021521 0ustar olesoles#!/bin/bash # # Script to check include/test code for common pybind11 code style errors. # # This script currently checks for # # 1. missing space between keyword and parenthesis, e.g.: for(, if(, while( # 2. Missing space between right parenthesis and brace, e.g. 'for (...){' # 3. opening brace on its own line. It should always be on the same line as the # if/while/for/do statement. # # Invoke as: tools/check-style.sh # check_style_errors=0 IFS=$'\n' found="$(grep '\<\(if\|for\|while\|catch\)(\|){' "$@" -rn --color=always)" if [ -n "$found" ]; then echo -e '\033[31;01mError: found the following coding style problems:\033[0m' check_style_errors=1 echo "${found//^/ /}" fi found="$(awk ' function prefix(filename, lineno) { return " \033[35m" filename "\033[36m:\033[32m" lineno "\033[36m:\033[0m" } function mark(pattern, string) { sub(pattern, "\033[01;31m&\033[0m", string); return string } last && /^\s*{/ { print prefix(FILENAME, FNR-1) mark("\\)\\s*$", last) print prefix(FILENAME, FNR) mark("^\\s*{", $0) last="" } { last = /(if|for|while|catch|switch)\s*\(.*\)\s*$/ ? $0 : "" } ' "$(find include -type f)" "$@")" if [ -n "$found" ]; then check_style_errors=1 echo -e '\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\033[0m' echo "$found" fi exit $check_style_errors aoflagger-v3.4.0/external/pybind11/tools/setup_global.py.in0000644000175000017500000000407014507760431022401 0ustar olesoles#!/usr/bin/env python3 # Setup script for pybind11-global (in the sdist or in tools/setup_global.py in the repository) # This package is targeted for easy use from CMake. import glob import os import re # Setuptools has to be before distutils from setuptools import setup from distutils.command.install_headers import install_headers class InstallHeadersNested(install_headers): def run(self): headers = self.distribution.headers or [] for header in headers: # Remove pybind11/include/ short_header = header.split("/", 2)[-1] dst = os.path.join(self.install_dir, os.path.dirname(short_header)) self.mkpath(dst) (out, _) = self.copy_file(header, dst) self.outfiles.append(out) main_headers = glob.glob("pybind11/include/pybind11/*.h") detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h") eigen_headers = glob.glob("pybind11/include/pybind11/eigen/*.h") stl_headers = glob.glob("pybind11/include/pybind11/stl/*.h") cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake") pkgconfig_files = glob.glob("pybind11/share/pkgconfig/*.pc") headers = main_headers + detail_headers + stl_headers + eigen_headers cmdclass = {"install_headers": InstallHeadersNested} $extra_cmd # This will _not_ affect installing from wheels, # only building wheels or installing from SDist. # Primarily intended on Windows, where this is sometimes # customized (for example, conda-forge uses Library/) base = os.environ.get("PYBIND11_GLOBAL_PREFIX", "") # Must have a separator if base and not base.endswith("/"): base += "/" setup( name="pybind11_global", version="$version", packages=[], headers=headers, data_files=[ (base + "share/cmake/pybind11", cmake_files), (base + "share/pkgconfig", pkgconfig_files), (base + "include/pybind11", main_headers), (base + "include/pybind11/detail", detail_headers), (base + "include/pybind11/eigen", eigen_headers), (base + "include/pybind11/stl", stl_headers), ], cmdclass=cmdclass, ) aoflagger-v3.4.0/external/pybind11/tools/JoinPaths.cmake0000644000175000017500000000146114507760431021644 0ustar olesoles# This module provides function for joining paths # known from most languages # # SPDX-License-Identifier: (MIT OR CC0-1.0) # Copyright 2020 Jan Tojnar # https://github.com/jtojnar/cmake-snips # # Modelled after Python’s os.path.join # https://docs.python.org/3.7/library/os.path.html#os.path.join # Windows not supported function(join_paths joined_path first_path_segment) set(temp_path "${first_path_segment}") foreach(current_segment IN LISTS ARGN) if(NOT ("${current_segment}" STREQUAL "")) if(IS_ABSOLUTE "${current_segment}") set(temp_path "${current_segment}") else() set(temp_path "${temp_path}/${current_segment}") endif() endif() endforeach() set(${joined_path} "${temp_path}" PARENT_SCOPE) endfunction() aoflagger-v3.4.0/external/pybind11/tools/pybind11.pc.in0000644000175000017500000000030414507760431021316 0ustar olesolesprefix=@prefix_for_pc_file@ includedir=@includedir_for_pc_file@ Name: @PROJECT_NAME@ Description: Seamless operability between C++11 and Python Version: @PROJECT_VERSION@ Cflags: -I${includedir} aoflagger-v3.4.0/external/pybind11/tools/pybind11Tools.cmake0000644000175000017500000002025114507760431022413 0ustar olesoles# tools/pybind11Tools.cmake -- Build system for the pybind11 modules # # Copyright (c) 2020 Wenzel Jakob # # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. # include_guard(global) (pre-CMake 3.10) if(TARGET pybind11::python_headers) return() endif() # Built-in in CMake 3.5+ include(CMakeParseArguments) if(pybind11_FIND_QUIETLY) set(_pybind11_quiet QUIET) else() set(_pybind11_quiet "") endif() # If this is the first run, PYTHON_VERSION can stand in for PYBIND11_PYTHON_VERSION if(NOT DEFINED PYBIND11_PYTHON_VERSION AND DEFINED PYTHON_VERSION) message(WARNING "Set PYBIND11_PYTHON_VERSION to search for a specific version, not " "PYTHON_VERSION (which is an output). Assuming that is what you " "meant to do and continuing anyway.") set(PYBIND11_PYTHON_VERSION "${PYTHON_VERSION}" CACHE STRING "Python version to use for compiling modules") unset(PYTHON_VERSION) unset(PYTHON_VERSION CACHE) elseif(DEFINED PYBIND11_PYTHON_VERSION) # If this is set as a normal variable, promote it set(PYBIND11_PYTHON_VERSION "${PYBIND11_PYTHON_VERSION}" CACHE STRING "Python version to use for compiling modules") else() # Make an empty cache variable. set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") endif() # A user can set versions manually too set(Python_ADDITIONAL_VERSIONS "3.11;3.10;3.9;3.8;3.7;3.6" CACHE INTERNAL "") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED ${_pybind11_quiet}) list(REMOVE_AT CMAKE_MODULE_PATH -1) # Makes a normal variable a cached variable macro(_PYBIND11_PROMOTE_TO_CACHE NAME) set(_tmp_ptc "${${NAME}}") # CMake 3.21 complains if a cached variable is shadowed by a normal one unset(${NAME}) set(${NAME} "${_tmp_ptc}" CACHE INTERNAL "") endmacro() # Cache variables so pybind11_add_module can be used in parent projects _pybind11_promote_to_cache(PYTHON_INCLUDE_DIRS) _pybind11_promote_to_cache(PYTHON_LIBRARIES) _pybind11_promote_to_cache(PYTHON_MODULE_PREFIX) _pybind11_promote_to_cache(PYTHON_MODULE_EXTENSION) _pybind11_promote_to_cache(PYTHON_VERSION_MAJOR) _pybind11_promote_to_cache(PYTHON_VERSION_MINOR) _pybind11_promote_to_cache(PYTHON_VERSION) _pybind11_promote_to_cache(PYTHON_IS_DEBUG) if(PYBIND11_MASTER_PROJECT) if(PYTHON_MODULE_EXTENSION MATCHES "pypy") if(NOT DEFINED PYPY_VERSION) execute_process( COMMAND ${PYTHON_EXECUTABLE} -c [=[import sys; sys.stdout.write(".".join(map(str, sys.pypy_version_info[:3])))]=] OUTPUT_VARIABLE pypy_version) set(PYPY_VERSION ${pypy_version} CACHE INTERNAL "") endif() message(STATUS "PYPY ${PYPY_VERSION} (Py ${PYTHON_VERSION})") else() message(STATUS "PYTHON ${PYTHON_VERSION}") endif() endif() # Only add Python for build - must be added during the import for config since # it has to be re-discovered. # # This needs to be an target to it is included after the local pybind11 # directory, just in case there are multiple versions of pybind11, we want the # one we expect. add_library(pybind11::python_headers INTERFACE IMPORTED) set_property(TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$") set_property( TARGET pybind11::pybind11 APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers) set(pybind11_INCLUDE_DIRS "${pybind11_INCLUDE_DIR}" "${PYTHON_INCLUDE_DIRS}" CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located") # Python debug libraries expose slightly different objects before 3.8 # https://docs.python.org/3.6/c-api/intro.html#debugging-builds # https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib if(PYTHON_IS_DEBUG) set_property( TARGET pybind11::pybind11 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG) endif() # The <3.11 code here does not support release/debug builds at the same time, like on vcpkg if(CMAKE_VERSION VERSION_LESS 3.11) set_property( TARGET pybind11::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_link_helper "$<$,$>:$>" ) set_property( TARGET pybind11::embed APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $) else() # The IMPORTED INTERFACE library here is to ensure that "debug" and "release" get processed outside # of a generator expression - https://gitlab.kitware.com/cmake/cmake/-/issues/18424, as they are # target_link_library keywords rather than real libraries. add_library(pybind11::_ClassicPythonLibraries IMPORTED INTERFACE) target_link_libraries(pybind11::_ClassicPythonLibraries INTERFACE ${PYTHON_LIBRARIES}) target_link_libraries( pybind11::module INTERFACE pybind11::python_link_helper "$<$,$>:pybind11::_ClassicPythonLibraries>") target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11 pybind11::_ClassicPythonLibraries) endif() function(pybind11_extension name) # The prefix and extension are provided by FindPythonLibsNew.cmake set_target_properties(${name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" SUFFIX "${PYTHON_MODULE_EXTENSION}") endfunction() # Build a Python extension module: # pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] # [NO_EXTRAS] [THIN_LTO] [OPT_SIZE] source1 [source2 ...]) # function(pybind11_add_module target_name) set(options "MODULE;SHARED;EXCLUDE_FROM_ALL;NO_EXTRAS;SYSTEM;THIN_LTO;OPT_SIZE") cmake_parse_arguments(ARG "${options}" "" "" ${ARGN}) if(ARG_MODULE AND ARG_SHARED) message(FATAL_ERROR "Can't be both MODULE and SHARED") elseif(ARG_SHARED) set(lib_type SHARED) else() set(lib_type MODULE) endif() if(ARG_EXCLUDE_FROM_ALL) set(exclude_from_all EXCLUDE_FROM_ALL) else() set(exclude_from_all "") endif() add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) target_link_libraries(${target_name} PRIVATE pybind11::module) if(ARG_SYSTEM) message( STATUS "Warning: this does not have an effect - use NO_SYSTEM_FROM_IMPORTED if using imported targets" ) endif() pybind11_extension(${target_name}) # -fvisibility=hidden is required to allow multiple modules compiled against # different pybind versions to work properly, and for some features (e.g. # py::module_local). We force it on everything inside the `pybind11` # namespace; also turning it on for a pybind module compilation here avoids # potential warnings or issues from having mixed hidden/non-hidden types. if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET) set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden") endif() if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET) set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden") endif() if(ARG_NO_EXTRAS) return() endif() if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION) if(ARG_THIN_LTO) target_link_libraries(${target_name} PRIVATE pybind11::thin_lto) else() target_link_libraries(${target_name} PRIVATE pybind11::lto) endif() endif() # Use case-insensitive comparison to match the result of $ string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) if(NOT MSVC AND NOT "${uppercase_CMAKE_BUILD_TYPE}" MATCHES DEBUG|RELWITHDEBINFO) pybind11_strip(${target_name}) endif() if(MSVC) target_link_libraries(${target_name} PRIVATE pybind11::windows_extras) endif() if(ARG_OPT_SIZE) target_link_libraries(${target_name} PRIVATE pybind11::opt_size) endif() endfunction() # Provide general way to call common Python commands in "common" file. set(_Python PYTHON CACHE INTERNAL "" FORCE) aoflagger-v3.4.0/external/pybind11/tools/pybind11Config.cmake.in0000644000175000017500000001542214507760431023131 0ustar olesoles#[=============================================================================[.rst: pybind11Config.cmake #################### Exported variables ================== This module sets the following variables in your project: ``pybind11_FOUND`` true if pybind11 and all required components found on the system ``pybind11_VERSION`` pybind11 version in format Major.Minor.Release ``pybind11_VERSION_TYPE`` pybind11 version type (``dev*`` or empty for a release) ``pybind11_INCLUDE_DIRS`` Directories where pybind11 and python headers are located. ``pybind11_INCLUDE_DIR`` Directory where pybind11 headers are located. ``pybind11_DEFINITIONS`` Definitions necessary to use pybind11, namely USING_pybind11. ``pybind11_LIBRARIES`` Compile flags and python libraries (as needed) to link against. ``pybind11_LIBRARY`` Empty. Available components: None Exported targets ================ If pybind11 is found, this module defines the following ``IMPORTED`` interface library targets: ``pybind11::module`` for extension modules. ``pybind11::embed`` for embedding the Python interpreter. Python headers, libraries (as needed by platform), and the C++ standard are attached to the target. Advanced targets are also supplied - these are primary for users building complex applications, and they are available in all modes: ``pybind11::headers`` Just the pybind11 headers and minimum compile requirements. ``pybind11::pybind11`` Python headers too. ``pybind11::python_link_helper`` Just the "linking" part of ``pybind11:module``, for CMake < 3.15. ``pybind11::thin_lto`` An alternative to ``INTERPROCEDURAL_OPTIMIZATION``. ``pybind11::lto`` An alternative to ``INTERPROCEDURAL_OPTIMIZATION`` (also avoids thin LTO on clang). ``pybind11::windows_extras`` Adds bigobj and mp for MSVC. Modes ===== There are two modes provided; classic, which is built on the old Python discovery packages in CMake, or the new FindPython mode, which uses FindPython from 3.12+ forward (3.15+ _highly_ recommended). New FindPython mode ^^^^^^^^^^^^^^^^^^^ To activate this mode, either call ``find_package(Python COMPONENTS Interpreter Development)`` before finding this package, or set the ``PYBIND11_FINDPYTHON`` variable to ON. In this mode, you can either use the basic targets, or use the FindPython tools: .. code-block:: cmake find_package(Python COMPONENTS Interpreter Development) find_package(pybind11 CONFIG) # pybind11 method: pybind11_add_module(MyModule1 src1.cpp) # Python method: Python_add_library(MyModule2 src2.cpp) target_link_libraries(MyModule2 pybind11::headers) set_target_properties(MyModule2 PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON CXX_VISIBILITY_PRESET ON VISIBILITY_INLINES_HIDDEN ON) If you build targets yourself, you may be interested in stripping the output for reduced size; this is the one other feature that the helper function gives you. Classic mode ^^^^^^^^^^^^ Set PythonLibsNew variables to influence python detection and CMAKE_CXX_STANDARD to influence standard setting. .. code-block:: cmake find_package(pybind11 CONFIG REQUIRED) # Create an extension module add_library(mylib MODULE main.cpp) target_link_libraries(mylib PUBLIC pybind11::module) # Or embed the Python interpreter into an executable add_executable(myexe main.cpp) target_link_libraries(myexe PUBLIC pybind11::embed) Hints ===== The following variables can be set to guide the search for this package: ``pybind11_DIR`` CMake variable, set to directory containing this Config file. ``CMAKE_PREFIX_PATH`` CMake variable, set to root directory of this package. ``PATH`` Environment variable, set to bin directory of this package. ``CMAKE_DISABLE_FIND_PACKAGE_pybind11`` CMake variable, disables ``find_package(pybind11)`` when not ``REQUIRED``, perhaps to force internal build. Commands ======== pybind11_add_module ^^^^^^^^^^^^^^^^^^^ This module defines the following commands to assist with creating Python modules: .. code-block:: cmake pybind11_add_module( [STATIC|SHARED|MODULE] [THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOABI] ... ) Add a module and setup all helpers. You can select the type of the library; the default is ``MODULE``. There are several options: ``OPT_SIZE`` Optimize for size, even if the ``CMAKE_BUILD_TYPE`` is not ``MinSizeRel``. ``THIN_LTO`` Use thin TLO instead of regular if there's a choice (pybind11's selection is disabled if ``CMAKE_INTERPROCEDURAL_OPTIMIZATIONS`` is set). ``WITHOUT_SOABI`` Disable the SOABI component (``PYBIND11_NEWPYTHON`` mode only). ``NO_EXTRAS`` Disable all extras, exit immediately after making the module. pybind11_strip ^^^^^^^^^^^^^^ .. code-block:: cmake pybind11_strip() Strip a target after building it (linux/macOS), called by ``pybind11_add_module``. pybind11_extension ^^^^^^^^^^^^^^^^^^ .. code-block:: cmake pybind11_extension() Sets the Python extension name correctly for Python on your platform, called by ``pybind11_add_module``. pybind11_find_import(module) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: cmake pybind11_find_import( [VERSION ] [REQUIRED] [QUIET]) See if a module is installed. Use the registered name (the one on PyPI). You can specify a ``VERSION``, and you can specify ``REQUIRED`` or ``QUIET``. Only available if ``NOPYTHON`` mode is not active. Sets ``module_VERSION`` and ``module_FOUND``. Caches the result once a valid install is found. Suggested usage =============== Using ``find_package`` with version info is not recommended except for release versions. .. code-block:: cmake find_package(pybind11 CONFIG) find_package(pybind11 2.9 EXACT CONFIG REQUIRED) #]=============================================================================] @PACKAGE_INIT@ # Location of pybind11/pybind11.h # This will be relative unless explicitly set as absolute set(pybind11_INCLUDE_DIR "@pybind11_INCLUDEDIR@") set(pybind11_LIBRARY "") set(pybind11_DEFINITIONS USING_pybind11) set(pybind11_VERSION_TYPE "@pybind11_VERSION_TYPE@") check_required_components(pybind11) if(TARGET pybind11::python_link_helper) # This has already been setup elsewhere, such as with a previous call or # add_subdirectory return() endif() include("${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake") # Easier to use / remember add_library(pybind11::headers IMPORTED INTERFACE) set_target_properties(pybind11::headers PROPERTIES INTERFACE_LINK_LIBRARIES pybind11::pybind11_headers) include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake") if(NOT pybind11_FIND_QUIETLY) message( STATUS "Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}${pybind11_VERSION_TYPE}\")" ) endif() aoflagger-v3.4.0/external/pybind11/tools/pybind11NewTools.cmake0000644000175000017500000002140014507760431023062 0ustar olesoles# tools/pybind11NewTools.cmake -- Build system for the pybind11 modules # # Copyright (c) 2020 Wenzel Jakob and Henry Schreiner # # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. if(CMAKE_VERSION VERSION_LESS 3.12) message(FATAL_ERROR "You cannot use the new FindPython module with CMake < 3.12") endif() include_guard(DIRECTORY) get_property( is_config TARGET pybind11::headers PROPERTY IMPORTED) if(pybind11_FIND_QUIETLY) set(_pybind11_quiet QUIET) else() set(_pybind11_quiet "") endif() if(NOT Python_FOUND AND NOT Python3_FOUND) if(NOT DEFINED Python_FIND_IMPLEMENTATIONS) set(Python_FIND_IMPLEMENTATIONS CPython PyPy) endif() # GitHub Actions like activation if(NOT DEFINED Python_ROOT_DIR AND DEFINED ENV{pythonLocation}) set(Python_ROOT_DIR "$ENV{pythonLocation}") endif() find_package(Python 3.6 REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet}) # If we are in submodule mode, export the Python targets to global targets. # If this behavior is not desired, FindPython _before_ pybind11. if(NOT is_config) set_property(TARGET Python::Python PROPERTY IMPORTED_GLOBAL TRUE) set_property(TARGET Python::Interpreter PROPERTY IMPORTED_GLOBAL TRUE) if(TARGET Python::Module) set_property(TARGET Python::Module PROPERTY IMPORTED_GLOBAL TRUE) endif() endif() endif() if(Python_FOUND) set(_Python Python CACHE INTERNAL "" FORCE) elseif(Python3_FOUND) set(_Python Python3 CACHE INTERNAL "" FORCE) endif() if(PYBIND11_MASTER_PROJECT) if(${_Python}_INTERPRETER_ID MATCHES "PyPy") message(STATUS "PyPy ${${_Python}_PyPy_VERSION} (Py ${${_Python}_VERSION})") else() message(STATUS "${_Python} ${${_Python}_VERSION}") endif() endif() # If a user finds Python, they may forget to include the Interpreter component # and the following two steps require it. It is highly recommended by CMake # when finding development libraries anyway, so we will require it. if(NOT DEFINED ${_Python}_EXECUTABLE) message( FATAL_ERROR "${_Python} was found without the Interpreter component. Pybind11 requires this component.") endif() if(NOT ${_Python}_EXECUTABLE STREQUAL PYBIND11_PYTHON_EXECUTABLE_LAST) # Detect changes to the Python version/binary in subsequent CMake runs, and refresh config if needed unset(PYTHON_IS_DEBUG CACHE) unset(PYTHON_MODULE_EXTENSION CACHE) set(PYBIND11_PYTHON_EXECUTABLE_LAST "${${_Python}_EXECUTABLE}" CACHE INTERNAL "Python executable during the last CMake run") endif() if(NOT DEFINED PYTHON_IS_DEBUG) # Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter execute_process( COMMAND "${${_Python}_EXECUTABLE}" "-c" "import sys; sys.exit(hasattr(sys, 'gettotalrefcount'))" RESULT_VARIABLE _PYTHON_IS_DEBUG) set(PYTHON_IS_DEBUG "${_PYTHON_IS_DEBUG}" CACHE INTERNAL "Python debug status") endif() # Get the suffix - SO is deprecated, should use EXT_SUFFIX, but this is # required for PyPy3 (as of 7.3.1) if(NOT DEFINED PYTHON_MODULE_EXTENSION) execute_process( COMMAND "${${_Python}_EXECUTABLE}" "-c" "import sys, importlib; s = importlib.import_module('distutils.sysconfig' if sys.version_info < (3, 10) else 'sysconfig'); print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))" OUTPUT_VARIABLE _PYTHON_MODULE_EXTENSION ERROR_VARIABLE _PYTHON_MODULE_EXTENSION_ERR OUTPUT_STRIP_TRAILING_WHITESPACE) if(_PYTHON_MODULE_EXTENSION STREQUAL "") message( FATAL_ERROR "pybind11 could not query the module file extension, likely the 'distutils'" "package is not installed. Full error message:\n${_PYTHON_MODULE_EXTENSION_ERR}") endif() # This needs to be available for the pybind11_extension function set(PYTHON_MODULE_EXTENSION "${_PYTHON_MODULE_EXTENSION}" CACHE INTERNAL "") endif() # Python debug libraries expose slightly different objects before 3.8 # https://docs.python.org/3.6/c-api/intro.html#debugging-builds # https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib if(PYTHON_IS_DEBUG) set_property( TARGET pybind11::pybind11 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG) endif() # Check on every access - since Python can change - do nothing in that case. if(DEFINED ${_Python}_INCLUDE_DIRS) # Only add Python for build - must be added during the import for config # since it has to be re-discovered. # # This needs to be a target to be included after the local pybind11 # directory, just in case there there is an installed pybind11 sitting # next to Python's includes. It also ensures Python is a SYSTEM library. add_library(pybind11::python_headers INTERFACE IMPORTED) set_property( TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$") set_property( TARGET pybind11::pybind11 APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers) set(pybind11_INCLUDE_DIRS "${pybind11_INCLUDE_DIR}" "${${_Python}_INCLUDE_DIRS}" CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located") endif() # In CMake 3.18+, you can find these separately, so include an if if(TARGET ${_Python}::Python) set_property( TARGET pybind11::embed APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Python) endif() # CMake 3.15+ has this if(TARGET ${_Python}::Module) set_property( TARGET pybind11::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Module) else() set_property( TARGET pybind11::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_link_helper) endif() # WITHOUT_SOABI and WITH_SOABI will disable the custom extension handling used by pybind11. # WITH_SOABI is passed on to python_add_library. function(pybind11_add_module target_name) cmake_parse_arguments(PARSE_ARGV 1 ARG "STATIC;SHARED;MODULE;THIN_LTO;OPT_SIZE;NO_EXTRAS;WITHOUT_SOABI" "" "") if(ARG_STATIC) set(lib_type STATIC) elseif(ARG_SHARED) set(lib_type SHARED) else() set(lib_type MODULE) endif() if("${_Python}" STREQUAL "Python") python_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS}) elseif("${_Python}" STREQUAL "Python3") python3_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS}) else() message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}") endif() target_link_libraries(${target_name} PRIVATE pybind11::headers) if(lib_type STREQUAL "MODULE") target_link_libraries(${target_name} PRIVATE pybind11::module) else() target_link_libraries(${target_name} PRIVATE pybind11::embed) endif() if(MSVC) target_link_libraries(${target_name} PRIVATE pybind11::windows_extras) endif() # -fvisibility=hidden is required to allow multiple modules compiled against # different pybind versions to work properly, and for some features (e.g. # py::module_local). We force it on everything inside the `pybind11` # namespace; also turning it on for a pybind module compilation here avoids # potential warnings or issues from having mixed hidden/non-hidden types. if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET) set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden") endif() if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET) set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden") endif() # If we don't pass a WITH_SOABI or WITHOUT_SOABI, use our own default handling of extensions if(NOT ARG_WITHOUT_SOABI AND NOT "WITH_SOABI" IN_LIST ARG_UNPARSED_ARGUMENTS) pybind11_extension(${target_name}) endif() if(ARG_NO_EXTRAS) return() endif() if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION) if(ARG_THIN_LTO) target_link_libraries(${target_name} PRIVATE pybind11::thin_lto) else() target_link_libraries(${target_name} PRIVATE pybind11::lto) endif() endif() # Use case-insensitive comparison to match the result of $ string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) if(NOT MSVC AND NOT "${uppercase_CMAKE_BUILD_TYPE}" MATCHES DEBUG|RELWITHDEBINFO) # Strip unnecessary sections of the binary on Linux/macOS pybind11_strip(${target_name}) endif() if(MSVC) target_link_libraries(${target_name} PRIVATE pybind11::windows_extras) endif() if(ARG_OPT_SIZE) target_link_libraries(${target_name} PRIVATE pybind11::opt_size) endif() endfunction() function(pybind11_extension name) # The extension is precomputed set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX "${PYTHON_MODULE_EXTENSION}") endfunction() aoflagger-v3.4.0/external/pybind11/tools/libsize.py0000644000175000017500000000200714507760431020753 0ustar olesolesimport os import sys # Internal build script for generating debugging test .so size. # Usage: # python libsize.py file.so save.txt -- displays the size of file.so and, if save.txt exists, compares it to the # size in it, then overwrites save.txt with the new size for future runs. if len(sys.argv) != 3: sys.exit("Invalid arguments: usage: python libsize.py file.so save.txt") lib = sys.argv[1] save = sys.argv[2] if not os.path.exists(lib): sys.exit(f"Error: requested file ({lib}) does not exist") libsize = os.path.getsize(lib) print("------", os.path.basename(lib), "file size:", libsize, end="") if os.path.exists(save): with open(save) as sf: oldsize = int(sf.readline()) if oldsize > 0: change = libsize - oldsize if change == 0: print(" (no change)") else: print(f" (change of {change:+} bytes = {change / oldsize:+.2%})") else: print() with open(save, "w") as sf: sf.write(str(libsize)) aoflagger-v3.4.0/external/pybind11/tools/make_changelog.py0000755000175000017500000000243714507760431022250 0ustar olesoles#!/usr/bin/env python3 import re import ghapi.all from rich import print from rich.syntax import Syntax ENTRY = re.compile( r""" Suggested \s changelog \s entry: .* ```rst \s* (.*?) \s* ``` """, re.DOTALL | re.VERBOSE, ) print() api = ghapi.all.GhApi(owner="pybind", repo="pybind11") issues_pages = ghapi.page.paged( api.issues.list_for_repo, labels="needs changelog", state="closed" ) issues = (issue for page in issues_pages for issue in page) missing = [] for issue in issues: changelog = ENTRY.findall(issue.body or "") if not changelog or not changelog[0]: missing.append(issue) else: (msg,) = changelog if not msg.startswith("* "): msg = "* " + msg if not msg.endswith("."): msg += "." msg += f"\n `#{issue.number} <{issue.html_url}>`_" print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True)) print() if missing: print() print("[blue]" + "-" * 30) print() for issue in missing: print(f"[red bold]Missing:[/red bold][red] {issue.title}") print(f"[red] {issue.html_url}\n") print("[bold]Template:\n") msg = "## Suggested changelog entry:\n\n```rst\n\n```" print(Syntax(msg, "md", theme="ansi_light")) print() aoflagger-v3.4.0/external/pybind11/tools/codespell_ignore_lines_from_errors.py0000644000175000017500000000213514507760431026442 0ustar olesoles"""Simple script for rebuilding .codespell-ignore-lines Usage: cat < /dev/null > .codespell-ignore-lines pre-commit run --all-files codespell >& /tmp/codespell_errors.txt python3 tools/codespell_ignore_lines_from_errors.py /tmp/codespell_errors.txt > .codespell-ignore-lines git diff to review changes, then commit, push. """ import sys from typing import List def run(args: List[str]) -> None: assert len(args) == 1, "codespell_errors.txt" cache = {} done = set() with open(args[0]) as f: lines = f.read().splitlines() for line in sorted(lines): i = line.find(" ==> ") if i > 0: flds = line[:i].split(":") if len(flds) >= 2: filename, line_num = flds[:2] if filename not in cache: with open(filename) as f: cache[filename] = f.read().splitlines() supp = cache[filename][int(line_num) - 1] if supp not in done: print(supp) done.add(supp) if __name__ == "__main__": run(args=sys.argv[1:]) aoflagger-v3.4.0/external/pybind11/tools/FindCatch.cmake0000644000175000017500000000462114507760431021571 0ustar olesoles# - Find the Catch test framework or download it (single header) # # This is a quick module for internal use. It assumes that Catch is # REQUIRED and that a minimum version is provided (not EXACT). If # a suitable version isn't found locally, the single header file # will be downloaded and placed in the build dir: PROJECT_BINARY_DIR. # # This code sets the following variables: # CATCH_INCLUDE_DIR - path to catch.hpp # CATCH_VERSION - version number option(DOWNLOAD_CATCH "Download catch2 if not found") if(NOT Catch_FIND_VERSION) message(FATAL_ERROR "A version number must be specified.") elseif(Catch_FIND_REQUIRED) message(FATAL_ERROR "This module assumes Catch is not required.") elseif(Catch_FIND_VERSION_EXACT) message(FATAL_ERROR "Exact version numbers are not supported, only minimum.") endif() # Extract the version number from catch.hpp function(_get_catch_version) file( STRINGS "${CATCH_INCLUDE_DIR}/catch.hpp" version_line REGEX "Catch v.*" LIMIT_COUNT 1) if(version_line MATCHES "Catch v([0-9]+)\\.([0-9]+)\\.([0-9]+)") set(CATCH_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" PARENT_SCOPE) endif() endfunction() # Download the single-header version of Catch function(_download_catch version destination_dir) message(STATUS "Downloading catch v${version}...") set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp) file( DOWNLOAD ${url} "${destination_dir}/catch.hpp" STATUS status LOG log) list(GET status 0 error) if(error) string(REPLACE "\n" "\n " log " ${log}") message(FATAL_ERROR "Could not download URL:\n" " ${url}\n" "Log:\n" "${log}") endif() set(CATCH_INCLUDE_DIR "${destination_dir}" CACHE INTERNAL "") endfunction() # Look for catch locally find_path( CATCH_INCLUDE_DIR NAMES catch.hpp PATH_SUFFIXES catch2) if(CATCH_INCLUDE_DIR) _get_catch_version() endif() # Download the header if it wasn't found or if it's outdated if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION}) if(DOWNLOAD_CATCH) _download_catch(${Catch_FIND_VERSION} "${PROJECT_BINARY_DIR}/catch/") _get_catch_version() else() set(CATCH_FOUND FALSE) return() endif() endif() add_library(Catch2::Catch2 IMPORTED INTERFACE) set_property(TARGET Catch2::Catch2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CATCH_INCLUDE_DIR}") set(CATCH_FOUND TRUE) aoflagger-v3.4.0/external/pybind11/tools/pybind11Common.cmake0000644000175000017500000003332114507760431022545 0ustar olesoles#[======================================================[.rst Adds the following targets:: pybind11::pybind11 - link to headers and pybind11 pybind11::module - Adds module links pybind11::embed - Adds embed links pybind11::lto - Link time optimizations (manual selection) pybind11::thin_lto - Link time optimizations (manual selection) pybind11::python_link_helper - Adds link to Python libraries pybind11::windows_extras - MSVC bigobj and mp for building multithreaded pybind11::opt_size - avoid optimizations that increase code size Adds the following functions:: pybind11_strip(target) - strip target after building on linux/macOS pybind11_find_import(module) - See if a module is installed. #]======================================================] # CMake 3.10 has an include_guard command, but we can't use that yet # include_guard(global) (pre-CMake 3.10) if(TARGET pybind11::lto) return() endif() # If we are in subdirectory mode, all IMPORTED targets must be GLOBAL. If we # are in CONFIG mode, they should be "normal" targets instead. # In CMake 3.11+ you can promote a target to global after you create it, # which might be simpler than this check. get_property( is_config TARGET pybind11::headers PROPERTY IMPORTED) if(NOT is_config) set(optional_global GLOBAL) endif() # If not run in Python mode, we still would like this to at least # include pybind11's include directory: set(pybind11_INCLUDE_DIRS "${pybind11_INCLUDE_DIR}" CACHE INTERNAL "Include directory for pybind11 (Python not requested)") # --------------------- Shared targets ---------------------------- # Build an interface library target: add_library(pybind11::pybind11 IMPORTED INTERFACE ${optional_global}) set_property( TARGET pybind11::pybind11 APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::headers) # Build a module target: add_library(pybind11::module IMPORTED INTERFACE ${optional_global}) set_property( TARGET pybind11::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11) # Build an embed library target: add_library(pybind11::embed IMPORTED INTERFACE ${optional_global}) set_property( TARGET pybind11::embed APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11) # --------------------------- link helper --------------------------- add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global}) if(CMAKE_VERSION VERSION_LESS 3.13) # In CMake 3.11+, you can set INTERFACE properties via the normal methods, and # this would be simpler. set_property( TARGET pybind11::python_link_helper APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$<$:-undefined dynamic_lookup>") else() # link_options was added in 3.13+ # This is safer, because you are ensured the deduplication pass in CMake will not consider # these separate and remove one but not the other. set_property( TARGET pybind11::python_link_helper APPEND PROPERTY INTERFACE_LINK_OPTIONS "$<$:LINKER:-undefined,dynamic_lookup>") endif() # ------------------------ Windows extras ------------------------- add_library(pybind11::windows_extras IMPORTED INTERFACE ${optional_global}) if(MSVC) # That's also clang-cl # /bigobj is needed for bigger binding projects due to the limit to 64k # addressable sections set_property( TARGET pybind11::windows_extras APPEND PROPERTY INTERFACE_COMPILE_OPTIONS $<$:/bigobj>) # /MP enables multithreaded builds (relevant when there are many files) for MSVC if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # no Clang no Intel if(CMAKE_VERSION VERSION_LESS 3.11) set_property( TARGET pybind11::windows_extras APPEND PROPERTY INTERFACE_COMPILE_OPTIONS $<$>:/MP>) else() # Only set these options for C++ files. This is important so that, for # instance, projects that include other types of source files like CUDA # .cu files don't get these options propagated to nvcc since that would # cause the build to fail. set_property( TARGET pybind11::windows_extras APPEND PROPERTY INTERFACE_COMPILE_OPTIONS $<$>:$<$:/MP>>) endif() endif() endif() # ----------------------- Optimize binary size -------------------------- add_library(pybind11::opt_size IMPORTED INTERFACE ${optional_global}) if(MSVC) set(PYBIND11_OPT_SIZE /Os) else() set(PYBIND11_OPT_SIZE -Os) endif() set_property( TARGET pybind11::opt_size APPEND PROPERTY INTERFACE_COMPILE_OPTIONS $<$:${PYBIND11_OPT_SIZE}> $<$:${PYBIND11_OPT_SIZE}> $<$:${PYBIND11_OPT_SIZE}>) # ----------------------- Legacy option -------------------------- # Warn or error if old variable name used if(PYBIND11_CPP_STANDARD) string(REGEX MATCH [[..$]] VAL "${PYBIND11_CPP_STANDARD}") if(CMAKE_CXX_STANDARD) if(NOT CMAKE_CXX_STANDARD STREQUAL VAL) message(WARNING "CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} does not match " "PYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}, " "please remove PYBIND11_CPP_STANDARD from your cache") endif() else() set(supported_standards 11 14 17 20) if("${VAL}" IN_LIST supported_standards) message(WARNING "USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_CPP_STANDARD") set(CMAKE_CXX_STANDARD ${VAL} CACHE STRING "From PYBIND11_CPP_STANDARD") else() message(FATAL_ERROR "PYBIND11_CPP_STANDARD should be replaced with CMAKE_CXX_STANDARD " "(last two chars: ${VAL} not understood as a valid CXX std)") endif() endif() endif() # --------------------- Python specifics ------------------------- # Check to see which Python mode we are in, new, old, or no python if(PYBIND11_NOPYTHON) set(_pybind11_nopython ON) elseif( PYBIND11_FINDPYTHON OR Python_FOUND OR Python2_FOUND OR Python3_FOUND) # New mode include("${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake") else() # Classic mode include("${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake") endif() # --------------------- pybind11_find_import ------------------------------- if(NOT _pybind11_nopython) # Check to see if modules are importable. Use REQUIRED to force an error if # one of the modules is not found. _FOUND will be set if the # package was found (underscores replace dashes if present). QUIET will hide # the found message, and VERSION will require a minimum version. A successful # find will cache the result. function(pybind11_find_import PYPI_NAME) # CMake variables need underscores (PyPI doesn't care) string(REPLACE "-" "_" NORM_PYPI_NAME "${PYPI_NAME}") # Return if found previously if(${NORM_PYPI_NAME}_FOUND) return() endif() set(options "REQUIRED;QUIET") set(oneValueArgs "VERSION") cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "" ${ARGN}) if(ARG_REQUIRED) set(status_level FATAL_ERROR) else() set(status_level WARNING) endif() execute_process( COMMAND ${${_Python}_EXECUTABLE} -c "from pkg_resources import get_distribution; print(get_distribution('${PYPI_NAME}').version)" RESULT_VARIABLE RESULT_PRESENT OUTPUT_VARIABLE PKG_VERSION ERROR_QUIET) string(STRIP "${PKG_VERSION}" PKG_VERSION) # If a result is present, this failed if(RESULT_PRESENT) set(${NORM_PYPI_NAME}_FOUND ${NORM_PYPI_NAME}-NOTFOUND CACHE INTERNAL "") # Always warn or error message( ${status_level} "Missing: ${PYPI_NAME} ${ARG_VERSION}\nTry: ${${_Python}_EXECUTABLE} -m pip install ${PYPI_NAME}" ) else() if(ARG_VERSION AND PKG_VERSION VERSION_LESS ARG_VERSION) message( ${status_level} "Version incorrect: ${PYPI_NAME} ${PKG_VERSION} found, ${ARG_VERSION} required - try upgrading" ) else() set(${NORM_PYPI_NAME}_FOUND YES CACHE INTERNAL "") set(${NORM_PYPI_NAME}_VERSION ${PKG_VERSION} CACHE INTERNAL "") endif() if(NOT ARG_QUIET) message(STATUS "Found ${PYPI_NAME} ${PKG_VERSION}") endif() endif() if(NOT ARG_VERSION OR (NOT PKG_VERSION VERSION_LESS ARG_VERSION)) # We have successfully found a good version, cache to avoid calling again. endif() endfunction() endif() # --------------------- LTO ------------------------------- include(CheckCXXCompilerFlag) # Checks whether the given CXX/linker flags can compile and link a cxx file. # cxxflags and linkerflags are lists of flags to use. The result variable is a # unique variable name for each set of flags: the compilation result will be # cached base on the result variable. If the flags work, sets them in # cxxflags_out/linkerflags_out internal cache variables (in addition to # ${result}). function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out linkerflags_out) set(CMAKE_REQUIRED_LIBRARIES ${linkerflags}) check_cxx_compiler_flag("${cxxflags}" ${result}) if(${result}) set(${cxxflags_out} "${cxxflags}" PARENT_SCOPE) set(${linkerflags_out} "${linkerflags}" PARENT_SCOPE) endif() endfunction() function(_pybind11_generate_lto target prefer_thin_lto) if(MINGW) message(STATUS "${target} disabled (problems with undefined symbols for MinGW for now)") return() endif() if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") set(cxx_append "") set(linker_append "") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) # Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it set(linker_append ";$<$:-O3>") elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT MINGW) set(cxx_append ";-fno-fat-lto-objects") endif() if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64") set(NO_FLTO_ARCH TRUE) else() set(NO_FLTO_ARCH FALSE) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND prefer_thin_lto AND NOT NO_FLTO_ARCH) _pybind11_return_if_cxx_and_linker_flags_work( HAS_FLTO_THIN "-flto=thin${cxx_append}" "-flto=thin${linker_append}" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) endif() if(NOT HAS_FLTO_THIN AND NOT NO_FLTO_ARCH) _pybind11_return_if_cxx_and_linker_flags_work( HAS_FLTO "-flto${cxx_append}" "-flto${linker_append}" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM") # IntelLLVM equivalent to LTO is called IPO; also IntelLLVM is WIN32/UNIX # WARNING/HELP WANTED: This block of code is currently not covered by pybind11 GitHub Actions! if(WIN32) _pybind11_return_if_cxx_and_linker_flags_work( HAS_INTEL_IPO "-Qipo" "-Qipo" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) else() _pybind11_return_if_cxx_and_linker_flags_work( HAS_INTEL_IPO "-ipo" "-ipo" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") # Intel equivalent to LTO is called IPO _pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO "-ipo" "-ipo" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) elseif(MSVC) # cmake only interprets libraries as linker flags when they start with a - (otherwise it # converts /LTCG to \LTCG as if it was a Windows path). Luckily MSVC supports passing flags # with - instead of /, even if it is a bit non-standard: _pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG "/GL" "-LTCG" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) endif() # Enable LTO flags if found, except for Debug builds if(PYBIND11_LTO_CXX_FLAGS) # CONFIG takes multiple values in CMake 3.19+, until then we have to use OR set(is_debug "$,$>") set(not_debug "$") set(cxx_lang "$") if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11) set(genex "${not_debug}") else() set(genex "$") endif() set_property( TARGET ${target} APPEND PROPERTY INTERFACE_COMPILE_OPTIONS "$<${genex}:${PYBIND11_LTO_CXX_FLAGS}>") if(CMAKE_PROJECT_NAME STREQUAL "pybind11") message(STATUS "${target} enabled") endif() else() if(CMAKE_PROJECT_NAME STREQUAL "pybind11") message(STATUS "${target} disabled (not supported by the compiler and/or linker)") endif() endif() if(PYBIND11_LTO_LINKER_FLAGS) if(CMAKE_VERSION VERSION_LESS 3.11) set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") else() set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") endif() endif() endfunction() add_library(pybind11::lto IMPORTED INTERFACE ${optional_global}) _pybind11_generate_lto(pybind11::lto FALSE) add_library(pybind11::thin_lto IMPORTED INTERFACE ${optional_global}) _pybind11_generate_lto(pybind11::thin_lto TRUE) # ---------------------- pybind11_strip ----------------------------- function(pybind11_strip target_name) # Strip unnecessary sections of the binary on Linux/macOS if(CMAKE_STRIP) if(APPLE) set(x_opt -x) endif() add_custom_command( TARGET ${target_name} POST_BUILD COMMAND ${CMAKE_STRIP} ${x_opt} $) endif() endfunction() aoflagger-v3.4.0/external/pybind11/tools/FindPythonLibsNew.cmake0000644000175000017500000002566614507760431023330 0ustar olesoles# - Find python libraries # This module finds the libraries corresponding to the Python interpreter # FindPythonInterp provides. # This code sets the following variables: # # PYTHONLIBS_FOUND - have the Python libs been found # PYTHON_PREFIX - path to the Python installation # PYTHON_LIBRARIES - path to the python library # PYTHON_INCLUDE_DIRS - path to where Python.h is found # PYTHON_MODULE_EXTENSION - lib extension, e.g. '.so' or '.pyd' # PYTHON_MODULE_PREFIX - lib name prefix: usually an empty string # PYTHON_SITE_PACKAGES - path to installation site-packages # PYTHON_IS_DEBUG - whether the Python interpreter is a debug build # # Thanks to talljimbo for the patch adding the 'LDVERSION' config # variable usage. #============================================================================= # Copyright 2001-2009 Kitware, Inc. # Copyright 2012 Continuum Analytics, Inc. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the names of Kitware, Inc., the Insight Software Consortium, # nor the names of their contributors may be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= # Checking for the extension makes sure that `LibsNew` was found and not just `Libs`. if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION) return() endif() if(PythonLibsNew_FIND_QUIETLY) set(_pythonlibs_quiet QUIET) else() set(_pythonlibs_quiet "") endif() if(PythonLibsNew_FIND_REQUIRED) set(_pythonlibs_required REQUIRED) endif() # Check to see if the `python` command is present and from a virtual # environment, conda, or GHA activation - if it is, try to use that. if(NOT DEFINED PYTHON_EXECUTABLE) if(DEFINED ENV{VIRTUAL_ENV}) find_program( PYTHON_EXECUTABLE python PATHS "$ENV{VIRTUAL_ENV}" "$ENV{VIRTUAL_ENV}/bin" NO_DEFAULT_PATH) elseif(DEFINED ENV{CONDA_PREFIX}) find_program( PYTHON_EXECUTABLE python PATHS "$ENV{CONDA_PREFIX}" "$ENV{CONDA_PREFIX}/bin" NO_DEFAULT_PATH) elseif(DEFINED ENV{pythonLocation}) find_program( PYTHON_EXECUTABLE python PATHS "$ENV{pythonLocation}" "$ENV{pythonLocation}/bin" NO_DEFAULT_PATH) endif() if(NOT PYTHON_EXECUTABLE) unset(PYTHON_EXECUTABLE) endif() endif() # Use the Python interpreter to find the libs. if(NOT PythonLibsNew_FIND_VERSION) set(PythonLibsNew_FIND_VERSION "3.6") endif() find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required} ${_pythonlibs_quiet}) if(NOT PYTHONINTERP_FOUND) set(PYTHONLIBS_FOUND FALSE) set(PythonLibsNew_FOUND FALSE) return() endif() # According to https://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter # testing whether sys has the gettotalrefcount function is a reliable, cross-platform # way to detect a CPython debug interpreter. # # The library suffix is from the config var LDVERSION sometimes, otherwise # VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows. execute_process( COMMAND "${PYTHON_EXECUTABLE}" "-c" " import sys;import struct; import sysconfig as s USE_SYSCONFIG = sys.version_info >= (3, 10) if not USE_SYSCONFIG: from distutils import sysconfig as ds print('.'.join(str(v) for v in sys.version_info)); print(sys.prefix); if USE_SYSCONFIG: scheme = s.get_default_scheme() if scheme == 'posix_local': # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/ scheme = 'posix_prefix' print(s.get_path('platinclude', scheme)) print(s.get_path('platlib')) print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO')) else: print(ds.get_python_inc(plat_specific=True)); print(ds.get_python_lib(plat_specific=True)); print(ds.get_config_var('EXT_SUFFIX') or ds.get_config_var('SO')); print(hasattr(sys, 'gettotalrefcount')+0); print(struct.calcsize('@P')); print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION')); print(s.get_config_var('LIBDIR') or ''); print(s.get_config_var('MULTIARCH') or ''); " RESULT_VARIABLE _PYTHON_SUCCESS OUTPUT_VARIABLE _PYTHON_VALUES ERROR_VARIABLE _PYTHON_ERROR_VALUE) if(NOT _PYTHON_SUCCESS MATCHES 0) if(PythonLibsNew_FIND_REQUIRED) message(FATAL_ERROR "Python config failure:\n${_PYTHON_ERROR_VALUE}") endif() set(PYTHONLIBS_FOUND FALSE) set(PythonLibsNew_FOUND FALSE) return() endif() option( PYBIND11_PYTHONLIBS_OVERWRITE "Overwrite cached values read from Python library (classic search). Turn off if cross-compiling and manually setting these values." ON) # Can manually set values when cross-compiling macro(_PYBIND11_GET_IF_UNDEF lst index name) if(PYBIND11_PYTHONLIBS_OVERWRITE OR NOT DEFINED "${name}") list(GET "${lst}" "${index}" "${name}") endif() endmacro() # Convert the process output into a list if(WIN32) string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES}) endif() string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES}) string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES}) _pybind11_get_if_undef(_PYTHON_VALUES 0 _PYTHON_VERSION_LIST) _pybind11_get_if_undef(_PYTHON_VALUES 1 PYTHON_PREFIX) _pybind11_get_if_undef(_PYTHON_VALUES 2 PYTHON_INCLUDE_DIR) _pybind11_get_if_undef(_PYTHON_VALUES 3 PYTHON_SITE_PACKAGES) _pybind11_get_if_undef(_PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION) _pybind11_get_if_undef(_PYTHON_VALUES 5 PYTHON_IS_DEBUG) _pybind11_get_if_undef(_PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P) _pybind11_get_if_undef(_PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX) _pybind11_get_if_undef(_PYTHON_VALUES 8 PYTHON_LIBDIR) _pybind11_get_if_undef(_PYTHON_VALUES 9 PYTHON_MULTIARCH) # Make sure the Python has the same pointer-size as the chosen compiler # Skip if CMAKE_SIZEOF_VOID_P is not defined # This should be skipped for (non-Apple) cross-compiles (like EMSCRIPTEN) if(NOT CMAKE_CROSSCOMPILING AND CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}")) if(PythonLibsNew_FIND_REQUIRED) math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8") math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8") message(FATAL_ERROR "Python config failure: Python is ${_PYTHON_BITS}-bit, " "chosen compiler is ${_CMAKE_BITS}-bit") endif() set(PYTHONLIBS_FOUND FALSE) set(PythonLibsNew_FOUND FALSE) return() endif() # The built-in FindPython didn't always give the version numbers string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST}) list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR) list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR) list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH) set(PYTHON_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}") # Make sure all directory separators are '/' string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}") string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}") string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}") if(DEFINED PYTHON_LIBRARY) # Don't write to PYTHON_LIBRARY if it's already set elseif(CMAKE_HOST_WIN32) set(PYTHON_LIBRARY "${PYTHON_PREFIX}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib") # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the # original python installation. They may be found relative to PYTHON_INCLUDE_DIR. if(NOT EXISTS "${PYTHON_LIBRARY}") get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY) set(PYTHON_LIBRARY "${_PYTHON_ROOT}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib") endif() # if we are in MSYS & MINGW, and we didn't find windows python lib, look for system python lib if(DEFINED ENV{MSYSTEM} AND MINGW AND NOT EXISTS "${PYTHON_LIBRARY}") if(PYTHON_MULTIARCH) set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") else() set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") endif() unset(PYTHON_LIBRARY) find_library( PYTHON_LIBRARY NAMES "python${PYTHON_LIBRARY_SUFFIX}" PATHS ${_PYTHON_LIBS_SEARCH} NO_DEFAULT_PATH) endif() # raise an error if the python libs are still not found. if(NOT EXISTS "${PYTHON_LIBRARY}") message(FATAL_ERROR "Python libraries not found") endif() else() if(PYTHON_MULTIARCH) set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") else() set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") endif() #message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}") # Probably this needs to be more involved. It would be nice if the config # information the python interpreter itself gave us were more complete. find_library( PYTHON_LIBRARY NAMES "python${PYTHON_LIBRARY_SUFFIX}" PATHS ${_PYTHON_LIBS_SEARCH} NO_DEFAULT_PATH) # If all else fails, just set the name/version and let the linker figure out the path. if(NOT PYTHON_LIBRARY) set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX}) endif() endif() mark_as_advanced(PYTHON_LIBRARY PYTHON_INCLUDE_DIR) # We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the # cache entries because they are meant to specify the location of a single # library. We now set the variables listed by the documentation for this # module. set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") if(NOT PYTHON_DEBUG_LIBRARY) set(PYTHON_DEBUG_LIBRARY "") endif() set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") find_package_message(PYTHON "Found PythonLibs: ${PYTHON_LIBRARIES}" "${PYTHON_EXECUTABLE}${PYTHON_VERSION_STRING}") set(PYTHONLIBS_FOUND TRUE) set(PythonLibsNew_FOUND TRUE) if(NOT PYTHON_MODULE_PREFIX) set(PYTHON_MODULE_PREFIX "") endif() aoflagger-v3.4.0/external/pybind11/tools/pyproject.toml0000644000175000017500000000013614507760431021655 0ustar olesoles[build-system] requires = ["setuptools>=42", "wheel"] build-backend = "setuptools.build_meta" aoflagger-v3.4.0/external/pybind11/tests/0000755000175000017500000000000014516225226016741 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_multiple_inheritance.py0000644000175000017500000002714214507760431024566 0ustar olesolesimport pytest import env # noqa: F401 from pybind11_tests import ConstructorStats from pybind11_tests import multiple_inheritance as m def test_multiple_inheritance_cpp(): mt = m.MIType(3, 4) assert mt.foo() == 3 assert mt.bar() == 4 @pytest.mark.xfail("env.PYPY") def test_multiple_inheritance_mix1(): class Base1: def __init__(self, i): self.i = i def foo(self): return self.i class MITypePy(Base1, m.Base2): def __init__(self, i, j): Base1.__init__(self, i) m.Base2.__init__(self, j) mt = MITypePy(3, 4) assert mt.foo() == 3 assert mt.bar() == 4 def test_multiple_inheritance_mix2(): class Base2: def __init__(self, i): self.i = i def bar(self): return self.i class MITypePy(m.Base1, Base2): def __init__(self, i, j): m.Base1.__init__(self, i) Base2.__init__(self, j) mt = MITypePy(3, 4) assert mt.foo() == 3 assert mt.bar() == 4 @pytest.mark.xfail("env.PYPY") def test_multiple_inheritance_python(): class MI1(m.Base1, m.Base2): def __init__(self, i, j): m.Base1.__init__(self, i) m.Base2.__init__(self, j) class B1: def v(self): return 1 class MI2(B1, m.Base1, m.Base2): def __init__(self, i, j): B1.__init__(self) m.Base1.__init__(self, i) m.Base2.__init__(self, j) class MI3(MI2): def __init__(self, i, j): MI2.__init__(self, i, j) class MI4(MI3, m.Base2): def __init__(self, i, j): MI3.__init__(self, i, j) # This should be ignored (Base2 is already initialized via MI2): m.Base2.__init__(self, i + 100) class MI5(m.Base2, B1, m.Base1): def __init__(self, i, j): B1.__init__(self) m.Base1.__init__(self, i) m.Base2.__init__(self, j) class MI6(m.Base2, B1): def __init__(self, i): m.Base2.__init__(self, i) B1.__init__(self) class B2(B1): def v(self): return 2 class B3: def v(self): return 3 class B4(B3, B2): def v(self): return 4 class MI7(B4, MI6): def __init__(self, i): B4.__init__(self) MI6.__init__(self, i) class MI8(MI6, B3): def __init__(self, i): MI6.__init__(self, i) B3.__init__(self) class MI8b(B3, MI6): def __init__(self, i): B3.__init__(self) MI6.__init__(self, i) mi1 = MI1(1, 2) assert mi1.foo() == 1 assert mi1.bar() == 2 mi2 = MI2(3, 4) assert mi2.v() == 1 assert mi2.foo() == 3 assert mi2.bar() == 4 mi3 = MI3(5, 6) assert mi3.v() == 1 assert mi3.foo() == 5 assert mi3.bar() == 6 mi4 = MI4(7, 8) assert mi4.v() == 1 assert mi4.foo() == 7 assert mi4.bar() == 8 mi5 = MI5(10, 11) assert mi5.v() == 1 assert mi5.foo() == 10 assert mi5.bar() == 11 mi6 = MI6(12) assert mi6.v() == 1 assert mi6.bar() == 12 mi7 = MI7(13) assert mi7.v() == 4 assert mi7.bar() == 13 mi8 = MI8(14) assert mi8.v() == 1 assert mi8.bar() == 14 mi8b = MI8b(15) assert mi8b.v() == 3 assert mi8b.bar() == 15 def test_multiple_inheritance_python_many_bases(): class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4): def __init__(self): m.BaseN1.__init__(self, 1) m.BaseN2.__init__(self, 2) m.BaseN3.__init__(self, 3) m.BaseN4.__init__(self, 4) class MIMany58(m.BaseN5, m.BaseN6, m.BaseN7, m.BaseN8): def __init__(self): m.BaseN5.__init__(self, 5) m.BaseN6.__init__(self, 6) m.BaseN7.__init__(self, 7) m.BaseN8.__init__(self, 8) class MIMany916( m.BaseN9, m.BaseN10, m.BaseN11, m.BaseN12, m.BaseN13, m.BaseN14, m.BaseN15, m.BaseN16, ): def __init__(self): m.BaseN9.__init__(self, 9) m.BaseN10.__init__(self, 10) m.BaseN11.__init__(self, 11) m.BaseN12.__init__(self, 12) m.BaseN13.__init__(self, 13) m.BaseN14.__init__(self, 14) m.BaseN15.__init__(self, 15) m.BaseN16.__init__(self, 16) class MIMany19(MIMany14, MIMany58, m.BaseN9): def __init__(self): MIMany14.__init__(self) MIMany58.__init__(self) m.BaseN9.__init__(self, 9) class MIMany117(MIMany14, MIMany58, MIMany916, m.BaseN17): def __init__(self): MIMany14.__init__(self) MIMany58.__init__(self) MIMany916.__init__(self) m.BaseN17.__init__(self, 17) # Inherits from 4 registered C++ classes: can fit in one pointer on any modern arch: a = MIMany14() for i in range(1, 4): assert getattr(a, "f" + str(i))() == 2 * i # Inherits from 8: requires 1/2 pointers worth of holder flags on 32/64-bit arch: b = MIMany916() for i in range(9, 16): assert getattr(b, "f" + str(i))() == 2 * i # Inherits from 9: requires >= 2 pointers worth of holder flags c = MIMany19() for i in range(1, 9): assert getattr(c, "f" + str(i))() == 2 * i # Inherits from 17: requires >= 3 pointers worth of holder flags d = MIMany117() for i in range(1, 17): assert getattr(d, "f" + str(i))() == 2 * i def test_multiple_inheritance_virtbase(): class MITypePy(m.Base12a): def __init__(self, i, j): m.Base12a.__init__(self, i, j) mt = MITypePy(3, 4) assert mt.bar() == 4 assert m.bar_base2a(mt) == 4 assert m.bar_base2a_sharedptr(mt) == 4 def test_mi_static_properties(): """Mixing bases with and without static properties should be possible and the result should be independent of base definition order""" for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()): assert d.vanilla() == "Vanilla" assert d.static_func1() == "WithStatic1" assert d.static_func2() == "WithStatic2" assert d.static_func() == d.__class__.__name__ m.WithStatic1.static_value1 = 1 m.WithStatic2.static_value2 = 2 assert d.static_value1 == 1 assert d.static_value2 == 2 assert d.static_value == 12 d.static_value1 = 0 assert d.static_value1 == 0 d.static_value2 = 0 assert d.static_value2 == 0 d.static_value = 0 assert d.static_value == 0 # Requires PyPy 6+ def test_mi_dynamic_attributes(): """Mixing bases with and without dynamic attribute support""" for d in (m.VanillaDictMix1(), m.VanillaDictMix2()): d.dynamic = 1 assert d.dynamic == 1 def test_mi_unaligned_base(): """Returning an offset (non-first MI) base class pointer should recognize the instance""" n_inst = ConstructorStats.detail_reg_inst() c = m.I801C() d = m.I801D() # + 4 below because we have the two instances, and each instance has offset base I801B2 assert ConstructorStats.detail_reg_inst() == n_inst + 4 b1c = m.i801b1_c(c) assert b1c is c b2c = m.i801b2_c(c) assert b2c is c b1d = m.i801b1_d(d) assert b1d is d b2d = m.i801b2_d(d) assert b2d is d assert ConstructorStats.detail_reg_inst() == n_inst + 4 # no extra instances del c, b1c, b2c assert ConstructorStats.detail_reg_inst() == n_inst + 2 del d, b1d, b2d assert ConstructorStats.detail_reg_inst() == n_inst def test_mi_base_return(): """Tests returning an offset (non-first MI) base class pointer to a derived instance""" n_inst = ConstructorStats.detail_reg_inst() c1 = m.i801c_b1() assert type(c1) is m.I801C assert c1.a == 1 assert c1.b == 2 d1 = m.i801d_b1() assert type(d1) is m.I801D assert d1.a == 1 assert d1.b == 2 assert ConstructorStats.detail_reg_inst() == n_inst + 4 c2 = m.i801c_b2() assert type(c2) is m.I801C assert c2.a == 1 assert c2.b == 2 d2 = m.i801d_b2() assert type(d2) is m.I801D assert d2.a == 1 assert d2.b == 2 assert ConstructorStats.detail_reg_inst() == n_inst + 8 del c2 assert ConstructorStats.detail_reg_inst() == n_inst + 6 del c1, d1, d2 assert ConstructorStats.detail_reg_inst() == n_inst # Returning an unregistered derived type with a registered base; we won't # pick up the derived type, obviously, but should still work (as an object # of whatever type was returned). e1 = m.i801e_c() assert type(e1) is m.I801C assert e1.a == 1 assert e1.b == 2 e2 = m.i801e_b2() assert type(e2) is m.I801B2 assert e2.b == 2 def test_diamond_inheritance(): """Tests that diamond inheritance works as expected (issue #959)""" # Issue #959: this shouldn't segfault: d = m.D() # Make sure all the various distinct pointers are all recognized as registered instances: assert d is d.c0() assert d is d.c1() assert d is d.b() assert d is d.c0().b() assert d is d.c1().b() assert d is d.c0().c1().b().c0().b() def test_pr3635_diamond_b(): o = m.MVB() assert o.b == 1 assert o.get_b_b() == 1 def test_pr3635_diamond_c(): o = m.MVC() assert o.b == 1 assert o.c == 2 assert o.get_b_b() == 1 assert o.get_c_b() == 1 assert o.get_c_c() == 2 def test_pr3635_diamond_d0(): o = m.MVD0() assert o.b == 1 assert o.c == 2 assert o.d0 == 3 assert o.get_b_b() == 1 assert o.get_c_b() == 1 assert o.get_d0_b() == 1 assert o.get_c_c() == 2 assert o.get_d0_c() == 2 assert o.get_d0_d0() == 3 def test_pr3635_diamond_d1(): o = m.MVD1() assert o.b == 1 assert o.c == 2 assert o.d1 == 4 assert o.get_b_b() == 1 assert o.get_c_b() == 1 assert o.get_d1_b() == 1 assert o.get_c_c() == 2 assert o.get_d1_c() == 2 assert o.get_d1_d1() == 4 def test_pr3635_diamond_e(): o = m.MVE() assert o.b == 1 assert o.c == 2 assert o.d0 == 3 assert o.d1 == 4 assert o.e == 5 assert o.get_b_b() == 1 assert o.get_c_b() == 1 assert o.get_d0_b() == 1 assert o.get_d1_b() == 1 assert o.get_e_b() == 1 assert o.get_c_c() == 2 assert o.get_d0_c() == 2 assert o.get_d1_c() == 2 assert o.get_e_c() == 2 assert o.get_d0_d0() == 3 assert o.get_e_d0() == 3 assert o.get_d1_d1() == 4 assert o.get_e_d1() == 4 assert o.get_e_e() == 5 def test_pr3635_diamond_f(): o = m.MVF() assert o.b == 1 assert o.c == 2 assert o.d0 == 3 assert o.d1 == 4 assert o.e == 5 assert o.f == 6 assert o.get_b_b() == 1 assert o.get_c_b() == 1 assert o.get_d0_b() == 1 assert o.get_d1_b() == 1 assert o.get_e_b() == 1 assert o.get_f_b() == 1 assert o.get_c_c() == 2 assert o.get_d0_c() == 2 assert o.get_d1_c() == 2 assert o.get_e_c() == 2 assert o.get_f_c() == 2 assert o.get_d0_d0() == 3 assert o.get_e_d0() == 3 assert o.get_f_d0() == 3 assert o.get_d1_d1() == 4 assert o.get_e_d1() == 4 assert o.get_f_d1() == 4 assert o.get_e_e() == 5 assert o.get_f_e() == 5 assert o.get_f_f() == 6 def test_python_inherit_from_mi(): """Tests extending a Python class from a single inheritor of a MI class""" class PyMVF(m.MVF): g = 7 def get_g_g(self): return self.g o = PyMVF() assert o.b == 1 assert o.c == 2 assert o.d0 == 3 assert o.d1 == 4 assert o.e == 5 assert o.f == 6 assert o.g == 7 assert o.get_g_g() == 7 aoflagger-v3.4.0/external/pybind11/tests/test_async.cpp0000644000175000017500000000152714507760431021630 0ustar olesoles/* tests/test_async.cpp -- __await__ support Copyright (c) 2019 Google Inc. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "pybind11_tests.h" TEST_SUBMODULE(async_module, m) { struct DoesNotSupportAsync {}; py::class_(m, "DoesNotSupportAsync").def(py::init<>()); struct SupportsAsync {}; py::class_(m, "SupportsAsync") .def(py::init<>()) .def("__await__", [](const SupportsAsync &self) -> py::object { static_cast(self); py::object loop = py::module_::import("asyncio.events").attr("get_event_loop")(); py::object f = loop.attr("create_future")(); f.attr("set_result")(5); return f.attr("__await__")(); }); } aoflagger-v3.4.0/external/pybind11/tests/test_virtual_functions.cpp0000644000175000017500000005471714507760431024302 0ustar olesoles/* tests/test_virtual_functions.cpp -- overriding virtual functions from Python Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "constructor_stats.h" #include "pybind11_tests.h" #include /* This is an example class that we'll want to be able to extend from Python */ class ExampleVirt { public: explicit ExampleVirt(int state) : state(state) { print_created(this, state); } ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); } ExampleVirt(ExampleVirt &&e) noexcept : state(e.state) { print_move_created(this); e.state = 0; } virtual ~ExampleVirt() { print_destroyed(this); } virtual int run(int value) { py::print("Original implementation of " "ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format( state, value, get_string1(), *get_string2())); return state + value; } virtual bool run_bool() = 0; virtual void pure_virtual() = 0; // Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a // bit trickier, because the actual int& or std::string& or whatever only exists temporarily, // so we have to handle it specially in the trampoline class (see below). virtual const std::string &get_string1() { return str1; } virtual const std::string *get_string2() { return &str2; } private: int state; const std::string str1{"default1"}, str2{"default2"}; }; /* This is a wrapper class that must be generated */ class PyExampleVirt : public ExampleVirt { public: using ExampleVirt::ExampleVirt; /* Inherit constructors */ int run(int value) override { /* Generate wrapping code that enables native function overloading */ PYBIND11_OVERRIDE(int, /* Return type */ ExampleVirt, /* Parent class */ run, /* Name of function */ value /* Argument(s) */ ); } bool run_bool() override { PYBIND11_OVERRIDE_PURE(bool, /* Return type */ ExampleVirt, /* Parent class */ run_bool, /* Name of function */ /* This function has no arguments. The trailing comma in the previous line is needed for some compilers */ ); } void pure_virtual() override { PYBIND11_OVERRIDE_PURE(void, /* Return type */ ExampleVirt, /* Parent class */ pure_virtual, /* Name of function */ /* This function has no arguments. The trailing comma in the previous line is needed for some compilers */ ); } // We can return reference types for compatibility with C++ virtual interfaces that do so, but // note they have some significant limitations (see the documentation). const std::string &get_string1() override { PYBIND11_OVERRIDE(const std::string &, /* Return type */ ExampleVirt, /* Parent class */ get_string1, /* Name of function */ /* (no arguments) */ ); } const std::string *get_string2() override { PYBIND11_OVERRIDE(const std::string *, /* Return type */ ExampleVirt, /* Parent class */ get_string2, /* Name of function */ /* (no arguments) */ ); } }; class NonCopyable { public: NonCopyable(int a, int b) : value{new int(a * b)} { print_created(this, a, b); } NonCopyable(NonCopyable &&o) noexcept : value{std::move(o.value)} { print_move_created(this); } NonCopyable(const NonCopyable &) = delete; NonCopyable() = delete; void operator=(const NonCopyable &) = delete; void operator=(NonCopyable &&) = delete; std::string get_value() const { if (value) { return std::to_string(*value); } return "(null)"; } ~NonCopyable() { print_destroyed(this); } private: std::unique_ptr value; }; // This is like the above, but is both copy and movable. In effect this means it should get moved // when it is not referenced elsewhere, but copied if it is still referenced. class Movable { public: Movable(int a, int b) : value{a + b} { print_created(this, a, b); } Movable(const Movable &m) : value{m.value} { print_copy_created(this); } Movable(Movable &&m) noexcept : value{m.value} { print_move_created(this); } std::string get_value() const { return std::to_string(value); } ~Movable() { print_destroyed(this); } private: int value; }; class NCVirt { public: virtual ~NCVirt() = default; NCVirt() = default; NCVirt(const NCVirt &) = delete; virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); } virtual Movable get_movable(int a, int b) = 0; std::string print_nc(int a, int b) { return get_noncopyable(a, b).get_value(); } std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); } }; class NCVirtTrampoline : public NCVirt { #if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__) NonCopyable get_noncopyable(int a, int b) override { PYBIND11_OVERRIDE(NonCopyable, NCVirt, get_noncopyable, a, b); } #endif Movable get_movable(int a, int b) override { PYBIND11_OVERRIDE_PURE(Movable, NCVirt, get_movable, a, b); } }; struct Base { virtual std::string dispatch() const = 0; virtual ~Base() = default; Base() = default; Base(const Base &) = delete; }; struct DispatchIssue : Base { std::string dispatch() const override { PYBIND11_OVERRIDE_PURE(std::string, Base, dispatch, /* no arguments */); } }; // An abstract adder class that uses visitor pattern to add two data // objects and send the result to the visitor functor struct AdderBase { struct Data {}; using DataVisitor = std::function; virtual void operator()(const Data &first, const Data &second, const DataVisitor &visitor) const = 0; virtual ~AdderBase() = default; AdderBase() = default; AdderBase(const AdderBase &) = delete; }; struct Adder : AdderBase { void operator()(const Data &first, const Data &second, const DataVisitor &visitor) const override { PYBIND11_OVERRIDE_PURE_NAME( void, AdderBase, "__call__", operator(), first, second, visitor); } }; static void test_gil() { { py::gil_scoped_acquire lock; py::print("1st lock acquired"); } { py::gil_scoped_acquire lock; py::print("2nd lock acquired"); } } static void test_gil_from_thread() { py::gil_scoped_release release; std::thread t(test_gil); t.join(); } class test_override_cache_helper { public: virtual int func() { return 0; } test_override_cache_helper() = default; virtual ~test_override_cache_helper() = default; // Non-copyable test_override_cache_helper &operator=(test_override_cache_helper const &Right) = delete; test_override_cache_helper(test_override_cache_helper const &Copy) = delete; }; class test_override_cache_helper_trampoline : public test_override_cache_helper { int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); } }; inline int test_override_cache(std::shared_ptr const &instance) { return instance->func(); } // Forward declaration (so that we can put the main tests here; the inherited virtual approaches // are rather long). void initialize_inherited_virtuals(py::module_ &m); TEST_SUBMODULE(virtual_functions, m) { // test_override py::class_(m, "ExampleVirt") .def(py::init()) /* Reference original class in function definitions */ .def("run", &ExampleVirt::run) .def("run_bool", &ExampleVirt::run_bool) .def("pure_virtual", &ExampleVirt::pure_virtual); py::class_(m, "NonCopyable").def(py::init()); py::class_(m, "Movable").def(py::init()); // test_move_support #if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__) py::class_(m, "NCVirt") .def(py::init<>()) .def("get_noncopyable", &NCVirt::get_noncopyable) .def("get_movable", &NCVirt::get_movable) .def("print_nc", &NCVirt::print_nc) .def("print_movable", &NCVirt::print_movable); #endif m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); }); m.def("runExampleVirtBool", [](ExampleVirt *ex) { return ex->run_bool(); }); m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); }); m.def("cstats_debug", &ConstructorStats::get); initialize_inherited_virtuals(m); // test_alias_delay_initialization1 // don't invoke Python dispatch classes by default when instantiating C++ classes // that were not extended on the Python side struct A { A() = default; A(const A &) = delete; virtual ~A() = default; virtual void f() { py::print("A.f()"); } }; struct PyA : A { PyA() { py::print("PyA.PyA()"); } PyA(const PyA &) = delete; ~PyA() override { py::print("PyA.~PyA()"); } void f() override { py::print("PyA.f()"); // This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to // protect a type containing a , PYBIND11_OVERRIDE(PYBIND11_TYPE(typename std::enable_if::type), A, f); } }; py::class_(m, "A").def(py::init<>()).def("f", &A::f); m.def("call_f", [](A *a) { a->f(); }); // test_alias_delay_initialization2 // ... unless we explicitly request it, as in this example: struct A2 { A2() = default; A2(const A2 &) = delete; virtual ~A2() = default; virtual void f() { py::print("A2.f()"); } }; struct PyA2 : A2 { PyA2() { py::print("PyA2.PyA2()"); } PyA2(const PyA2 &) = delete; ~PyA2() override { py::print("PyA2.~PyA2()"); } void f() override { py::print("PyA2.f()"); PYBIND11_OVERRIDE(void, A2, f); } }; py::class_(m, "A2") .def(py::init_alias<>()) .def(py::init([](int) { return new PyA2(); })) .def("f", &A2::f); m.def("call_f", [](A2 *a2) { a2->f(); }); // test_dispatch_issue // #159: virtual function dispatch has problems with similar-named functions py::class_(m, "DispatchIssue") .def(py::init<>()) .def("dispatch", &Base::dispatch); m.def("dispatch_issue_go", [](const Base *b) { return b->dispatch(); }); // test_recursive_dispatch_issue // #3357: Recursive dispatch fails to find python function override pybind11::class_(m, "Adder") .def(pybind11::init<>()) .def("__call__", &AdderBase::operator()); pybind11::class_(m, "Data").def(pybind11::init<>()); m.def("add2", [](const AdderBase::Data &first, const AdderBase::Data &second, const AdderBase &adder, const AdderBase::DataVisitor &visitor) { adder(first, second, visitor); }); m.def("add3", [](const AdderBase::Data &first, const AdderBase::Data &second, const AdderBase::Data &third, const AdderBase &adder, const AdderBase::DataVisitor &visitor) { adder(first, second, [&](const AdderBase::Data &first_plus_second) { // NOLINTNEXTLINE(readability-suspicious-call-argument) adder(first_plus_second, third, visitor); }); }); // test_override_ref // #392/397: overriding reference-returning functions class OverrideTest { public: struct A { std::string value = "hi"; }; std::string v; A a; explicit OverrideTest(const std::string &v) : v{v} {} OverrideTest() = default; OverrideTest(const OverrideTest &) = delete; virtual std::string str_value() { return v; } virtual std::string &str_ref() { return v; } virtual A A_value() { return a; } virtual A &A_ref() { return a; } virtual ~OverrideTest() = default; }; class PyOverrideTest : public OverrideTest { public: using OverrideTest::OverrideTest; std::string str_value() override { PYBIND11_OVERRIDE(std::string, OverrideTest, str_value); } // Not allowed (enabling the below should hit a static_assert failure): we can't get a // reference to a python numeric value, since we only copy values in the numeric type // caster: #ifdef PYBIND11_NEVER_DEFINED_EVER std::string &str_ref() override { PYBIND11_OVERRIDE(std::string &, OverrideTest, str_ref); } #endif // But we can work around it like this: private: std::string _tmp; std::string str_ref_helper() { PYBIND11_OVERRIDE(std::string, OverrideTest, str_ref); } public: std::string &str_ref() override { return _tmp = str_ref_helper(); } A A_value() override { PYBIND11_OVERRIDE(A, OverrideTest, A_value); } A &A_ref() override { PYBIND11_OVERRIDE(A &, OverrideTest, A_ref); } }; py::class_(m, "OverrideTest_A") .def_readwrite("value", &OverrideTest::A::value); py::class_(m, "OverrideTest") .def(py::init()) .def("str_value", &OverrideTest::str_value) #ifdef PYBIND11_NEVER_DEFINED_EVER .def("str_ref", &OverrideTest::str_ref) #endif .def("A_value", &OverrideTest::A_value) .def("A_ref", &OverrideTest::A_ref); py::class_>(m, "test_override_cache_helper") .def(py::init_alias<>()) .def("func", &test_override_cache_helper::func); m.def("test_override_cache", test_override_cache); } // Inheriting virtual methods. We do two versions here: the repeat-everything version and the // templated trampoline versions mentioned in docs/advanced.rst. // // These base classes are exactly the same, but we technically need distinct // classes for this example code because we need to be able to bind them // properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to // multiple python classes). class A_Repeat { #define A_METHODS \ public: \ virtual int unlucky_number() = 0; \ virtual std::string say_something(unsigned times) { \ std::string s = ""; \ for (unsigned i = 0; i < times; ++i) \ s += "hi"; \ return s; \ } \ std::string say_everything() { \ return say_something(1) + " " + std::to_string(unlucky_number()); \ } A_METHODS A_Repeat() = default; A_Repeat(const A_Repeat &) = delete; virtual ~A_Repeat() = default; }; class B_Repeat : public A_Repeat { #define B_METHODS \ public: \ int unlucky_number() override { return 13; } \ std::string say_something(unsigned times) override { \ return "B says hi " + std::to_string(times) + " times"; \ } \ virtual double lucky_number() { return 7.0; } B_METHODS }; class C_Repeat : public B_Repeat { #define C_METHODS \ public: \ int unlucky_number() override { return 4444; } \ double lucky_number() override { return 888; } C_METHODS }; class D_Repeat : public C_Repeat { #define D_METHODS // Nothing overridden. D_METHODS }; // Base classes for templated inheritance trampolines. Identical to the repeat-everything version: class A_Tpl { A_METHODS; A_Tpl() = default; A_Tpl(const A_Tpl &) = delete; virtual ~A_Tpl() = default; }; class B_Tpl : public A_Tpl { B_METHODS }; class C_Tpl : public B_Tpl { C_METHODS }; class D_Tpl : public C_Tpl { D_METHODS }; // Inheritance approach 1: each trampoline gets every virtual method (11 in total) class PyA_Repeat : public A_Repeat { public: using A_Repeat::A_Repeat; int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, A_Repeat, unlucky_number, ); } std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, A_Repeat, say_something, times); } }; class PyB_Repeat : public B_Repeat { public: using B_Repeat::B_Repeat; int unlucky_number() override { PYBIND11_OVERRIDE(int, B_Repeat, unlucky_number, ); } std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, B_Repeat, say_something, times); } double lucky_number() override { PYBIND11_OVERRIDE(double, B_Repeat, lucky_number, ); } }; class PyC_Repeat : public C_Repeat { public: using C_Repeat::C_Repeat; int unlucky_number() override { PYBIND11_OVERRIDE(int, C_Repeat, unlucky_number, ); } std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, C_Repeat, say_something, times); } double lucky_number() override { PYBIND11_OVERRIDE(double, C_Repeat, lucky_number, ); } }; class PyD_Repeat : public D_Repeat { public: using D_Repeat::D_Repeat; int unlucky_number() override { PYBIND11_OVERRIDE(int, D_Repeat, unlucky_number, ); } std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, D_Repeat, say_something, times); } double lucky_number() override { PYBIND11_OVERRIDE(double, D_Repeat, lucky_number, ); } }; // Inheritance approach 2: templated trampoline classes. // // Advantages: // - we have only 2 (template) class and 4 method declarations (one per virtual method, plus one // for any override of a pure virtual method), versus 4 classes and 6 methods (MI) or 4 classes // and 11 methods (repeat). // - Compared to MI, we also don't have to change the non-trampoline inheritance to virtual, and // can properly inherit constructors. // // Disadvantage: // - the compiler must still generate and compile 14 different methods (more, even, than the 11 // required for the repeat approach) instead of the 6 required for MI. (If there was no pure // method (or no pure method override), the number would drop down to the same 11 as the repeat // approach). template class PyA_Tpl : public Base { public: using Base::Base; // Inherit constructors int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, Base, unlucky_number, ); } std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, Base, say_something, times); } }; template class PyB_Tpl : public PyA_Tpl { public: using PyA_Tpl::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors) // NOLINTNEXTLINE(bugprone-parent-virtual-call) int unlucky_number() override { PYBIND11_OVERRIDE(int, Base, unlucky_number, ); } double lucky_number() override { PYBIND11_OVERRIDE(double, Base, lucky_number, ); } }; // Since C_Tpl and D_Tpl don't declare any new virtual methods, we don't actually need these // (we can use PyB_Tpl and PyB_Tpl for the trampoline classes instead): /* template class PyC_Tpl : public PyB_Tpl { public: using PyB_Tpl::PyB_Tpl; }; template class PyD_Tpl : public PyC_Tpl { public: using PyC_Tpl::PyC_Tpl; }; */ void initialize_inherited_virtuals(py::module_ &m) { // test_inherited_virtuals // Method 1: repeat py::class_(m, "A_Repeat") .def(py::init<>()) .def("unlucky_number", &A_Repeat::unlucky_number) .def("say_something", &A_Repeat::say_something) .def("say_everything", &A_Repeat::say_everything); py::class_(m, "B_Repeat") .def(py::init<>()) .def("lucky_number", &B_Repeat::lucky_number); py::class_(m, "C_Repeat").def(py::init<>()); py::class_(m, "D_Repeat").def(py::init<>()); // test_ // Method 2: Templated trampolines py::class_>(m, "A_Tpl") .def(py::init<>()) .def("unlucky_number", &A_Tpl::unlucky_number) .def("say_something", &A_Tpl::say_something) .def("say_everything", &A_Tpl::say_everything); py::class_>(m, "B_Tpl") .def(py::init<>()) .def("lucky_number", &B_Tpl::lucky_number); py::class_>(m, "C_Tpl").def(py::init<>()); py::class_>(m, "D_Tpl").def(py::init<>()); // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) m.def("test_gil", &test_gil); m.def("test_gil_from_thread", &test_gil_from_thread); }; aoflagger-v3.4.0/external/pybind11/tests/conftest.py0000644000175000017500000001277114507760431021152 0ustar olesoles"""pytest configuration Extends output capture as needed by pybind11: ignore constructors, optional unordered lines. Adds docstring and exceptions message sanitizers. """ import contextlib import difflib import gc import multiprocessing import os import re import textwrap import traceback import pytest # Early diagnostic for failed imports try: import pybind11_tests except Exception: # pytest does not show the traceback without this. traceback.print_exc() raise @pytest.fixture(scope="session", autouse=True) def always_forkserver_on_unix(): if os.name == "nt": return # Full background: https://github.com/pybind/pybind11/issues/4105#issuecomment-1301004592 # In a nutshell: fork() after starting threads == flakiness in the form of deadlocks. # It is actually a well-known pitfall, unfortunately without guard rails. # "forkserver" is more performant than "spawn" (~9s vs ~13s for tests/test_gil_scoped.py, # visit the issuecomment link above for details). # Windows does not have fork() and the associated pitfall, therefore it is best left # running with defaults. multiprocessing.set_start_method("forkserver") _long_marker = re.compile(r"([0-9])L") _hexadecimal = re.compile(r"0x[0-9a-fA-F]+") # Avoid collecting Python3 only files collect_ignore = [] def _strip_and_dedent(s): """For triple-quote strings""" return textwrap.dedent(s.lstrip("\n").rstrip()) def _split_and_sort(s): """For output which does not require specific line order""" return sorted(_strip_and_dedent(s).splitlines()) def _make_explanation(a, b): """Explanation for a failed assert -- the a and b arguments are List[str]""" return ["--- actual / +++ expected"] + [ line.strip("\n") for line in difflib.ndiff(a, b) ] class Output: """Basic output post-processing and comparison""" def __init__(self, string): self.string = string self.explanation = [] def __str__(self): return self.string def __eq__(self, other): # Ignore constructor/destructor output which is prefixed with "###" a = [ line for line in self.string.strip().splitlines() if not line.startswith("###") ] b = _strip_and_dedent(other).splitlines() if a == b: return True self.explanation = _make_explanation(a, b) return False class Unordered(Output): """Custom comparison for output without strict line ordering""" def __eq__(self, other): a = _split_and_sort(self.string) b = _split_and_sort(other) if a == b: return True self.explanation = _make_explanation(a, b) return False class Capture: def __init__(self, capfd): self.capfd = capfd self.out = "" self.err = "" def __enter__(self): self.capfd.readouterr() return self def __exit__(self, *args): self.out, self.err = self.capfd.readouterr() def __eq__(self, other): a = Output(self.out) b = other if a == b: return True self.explanation = a.explanation return False def __str__(self): return self.out def __contains__(self, item): return item in self.out @property def unordered(self): return Unordered(self.out) @property def stderr(self): return Output(self.err) @pytest.fixture() def capture(capsys): """Extended `capsys` with context manager and custom equality operators""" return Capture(capsys) class SanitizedString: def __init__(self, sanitizer): self.sanitizer = sanitizer self.string = "" self.explanation = [] def __call__(self, thing): self.string = self.sanitizer(thing) return self def __eq__(self, other): a = self.string b = _strip_and_dedent(other) if a == b: return True self.explanation = _make_explanation(a.splitlines(), b.splitlines()) return False def _sanitize_general(s): s = s.strip() s = s.replace("pybind11_tests.", "m.") return _long_marker.sub(r"\1", s) def _sanitize_docstring(thing): s = thing.__doc__ return _sanitize_general(s) @pytest.fixture() def doc(): """Sanitize docstrings and add custom failure explanation""" return SanitizedString(_sanitize_docstring) def _sanitize_message(thing): s = str(thing) s = _sanitize_general(s) return _hexadecimal.sub("0", s) @pytest.fixture() def msg(): """Sanitize messages and add custom failure explanation""" return SanitizedString(_sanitize_message) def pytest_assertrepr_compare(op, left, right): # noqa: ARG001 """Hook to insert custom failure explanation""" if hasattr(left, "explanation"): return left.explanation return None def gc_collect(): """Run the garbage collector twice (needed when running reference counting tests with PyPy)""" gc.collect() gc.collect() def pytest_configure(): pytest.suppress = contextlib.suppress pytest.gc_collect = gc_collect def pytest_report_header(config): del config # Unused. assert ( pybind11_tests.compiler_info is not None ), "Please update pybind11_tests.cpp if this assert fails." return ( "C++ Info:" f" {pybind11_tests.compiler_info}" f" {pybind11_tests.cpp_std}" f" {pybind11_tests.PYBIND11_INTERNALS_ID}" f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}" ) aoflagger-v3.4.0/external/pybind11/tests/cross_module_gil_utils.cpp0000644000175000017500000000677214507760431024234 0ustar olesoles/* tests/cross_module_gil_utils.cpp -- tools for acquiring GIL from a different module Copyright (c) 2019 Google LLC All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #if defined(PYBIND11_INTERNALS_VERSION) # undef PYBIND11_INTERNALS_VERSION #endif #define PYBIND11_INTERNALS_VERSION 21814642 // Ensure this module has its own `internals` instance. #include #include #include #include // This file mimics a DSO that makes pybind11 calls but does not define a // PYBIND11_MODULE. The purpose is to test that such a DSO can create a // py::gil_scoped_acquire when the running thread is in a GIL-released state. // // Note that we define a Python module here for convenience, but in general // this need not be the case. The typical scenario would be a DSO that implements // shared logic used internally by multiple pybind11 modules. namespace { namespace py = pybind11; void gil_acquire() { py::gil_scoped_acquire gil; } std::string gil_multi_acquire_release(unsigned bits) { if ((bits & 0x1u) != 0u) { py::gil_scoped_acquire gil; } if ((bits & 0x2u) != 0u) { py::gil_scoped_release gil; } if ((bits & 0x4u) != 0u) { py::gil_scoped_acquire gil; } if ((bits & 0x8u) != 0u) { py::gil_scoped_release gil; } return PYBIND11_INTERNALS_ID; } struct CustomAutoGIL { CustomAutoGIL() : gstate(PyGILState_Ensure()) {} ~CustomAutoGIL() { PyGILState_Release(gstate); } PyGILState_STATE gstate; }; struct CustomAutoNoGIL { CustomAutoNoGIL() : save(PyEval_SaveThread()) {} ~CustomAutoNoGIL() { PyEval_RestoreThread(save); } PyThreadState *save; }; template void gil_acquire_inner() { Acquire acquire_outer; Acquire acquire_inner; Release release; } template void gil_acquire_nested() { Acquire acquire_outer; Acquire acquire_inner; Release release; auto thread = std::thread(&gil_acquire_inner); thread.join(); } constexpr char kModuleName[] = "cross_module_gil_utils"; struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr}; } // namespace #define ADD_FUNCTION(Name, ...) \ PyModule_AddObject(m, Name, PyLong_FromVoidPtr(reinterpret_cast(&__VA_ARGS__))); extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() { PyObject *m = PyModule_Create(&moduledef); if (m != nullptr) { static_assert(sizeof(&gil_acquire) == sizeof(void *), "Function pointer must have the same size as void*"); ADD_FUNCTION("gil_acquire_funcaddr", gil_acquire) ADD_FUNCTION("gil_multi_acquire_release_funcaddr", gil_multi_acquire_release) ADD_FUNCTION("gil_acquire_inner_custom_funcaddr", gil_acquire_inner) ADD_FUNCTION("gil_acquire_nested_custom_funcaddr", gil_acquire_nested) ADD_FUNCTION("gil_acquire_inner_pybind11_funcaddr", gil_acquire_inner) ADD_FUNCTION("gil_acquire_nested_pybind11_funcaddr", gil_acquire_nested) } return m; } aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/0000755000175000017500000000000014516225226022237 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/embed.cpp0000644000175000017500000000124114507760431024017 0ustar olesoles#include namespace py = pybind11; PYBIND11_EMBEDDED_MODULE(test_cmake_build, m) { m.def("add", [](int i, int j) { return i + j; }); } int main(int argc, char *argv[]) { if (argc != 2) { throw std::runtime_error("Expected test.py file as the first argument"); } auto *test_py_file = argv[1]; py::scoped_interpreter guard{}; auto m = py::module_::import("test_cmake_build"); if (m.attr("add")(1, 2).cast() != 3) { throw std::runtime_error("embed.cpp failed"); } py::module_::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp"); py::eval_file(test_py_file, py::globals()); } aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/subdirectory_function/0000755000175000017500000000000014516225226026662 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt0000644000175000017500000000221314507760431031422 0ustar olesolescmake_minimum_required(VERSION 3.4) # The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.18) endif() project(test_subdirectory_function CXX) add_subdirectory("${pybind11_SOURCE_DIR}" pybind11) pybind11_add_module(test_subdirectory_function ../main.cpp) set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build) if(DEFINED Python_EXECUTABLE) set(_Python_EXECUTABLE "${Python_EXECUTABLE}") elseif(DEFINED PYTHON_EXECUTABLE) set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") else() message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") endif() add_custom_target( check_subdirectory_function ${CMAKE_COMMAND} -E env PYTHONPATH=$ ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME} DEPENDS test_subdirectory_function) aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/installed_embed/0000755000175000017500000000000014516225226025352 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt0000644000175000017500000000222314507760431030113 0ustar olesolescmake_minimum_required(VERSION 3.4) # The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.18) endif() project(test_installed_embed CXX) find_package(pybind11 CONFIG REQUIRED) message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") add_executable(test_installed_embed ../embed.cpp) target_link_libraries(test_installed_embed PRIVATE pybind11::embed) set_target_properties(test_installed_embed PROPERTIES OUTPUT_NAME test_cmake_build) # Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed). # This may be needed to resolve header conflicts, e.g. between Python release and debug headers. set_target_properties(test_installed_embed PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) add_custom_target( check_installed_embed $ ${PROJECT_SOURCE_DIR}/../test.py DEPENDS test_installed_embed) aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/installed_target/0000755000175000017500000000000014516225226025564 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt0000644000175000017500000000322514507760431030330 0ustar olesolescmake_minimum_required(VERSION 3.4) # The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.18) endif() project(test_installed_target CXX) find_package(pybind11 CONFIG REQUIRED) message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") add_library(test_installed_target MODULE ../main.cpp) target_link_libraries(test_installed_target PRIVATE pybind11::module) set_target_properties(test_installed_target PROPERTIES OUTPUT_NAME test_cmake_build) # Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib pybind11_extension(test_installed_target) # Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module). # This may be needed to resolve header conflicts, e.g. between Python release and debug headers. set_target_properties(test_installed_target PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) if(DEFINED Python_EXECUTABLE) set(_Python_EXECUTABLE "${Python_EXECUTABLE}") elseif(DEFINED PYTHON_EXECUTABLE) set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") else() message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") endif() add_custom_target( check_installed_target ${CMAKE_COMMAND} -E env PYTHONPATH=$ ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME} DEPENDS test_installed_target) aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/subdirectory_embed/0000755000175000017500000000000014516225226026111 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt0000644000175000017500000000251114507760431030652 0ustar olesolescmake_minimum_required(VERSION 3.4) # The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.18) endif() project(test_subdirectory_embed CXX) set(PYBIND11_INSTALL ON CACHE BOOL "") set(PYBIND11_EXPORT_NAME test_export) add_subdirectory("${pybind11_SOURCE_DIR}" pybind11) # Test basic target functionality add_executable(test_subdirectory_embed ../embed.cpp) target_link_libraries(test_subdirectory_embed PRIVATE pybind11::embed) set_target_properties(test_subdirectory_embed PROPERTIES OUTPUT_NAME test_cmake_build) add_custom_target( check_subdirectory_embed $ "${PROJECT_SOURCE_DIR}/../test.py" DEPENDS test_subdirectory_embed) # Test custom export group -- PYBIND11_EXPORT_NAME add_library(test_embed_lib ../embed.cpp) target_link_libraries(test_embed_lib PRIVATE pybind11::embed) install( TARGETS test_embed_lib EXPORT test_export ARCHIVE DESTINATION bin LIBRARY DESTINATION lib RUNTIME DESTINATION lib) install(EXPORT test_export DESTINATION lib/cmake/test_export/test_export-Targets.cmake) aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/test.py0000644000175000017500000000030614507760431023571 0ustar olesolesimport sys import test_cmake_build assert isinstance(__file__, str) # Test this is properly set assert test_cmake_build.add(1, 2) == 3 print(f"{sys.argv[1]} imports, runs, and adds: 1 + 2 = 3") aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/CMakeLists.txt0000644000175000017500000000511714507760431025005 0ustar olesoles# Built-in in CMake 3.5+ include(CMakeParseArguments) add_custom_target(test_cmake_build) function(pybind11_add_build_test name) cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN}) set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") if(PYBIND11_FINDPYTHON) list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}") if(DEFINED Python_ROOT_DIR) list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}") endif() list(APPEND build_options "-DPython_EXECUTABLE=${Python_EXECUTABLE}") else() list(APPEND build_options "-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}") endif() if(DEFINED CMAKE_CXX_STANDARD) list(APPEND build_options "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") endif() if(NOT ARG_INSTALL) list(APPEND build_options "-Dpybind11_SOURCE_DIR=${pybind11_SOURCE_DIR}") else() list(APPEND build_options "-DCMAKE_PREFIX_PATH=${pybind11_BINARY_DIR}/mock_install") endif() add_custom_target( test_build_${name} ${CMAKE_CTEST_COMMAND} --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/${name}" "${CMAKE_CURRENT_BINARY_DIR}/${name}" --build-config Release --build-noclean --build-generator ${CMAKE_GENERATOR} $<$:--build-generator-platform> ${CMAKE_GENERATOR_PLATFORM} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-target check_${name} --build-options ${build_options}) if(ARG_INSTALL) add_dependencies(test_build_${name} mock_install) endif() add_dependencies(test_cmake_build test_build_${name}) endfunction() possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID) pybind11_add_build_test(subdirectory_function) pybind11_add_build_test(subdirectory_target) if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy") message(STATUS "Skipping embed test on PyPy") else() pybind11_add_build_test(subdirectory_embed) endif() if(PYBIND11_INSTALL) add_custom_target( mock_install ${CMAKE_COMMAND} "-DCMAKE_INSTALL_PREFIX=${pybind11_BINARY_DIR}/mock_install" -P "${pybind11_BINARY_DIR}/cmake_install.cmake") pybind11_add_build_test(installed_function INSTALL) pybind11_add_build_test(installed_target INSTALL) if(NOT ("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" )) pybind11_add_build_test(installed_embed INSTALL) endif() endif() add_dependencies(check test_cmake_build) add_subdirectory(subdirectory_target EXCLUDE_FROM_ALL) add_subdirectory(subdirectory_embed EXCLUDE_FROM_ALL) aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/subdirectory_target/0000755000175000017500000000000014516225226026323 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt0000644000175000017500000000253014507760431031065 0ustar olesolescmake_minimum_required(VERSION 3.4) # The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.18) endif() project(test_subdirectory_target CXX) add_subdirectory("${pybind11_SOURCE_DIR}" pybind11) add_library(test_subdirectory_target MODULE ../main.cpp) set_target_properties(test_subdirectory_target PROPERTIES OUTPUT_NAME test_cmake_build) target_link_libraries(test_subdirectory_target PRIVATE pybind11::module) # Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib pybind11_extension(test_subdirectory_target) if(DEFINED Python_EXECUTABLE) set(_Python_EXECUTABLE "${Python_EXECUTABLE}") elseif(DEFINED PYTHON_EXECUTABLE) set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") else() message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") endif() add_custom_target( check_subdirectory_target ${CMAKE_COMMAND} -E env PYTHONPATH=$ ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME} DEPENDS test_subdirectory_target) aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/installed_function/0000755000175000017500000000000014516225226026123 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt0000644000175000017500000000241514507760431030667 0ustar olesolescmake_minimum_required(VERSION 3.4) project(test_installed_module CXX) # The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.18) endif() project(test_installed_function CXX) find_package(pybind11 CONFIG REQUIRED) message( STATUS "Found pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}: ${pybind11_INCLUDE_DIRS}") pybind11_add_module(test_installed_function SHARED NO_EXTRAS ../main.cpp) set_target_properties(test_installed_function PROPERTIES OUTPUT_NAME test_cmake_build) if(DEFINED Python_EXECUTABLE) set(_Python_EXECUTABLE "${Python_EXECUTABLE}") elseif(DEFINED PYTHON_EXECUTABLE) set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") else() message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") endif() add_custom_target( check_installed_function ${CMAKE_COMMAND} -E env PYTHONPATH=$ ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME} DEPENDS test_installed_function) aoflagger-v3.4.0/external/pybind11/tests/test_cmake_build/main.cpp0000644000175000017500000000023014507760431023664 0ustar olesoles#include namespace py = pybind11; PYBIND11_MODULE(test_cmake_build, m) { m.def("add", [](int i, int j) { return i + j; }); } aoflagger-v3.4.0/external/pybind11/tests/extra_setuptools/0000755000175000017500000000000014516225226022365 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/extra_setuptools/test_setuphelper.py0000644000175000017500000001007114507760431026337 0ustar olesolesimport os import subprocess import sys from textwrap import dedent import pytest DIR = os.path.abspath(os.path.dirname(__file__)) MAIN_DIR = os.path.dirname(os.path.dirname(DIR)) WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin") @pytest.mark.parametrize("parallel", [False, True]) @pytest.mark.parametrize("std", [11, 0]) def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): monkeypatch.chdir(tmpdir) monkeypatch.syspath_prepend(MAIN_DIR) (tmpdir / "setup.py").write_text( dedent( f"""\ import sys sys.path.append({MAIN_DIR!r}) from setuptools import setup, Extension from pybind11.setup_helpers import build_ext, Pybind11Extension std = {std} ext_modules = [ Pybind11Extension( "simple_setup", sorted(["main.cpp"]), cxx_std=std, ), ] cmdclass = dict() if std == 0: cmdclass["build_ext"] = build_ext parallel = {parallel} if parallel: from pybind11.setup_helpers import ParallelCompile ParallelCompile().install() setup( name="simple_setup_package", cmdclass=cmdclass, ext_modules=ext_modules, ) """ ), encoding="ascii", ) (tmpdir / "main.cpp").write_text( dedent( """\ #include int f(int x) { return x * 3; } PYBIND11_MODULE(simple_setup, m) { m.def("f", &f); } """ ), encoding="ascii", ) out = subprocess.check_output( [sys.executable, "setup.py", "build_ext", "--inplace"], ) if not WIN: assert b"-g0" in out out = subprocess.check_output( [sys.executable, "setup.py", "build_ext", "--inplace", "--force"], env=dict(os.environ, CFLAGS="-g"), ) if not WIN: assert b"-g0" not in out # Debug helper printout, normally hidden print(out) for item in tmpdir.listdir(): print(item.basename) assert ( len([f for f in tmpdir.listdir() if f.basename.startswith("simple_setup")]) == 1 ) assert len(list(tmpdir.listdir())) == 4 # two files + output + build_dir (tmpdir / "test.py").write_text( dedent( """\ import simple_setup assert simple_setup.f(3) == 9 """ ), encoding="ascii", ) subprocess.check_call( [sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr ) def test_intree_extensions(monkeypatch, tmpdir): monkeypatch.syspath_prepend(MAIN_DIR) from pybind11.setup_helpers import intree_extensions monkeypatch.chdir(tmpdir) root = tmpdir root.ensure_dir() subdir = root / "dir" subdir.ensure_dir() src = subdir / "ext.cpp" src.ensure() relpath = src.relto(tmpdir) (ext,) = intree_extensions([relpath]) assert ext.name == "ext" subdir.ensure("__init__.py") (ext,) = intree_extensions([relpath]) assert ext.name == "dir.ext" def test_intree_extensions_package_dir(monkeypatch, tmpdir): monkeypatch.syspath_prepend(MAIN_DIR) from pybind11.setup_helpers import intree_extensions monkeypatch.chdir(tmpdir) root = tmpdir / "src" root.ensure_dir() subdir = root / "dir" subdir.ensure_dir() src = subdir / "ext.cpp" src.ensure() (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"}) assert ext.name == "dir.ext" (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"}) assert ext.name == "foo.dir.ext" subdir.ensure("__init__.py") (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"}) assert ext.name == "dir.ext" (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"}) assert ext.name == "foo.dir.ext" aoflagger-v3.4.0/external/pybind11/tests/extra_setuptools/pytest.ini0000644000175000017500000000000014507760431024406 0ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_pytypes.py0000644000175000017500000005611514507760431022101 0ustar olesolesimport contextlib import sys import types import pytest import env from pybind11_tests import detailed_error_messages_enabled from pybind11_tests import pytypes as m def test_obj_class_name(): assert m.obj_class_name(None) == "NoneType" assert m.obj_class_name(list) == "list" assert m.obj_class_name([]) == "list" def test_handle_from_move_only_type_with_operator_PyObject(): assert m.handle_from_move_only_type_with_operator_PyObject_ncnst() assert m.handle_from_move_only_type_with_operator_PyObject_const() def test_bool(doc): assert doc(m.get_bool) == "get_bool() -> bool" def test_int(doc): assert doc(m.get_int) == "get_int() -> int" def test_iterator(doc): assert doc(m.get_iterator) == "get_iterator() -> Iterator" @pytest.mark.parametrize( ("pytype", "from_iter_func"), [ (frozenset, m.get_frozenset_from_iterable), (list, m.get_list_from_iterable), (set, m.get_set_from_iterable), (tuple, m.get_tuple_from_iterable), ], ) def test_from_iterable(pytype, from_iter_func): my_iter = iter(range(10)) s = from_iter_func(my_iter) assert type(s) == pytype assert s == pytype(range(10)) def test_iterable(doc): assert doc(m.get_iterable) == "get_iterable() -> Iterable" def test_float(doc): assert doc(m.get_float) == "get_float() -> float" def test_list(capture, doc): assert m.list_no_args() == [] assert m.list_ssize_t() == [] assert m.list_size_t() == [] lins = [1, 2] m.list_insert_ssize_t(lins) assert lins == [1, 83, 2] m.list_insert_size_t(lins) assert lins == [1, 83, 2, 57] with capture: lst = m.get_list() assert lst == ["inserted-0", "overwritten", "inserted-2"] lst.append("value2") m.print_list(lst) assert ( capture.unordered == """ Entry at position 0: value list item 0: inserted-0 list item 1: overwritten list item 2: inserted-2 list item 3: value2 """ ) assert doc(m.get_list) == "get_list() -> list" assert doc(m.print_list) == "print_list(arg0: list) -> None" def test_none(doc): assert doc(m.get_none) == "get_none() -> None" assert doc(m.print_none) == "print_none(arg0: None) -> None" def test_set(capture, doc): s = m.get_set() assert isinstance(s, set) assert s == {"key1", "key2", "key3"} s.add("key4") with capture: m.print_anyset(s) assert ( capture.unordered == """ key: key1 key: key2 key: key3 key: key4 """ ) m.set_add(s, "key5") assert m.anyset_size(s) == 5 m.set_clear(s) assert m.anyset_empty(s) assert not m.anyset_contains(set(), 42) assert m.anyset_contains({42}, 42) assert m.anyset_contains({"foo"}, "foo") assert doc(m.get_set) == "get_set() -> set" assert doc(m.print_anyset) == "print_anyset(arg0: anyset) -> None" def test_frozenset(capture, doc): s = m.get_frozenset() assert isinstance(s, frozenset) assert s == frozenset({"key1", "key2", "key3"}) with capture: m.print_anyset(s) assert ( capture.unordered == """ key: key1 key: key2 key: key3 """ ) assert m.anyset_size(s) == 3 assert not m.anyset_empty(s) assert not m.anyset_contains(frozenset(), 42) assert m.anyset_contains(frozenset({42}), 42) assert m.anyset_contains(frozenset({"foo"}), "foo") assert doc(m.get_frozenset) == "get_frozenset() -> frozenset" def test_dict(capture, doc): d = m.get_dict() assert d == {"key": "value"} with capture: d["key2"] = "value2" m.print_dict(d) assert ( capture.unordered == """ key: key, value=value key: key2, value=value2 """ ) assert not m.dict_contains({}, 42) assert m.dict_contains({42: None}, 42) assert m.dict_contains({"foo": None}, "foo") assert doc(m.get_dict) == "get_dict() -> dict" assert doc(m.print_dict) == "print_dict(arg0: dict) -> None" assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3} class CustomContains: d = {"key": None} def __contains__(self, m): return m in self.d @pytest.mark.parametrize( ("arg", "func"), [ (set(), m.anyset_contains), ({}, m.dict_contains), (CustomContains(), m.obj_contains), ], ) @pytest.mark.xfail("env.PYPY and sys.pypy_version_info < (7, 3, 10)", strict=False) def test_unhashable_exceptions(arg, func): class Unhashable: __hash__ = None with pytest.raises(TypeError) as exc_info: func(arg, Unhashable()) assert "unhashable type:" in str(exc_info.value) def test_tuple(): assert m.tuple_no_args() == () assert m.tuple_ssize_t() == () assert m.tuple_size_t() == () assert m.get_tuple() == (42, None, "spam") def test_simple_namespace(): ns = m.get_simple_namespace() assert ns.attr == 42 assert ns.x == "foo" assert ns.right == 2 assert not hasattr(ns, "wrong") def test_str(doc): assert m.str_from_char_ssize_t().encode().decode() == "red" assert m.str_from_char_size_t().encode().decode() == "blue" assert m.str_from_string().encode().decode() == "baz" assert m.str_from_bytes().encode().decode() == "boo" assert doc(m.str_from_bytes) == "str_from_bytes() -> str" class A: def __str__(self): return "this is a str" def __repr__(self): return "this is a repr" assert m.str_from_object(A()) == "this is a str" assert m.repr_from_object(A()) == "this is a repr" assert m.str_from_handle(A()) == "this is a str" s1, s2 = m.str_format() assert s1 == "1 + 2 = 3" assert s1 == s2 malformed_utf8 = b"\x80" if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): assert m.str_from_object(malformed_utf8) is malformed_utf8 else: assert m.str_from_object(malformed_utf8) == "b'\\x80'" assert m.str_from_handle(malformed_utf8) == "b'\\x80'" assert m.str_from_string_from_str("this is a str") == "this is a str" ucs_surrogates_str = "\udcc3" with pytest.raises(UnicodeEncodeError): m.str_from_string_from_str(ucs_surrogates_str) @pytest.mark.parametrize( "func", [ m.str_from_bytes_input, m.str_from_cstr_input, m.str_from_std_string_input, ], ) def test_surrogate_pairs_unicode_error(func): input_str = "\ud83d\ude4f".encode("utf-8", "surrogatepass") with pytest.raises(UnicodeDecodeError): func(input_str) def test_bytes(doc): assert m.bytes_from_char_ssize_t().decode() == "green" assert m.bytes_from_char_size_t().decode() == "purple" assert m.bytes_from_string().decode() == "foo" assert m.bytes_from_str().decode() == "bar" assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes" def test_bytearray(): assert m.bytearray_from_char_ssize_t().decode() == "$%" assert m.bytearray_from_char_size_t().decode() == "@$!" assert m.bytearray_from_string().decode() == "foo" assert m.bytearray_size() == len("foo") def test_capsule(capture): pytest.gc_collect() with capture: a = m.return_capsule_with_destructor() del a pytest.gc_collect() assert ( capture.unordered == """ creating capsule destructing capsule """ ) with capture: a = m.return_renamed_capsule_with_destructor() del a pytest.gc_collect() assert ( capture.unordered == """ creating capsule renaming capsule destructing capsule """ ) with capture: a = m.return_capsule_with_destructor_2() del a pytest.gc_collect() assert ( capture.unordered == """ creating capsule destructing capsule: 1234 """ ) with capture: a = m.return_renamed_capsule_with_destructor_2() del a pytest.gc_collect() assert ( capture.unordered == """ creating capsule renaming capsule destructing capsule: 1234 """ ) with capture: a = m.return_capsule_with_name_and_destructor() del a pytest.gc_collect() assert ( capture.unordered == """ created capsule (1234, 'pointer type description') destructing capsule (1234, 'pointer type description') """ ) with capture: a = m.return_capsule_with_explicit_nullptr_dtor() del a pytest.gc_collect() assert ( capture.unordered == """ creating capsule with explicit nullptr dtor """ ) def test_accessors(): class SubTestObject: attr_obj = 1 attr_char = 2 class TestObject: basic_attr = 1 begin_end = [1, 2, 3] d = {"operator[object]": 1, "operator[char *]": 2} sub = SubTestObject() def func(self, x, *args): return self.basic_attr + x + sum(args) d = m.accessor_api(TestObject()) assert d["basic_attr"] == 1 assert d["begin_end"] == [1, 2, 3] assert d["operator[object]"] == 1 assert d["operator[char *]"] == 2 assert d["attr(object)"] == 1 assert d["attr(char *)"] == 2 assert d["missing_attr_ptr"] == "raised" assert d["missing_attr_chain"] == "raised" assert d["is_none"] is False assert d["operator()"] == 2 assert d["operator*"] == 7 assert d["implicit_list"] == [1, 2, 3] assert all(x in TestObject.__dict__ for x in d["implicit_dict"]) assert m.tuple_accessor(()) == (0, 1, 2) d = m.accessor_assignment() assert d["get"] == 0 assert d["deferred_get"] == 0 assert d["set"] == 1 assert d["deferred_set"] == 1 assert d["var"] == 99 def test_accessor_moves(): inc_refs = m.accessor_moves() if inc_refs: assert inc_refs == [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0] else: pytest.skip("Not defined: PYBIND11_HANDLE_REF_DEBUG") def test_constructors(): """C++ default and converting constructors are equivalent to type calls in Python""" types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set] expected = {t.__name__: t() for t in types} assert m.default_constructors() == expected data = { bytes: b"41", # Currently no supported or working conversions. bytearray: bytearray(b"41"), str: 42, bool: "Not empty", int: "42", float: "+1e3", tuple: range(3), list: range(3), dict: [("two", 2), ("one", 1), ("three", 3)], set: [4, 4, 5, 6, 6, 6], frozenset: [4, 4, 5, 6, 6, 6], memoryview: b"abc", } inputs = {k.__name__: v for k, v in data.items()} expected = {k.__name__: k(v) for k, v in data.items()} assert m.converting_constructors(inputs) == expected assert m.cast_functions(inputs) == expected # Converting constructors and cast functions should just reference rather # than copy when no conversion is needed: noconv1 = m.converting_constructors(expected) for k in noconv1: assert noconv1[k] is expected[k] noconv2 = m.cast_functions(expected) for k in noconv2: assert noconv2[k] is expected[k] def test_non_converting_constructors(): non_converting_test_cases = [ ("bytes", range(10)), ("none", 42), ("ellipsis", 42), ("type", 42), ] for t, v in non_converting_test_cases: for move in [True, False]: with pytest.raises(TypeError) as excinfo: m.nonconverting_constructor(t, v, move) expected_error = ( f"Object of type '{type(v).__name__}' is not an instance of '{t}'" ) assert str(excinfo.value) == expected_error def test_pybind11_str_raw_str(): # specifically to exercise pybind11::str::raw_str cvt = m.convert_to_pybind11_str assert cvt("Str") == "Str" assert cvt(b"Bytes") == "b'Bytes'" assert cvt(None) == "None" assert cvt(False) == "False" assert cvt(True) == "True" assert cvt(42) == "42" assert cvt(2**65) == "36893488147419103232" assert cvt(-1.50) == "-1.5" assert cvt(()) == "()" assert cvt((18,)) == "(18,)" assert cvt([]) == "[]" assert cvt([28]) == "[28]" assert cvt({}) == "{}" assert cvt({3: 4}) == "{3: 4}" assert cvt(set()) == "set()" assert cvt({3, 3}) == "{3}" valid_orig = "DZ" valid_utf8 = valid_orig.encode("utf-8") valid_cvt = cvt(valid_utf8) if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): assert valid_cvt is valid_utf8 else: assert type(valid_cvt) is str assert valid_cvt == "b'\\xc7\\xb1'" malformed_utf8 = b"\x80" if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): assert cvt(malformed_utf8) is malformed_utf8 else: malformed_cvt = cvt(malformed_utf8) assert type(malformed_cvt) is str assert malformed_cvt == "b'\\x80'" def test_implicit_casting(): """Tests implicit casting when assigning or appending to dicts and lists.""" z = m.get_implicit_casting() assert z["d"] == { "char*_i1": "abc", "char*_i2": "abc", "char*_e": "abc", "char*_p": "abc", "str_i1": "str", "str_i2": "str1", "str_e": "str2", "str_p": "str3", "int_i1": 42, "int_i2": 42, "int_e": 43, "int_p": 44, } assert z["l"] == [3, 6, 9, 12, 15] def test_print(capture): with capture: m.print_function() assert ( capture == """ Hello, World! 1 2.0 three True -- multiple args *args-and-a-custom-separator no new line here -- next print flush py::print + str.format = this """ ) assert capture.stderr == "this goes to stderr" with pytest.raises(RuntimeError) as excinfo: m.print_failure() assert str(excinfo.value) == "Unable to convert call argument " + ( "'1' of type 'UnregisteredType' to Python object" if detailed_error_messages_enabled else "'1' to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" ) def test_hash(): class Hashable: def __init__(self, value): self.value = value def __hash__(self): return self.value class Unhashable: __hash__ = None assert m.hash_function(Hashable(42)) == 42 with pytest.raises(TypeError): m.hash_function(Unhashable()) def test_number_protocol(): for a, b in [(1, 1), (3, 5)]: li = [ a == b, a != b, a < b, a <= b, a > b, a >= b, a + b, a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b, ] assert m.test_number_protocol(a, b) == li def test_list_slicing(): li = list(range(100)) assert li[::2] == m.test_list_slicing(li) def test_issue2361(): # See issue #2361 assert m.issue2361_str_implicit_copy_none() == "None" with pytest.raises(TypeError) as excinfo: assert m.issue2361_dict_implicit_copy_none() assert "NoneType" in str(excinfo.value) assert "iterable" in str(excinfo.value) @pytest.mark.parametrize( ("method", "args", "fmt", "expected_view"), [ (m.test_memoryview_object, (b"red",), "B", b"red"), (m.test_memoryview_buffer_info, (b"green",), "B", b"green"), (m.test_memoryview_from_buffer, (False,), "h", [3, 1, 4, 1, 5]), (m.test_memoryview_from_buffer, (True,), "H", [2, 7, 1, 8]), (m.test_memoryview_from_buffer_nativeformat, (), "@i", [4, 7, 5]), ], ) def test_memoryview(method, args, fmt, expected_view): view = method(*args) assert isinstance(view, memoryview) assert view.format == fmt assert list(view) == list(expected_view) @pytest.mark.xfail("env.PYPY", reason="getrefcount is not available") @pytest.mark.parametrize( "method", [ m.test_memoryview_object, m.test_memoryview_buffer_info, ], ) def test_memoryview_refcount(method): buf = b"\x0a\x0b\x0c\x0d" ref_before = sys.getrefcount(buf) view = method(buf) ref_after = sys.getrefcount(buf) assert ref_before < ref_after assert list(view) == list(buf) def test_memoryview_from_buffer_empty_shape(): view = m.test_memoryview_from_buffer_empty_shape() assert isinstance(view, memoryview) assert view.format == "B" assert bytes(view) == b"" def test_test_memoryview_from_buffer_invalid_strides(): with pytest.raises(RuntimeError): m.test_memoryview_from_buffer_invalid_strides() def test_test_memoryview_from_buffer_nullptr(): with pytest.raises(ValueError): m.test_memoryview_from_buffer_nullptr() def test_memoryview_from_memory(): view = m.test_memoryview_from_memory() assert isinstance(view, memoryview) assert view.format == "B" assert bytes(view) == b"\xff\xe1\xab\x37" def test_builtin_functions(): assert m.get_len(list(range(42))) == 42 with pytest.raises(TypeError) as exc_info: m.get_len(i for i in range(42)) assert str(exc_info.value) in [ "object of type 'generator' has no len()", "'generator' has no length", ] # PyPy def test_isinstance_string_types(): assert m.isinstance_pybind11_bytes(b"") assert not m.isinstance_pybind11_bytes("") assert m.isinstance_pybind11_str("") if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): assert m.isinstance_pybind11_str(b"") else: assert not m.isinstance_pybind11_str(b"") def test_pass_bytes_or_unicode_to_string_types(): assert m.pass_to_pybind11_bytes(b"Bytes") == 5 with pytest.raises(TypeError): m.pass_to_pybind11_bytes("Str") if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): assert m.pass_to_pybind11_str(b"Bytes") == 5 else: with pytest.raises(TypeError): m.pass_to_pybind11_str(b"Bytes") assert m.pass_to_pybind11_str("Str") == 3 assert m.pass_to_std_string(b"Bytes") == 5 assert m.pass_to_std_string("Str") == 3 malformed_utf8 = b"\x80" if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): assert m.pass_to_pybind11_str(malformed_utf8) == 1 else: with pytest.raises(TypeError): m.pass_to_pybind11_str(malformed_utf8) @pytest.mark.parametrize( ("create_weakref", "create_weakref_with_callback"), [ (m.weakref_from_handle, m.weakref_from_handle_and_function), (m.weakref_from_object, m.weakref_from_object_and_function), ], ) def test_weakref(create_weakref, create_weakref_with_callback): from weakref import getweakrefcount # Apparently, you cannot weakly reference an object() class WeaklyReferenced: pass callback_called = False def callback(_): nonlocal callback_called callback_called = True obj = WeaklyReferenced() assert getweakrefcount(obj) == 0 wr = create_weakref(obj) assert getweakrefcount(obj) == 1 obj = WeaklyReferenced() assert getweakrefcount(obj) == 0 wr = create_weakref_with_callback(obj, callback) # noqa: F841 assert getweakrefcount(obj) == 1 assert not callback_called del obj pytest.gc_collect() assert callback_called @pytest.mark.parametrize( ("create_weakref", "has_callback"), [ (m.weakref_from_handle, False), (m.weakref_from_object, False), (m.weakref_from_handle_and_function, True), (m.weakref_from_object_and_function, True), ], ) def test_weakref_err(create_weakref, has_callback): class C: __slots__ = [] def callback(_): pass ob = C() # Should raise TypeError on CPython with pytest.raises(TypeError) if not env.PYPY else contextlib.nullcontext(): _ = create_weakref(ob, callback) if has_callback else create_weakref(ob) def test_cpp_iterators(): assert m.tuple_iterator() == 12 assert m.dict_iterator() == 305 + 711 assert m.passed_iterator(iter((-7, 3))) == -4 def test_implementation_details(): lst = [39, 43, 92, 49, 22, 29, 93, 98, 26, 57, 8] tup = tuple(lst) assert m.sequence_item_get_ssize_t(lst) == 43 assert m.sequence_item_set_ssize_t(lst) is None assert lst[1] == "peppa" assert m.sequence_item_get_size_t(lst) == 92 assert m.sequence_item_set_size_t(lst) is None assert lst[2] == "george" assert m.list_item_get_ssize_t(lst) == 49 assert m.list_item_set_ssize_t(lst) is None assert lst[3] == "rebecca" assert m.list_item_get_size_t(lst) == 22 assert m.list_item_set_size_t(lst) is None assert lst[4] == "richard" assert m.tuple_item_get_ssize_t(tup) == 29 assert m.tuple_item_set_ssize_t() == ("emely", "edmond") assert m.tuple_item_get_size_t(tup) == 93 assert m.tuple_item_set_size_t() == ("candy", "cat") def test_external_float_(): r1 = m.square_float_(2.0) assert r1 == 4.0 def test_tuple_rvalue_getter(): pop = 1000 tup = tuple(range(pop)) m.tuple_rvalue_getter(tup) def test_list_rvalue_getter(): pop = 1000 my_list = list(range(pop)) m.list_rvalue_getter(my_list) def test_populate_dict_rvalue(): pop = 1000 my_dict = {i: i for i in range(pop)} assert m.populate_dict_rvalue(pop) == my_dict def test_populate_obj_str_attrs(): pop = 1000 o = types.SimpleNamespace(**{str(i): i for i in range(pop)}) new_o = m.populate_obj_str_attrs(o, pop) new_attrs = {k: v for k, v in new_o.__dict__.items() if not k.startswith("_")} assert all(isinstance(v, str) for v in new_attrs.values()) assert len(new_attrs) == pop @pytest.mark.parametrize( ("a", "b"), [("foo", "bar"), (1, 2), (1.0, 2.0), (list(range(3)), list(range(3, 6)))], ) def test_inplace_append(a, b): expected = a + b assert m.inplace_append(a, b) == expected @pytest.mark.parametrize( ("a", "b"), [(3, 2), (3.0, 2.0), (set(range(3)), set(range(2)))] ) def test_inplace_subtract(a, b): expected = a - b assert m.inplace_subtract(a, b) == expected @pytest.mark.parametrize(("a", "b"), [(3, 2), (3.0, 2.0), ([1], 3)]) def test_inplace_multiply(a, b): expected = a * b assert m.inplace_multiply(a, b) == expected @pytest.mark.parametrize(("a", "b"), [(6, 3), (6.0, 3.0)]) def test_inplace_divide(a, b): expected = a / b assert m.inplace_divide(a, b) == expected @pytest.mark.parametrize( ("a", "b"), [ (False, True), ( set(), { 1, }, ), ], ) def test_inplace_or(a, b): expected = a | b assert m.inplace_or(a, b) == expected @pytest.mark.parametrize( ("a", "b"), [ (True, False), ( {1, 2, 3}, { 1, }, ), ], ) def test_inplace_and(a, b): expected = a & b assert m.inplace_and(a, b) == expected @pytest.mark.parametrize(("a", "b"), [(8, 1), (-3, 2)]) def test_inplace_lshift(a, b): expected = a << b assert m.inplace_lshift(a, b) == expected @pytest.mark.parametrize(("a", "b"), [(8, 1), (-2, 2)]) def test_inplace_rshift(a, b): expected = a >> b assert m.inplace_rshift(a, b) == expected aoflagger-v3.4.0/external/pybind11/tests/test_kwargs_and_defaults.cpp0000644000175000017500000002234414507760431024522 0ustar olesoles/* tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "constructor_stats.h" #include "pybind11_tests.h" #include TEST_SUBMODULE(kwargs_and_defaults, m) { auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; // test_named_arguments m.def("kw_func0", kw_func); m.def("kw_func1", kw_func, py::arg("x"), py::arg("y")); m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200); m.def( "kw_func3", [](const char *) {}, py::arg("data") = std::string("Hello world!")); /* A fancier default argument */ std::vector list{{13, 17}}; m.def( "kw_func4", [](const std::vector &entries) { std::string ret = "{"; for (int i : entries) { ret += std::to_string(i) + " "; } ret.back() = '}'; return ret; }, py::arg("myList") = list); m.def("kw_func_udl", kw_func, "x"_a, "y"_a = 300); m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a = 0); // test_args_and_kwargs m.def("args_function", [](py::args args) -> py::tuple { PYBIND11_WARNING_PUSH #ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING PYBIND11_WARNING_DISABLE_CLANG("-Wreturn-std-move") #endif return args; PYBIND11_WARNING_POP }); m.def("args_kwargs_function", [](const py::args &args, const py::kwargs &kwargs) { return py::make_tuple(args, kwargs); }); // test_mixed_args_and_kwargs m.def("mixed_plus_args", [](int i, double j, const py::args &args) { return py::make_tuple(i, j, args); }); m.def("mixed_plus_kwargs", [](int i, double j, const py::kwargs &kwargs) { return py::make_tuple(i, j, kwargs); }); auto mixed_plus_both = [](int i, double j, const py::args &args, const py::kwargs &kwargs) { return py::make_tuple(i, j, args, kwargs); }; m.def("mixed_plus_args_kwargs", mixed_plus_both); m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both, py::arg("i") = 1, py::arg("j") = 3.14159); m.def( "args_kwonly", [](int i, double j, const py::args &args, int z) { return py::make_tuple(i, j, args, z); }, "i"_a, "j"_a, "z"_a); m.def( "args_kwonly_kwargs", [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { return py::make_tuple(i, j, args, z, kwargs); }, "i"_a, "j"_a, py::kw_only{}, "z"_a); m.def( "args_kwonly_kwargs_defaults", [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { return py::make_tuple(i, j, args, z, kwargs); }, "i"_a = 1, "j"_a = 3.14159, "z"_a = 42); m.def( "args_kwonly_full_monty", [](int h, int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { return py::make_tuple(h, i, j, args, z, kwargs); }, py::arg() = 1, py::arg() = 2, py::pos_only{}, "j"_a = 3.14159, "z"_a = 42); // test_args_refcount // PyPy needs a garbage collection to get the reference count values to match CPython's behaviour #ifdef PYPY_VERSION # define GC_IF_NEEDED ConstructorStats::gc() #else # define GC_IF_NEEDED #endif m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); }); m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); }); m.def("arg_refcount_o", [](const py::object &o) { GC_IF_NEEDED; return o.ref_count(); }); m.def("args_refcount", [](py::args a) { GC_IF_NEEDED; py::tuple t(a.size()); for (size_t i = 0; i < a.size(); i++) { // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast(i))); } return t; }); m.def("mixed_args_refcount", [](const py::object &o, py::args a) { GC_IF_NEEDED; py::tuple t(a.size() + 1); t[0] = o.ref_count(); for (size_t i = 0; i < a.size(); i++) { // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast(i))); } return t; }); // pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end. // Uncomment these to test that the static_assert is indeed working: // m.def("bad_args1", [](py::args, int) {}); // m.def("bad_args2", [](py::kwargs, int) {}); // m.def("bad_args3", [](py::kwargs, py::args) {}); // m.def("bad_args4", [](py::args, int, py::kwargs) {}); // m.def("bad_args5", [](py::args, py::kwargs, int) {}); // m.def("bad_args6", [](py::args, py::args) {}); // m.def("bad_args7", [](py::kwargs, py::kwargs) {}); // test_keyword_only_args m.def( "kw_only_all", [](int i, int j) { return py::make_tuple(i, j); }, py::kw_only(), py::arg("i"), py::arg("j")); m.def( "kw_only_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, py::arg(), py::kw_only(), py::arg("j"), py::arg("k")); m.def( "kw_only_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); }, py::arg() = 3, "j"_a = 4, py::kw_only(), "k"_a = 5, "z"_a); m.def( "kw_only_mixed", [](int i, int j) { return py::make_tuple(i, j); }, "i"_a, py::kw_only(), "j"_a); m.def( "kw_only_plus_more", [](int i, int j, int k, const py::kwargs &kwargs) { return py::make_tuple(i, j, k, kwargs); }, py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kw_only(), py::arg("k") /* kw-only */); m.def("register_invalid_kw_only", [](py::module_ m) { m.def( "bad_kw_only", [](int i, int j) { return py::make_tuple(i, j); }, py::kw_only(), py::arg() /* invalid unnamed argument */, "j"_a); }); // test_positional_only_args m.def( "pos_only_all", [](int i, int j) { return py::make_tuple(i, j); }, py::arg("i"), py::arg("j"), py::pos_only()); m.def( "pos_only_mix", [](int i, int j) { return py::make_tuple(i, j); }, py::arg("i"), py::pos_only(), py::arg("j")); m.def( "pos_kw_only_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, py::arg("i"), py::pos_only(), py::arg("j"), py::kw_only(), py::arg("k")); m.def( "pos_only_def_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, py::arg("i"), py::arg("j") = 2, py::pos_only(), py::arg("k") = 3); // These should fail to compile: #ifdef PYBIND11_NEVER_DEFINED_EVER // argument annotations are required when using kw_only m.def( "bad_kw_only1", [](int) {}, py::kw_only()); // can't specify both `py::kw_only` and a `py::args` argument m.def( "bad_kw_only2", [](int i, py::args) {}, py::kw_only(), "i"_a); #endif // test_function_signatures (along with most of the above) struct KWClass { void foo(int, float) {} }; py::class_(m, "KWClass") .def("foo0", &KWClass::foo) .def("foo1", &KWClass::foo, "x"_a, "y"_a); // Make sure a class (not an instance) can be used as a default argument. // The return value doesn't matter, only that the module is importable. m.def( "class_default_argument", [](py::object a) { return py::repr(std::move(a)); }, "a"_a = py::module_::import("decimal").attr("Decimal")); // Initial implementation of kw_only was broken when used on a method/constructor before any // other arguments // https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987 struct first_arg_kw_only {}; py::class_(m, "first_arg_kw_only") .def(py::init([](int) { return first_arg_kw_only(); }), py::kw_only(), // This being before any args was broken py::arg("i") = 0) .def( "method", [](first_arg_kw_only &, int, int) {}, py::kw_only(), // and likewise here py::arg("i") = 1, py::arg("j") = 2) // Closely related: pos_only marker didn't show up properly when it was before any other // arguments (although that is fairly useless in practice). .def( "pos_only", [](first_arg_kw_only &, int, int) {}, py::pos_only{}, py::arg("i"), py::arg("j")); } aoflagger-v3.4.0/external/pybind11/tests/test_enum.py0000644000175000017500000002135314507760431021324 0ustar olesoles# ruff: noqa: SIM201 SIM300 SIM202 import pytest from pybind11_tests import enums as m def test_unscoped_enum(): assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne" assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" assert str(m.EOne) == "UnscopedEnum.EOne" assert repr(m.UnscopedEnum.EOne) == "" assert repr(m.UnscopedEnum.ETwo) == "" assert repr(m.EOne) == "" # name property assert m.UnscopedEnum.EOne.name == "EOne" assert m.UnscopedEnum.EOne.value == 1 assert m.UnscopedEnum.ETwo.name == "ETwo" assert m.UnscopedEnum.ETwo.value == 2 assert m.EOne is m.UnscopedEnum.EOne # name, value readonly with pytest.raises(AttributeError): m.UnscopedEnum.EOne.name = "" with pytest.raises(AttributeError): m.UnscopedEnum.EOne.value = 10 # name, value returns a copy # TODO: Neither the name nor value tests actually check against aliasing. # Use a mutable type that has reference semantics. nonaliased_name = m.UnscopedEnum.EOne.name nonaliased_name = "bar" # noqa: F841 assert m.UnscopedEnum.EOne.name == "EOne" nonaliased_value = m.UnscopedEnum.EOne.value nonaliased_value = 10 # noqa: F841 assert m.UnscopedEnum.EOne.value == 1 # __members__ property assert m.UnscopedEnum.__members__ == { "EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree, } # __members__ readonly with pytest.raises(AttributeError): m.UnscopedEnum.__members__ = {} # __members__ returns a copy nonaliased_members = m.UnscopedEnum.__members__ nonaliased_members["bar"] = "baz" assert m.UnscopedEnum.__members__ == { "EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree, } for docstring_line in """An unscoped enumeration Members: EOne : Docstring for EOne ETwo : Docstring for ETwo EThree : Docstring for EThree""".split( "\n" ): assert docstring_line in m.UnscopedEnum.__doc__ # Unscoped enums will accept ==/!= int comparisons y = m.UnscopedEnum.ETwo assert y == 2 assert 2 == y assert y != 3 assert 3 != y # Compare with None assert y != None # noqa: E711 assert not (y == None) # noqa: E711 # Compare with an object assert y != object() assert not (y == object()) # Compare with string assert y != "2" assert "2" != y assert not ("2" == y) assert not (y == "2") with pytest.raises(TypeError): y < object() # noqa: B015 with pytest.raises(TypeError): y <= object() # noqa: B015 with pytest.raises(TypeError): y > object() # noqa: B015 with pytest.raises(TypeError): y >= object() # noqa: B015 with pytest.raises(TypeError): y | object() with pytest.raises(TypeError): y & object() with pytest.raises(TypeError): y ^ object() assert int(m.UnscopedEnum.ETwo) == 2 assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo" # order assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo assert m.UnscopedEnum.EOne < 2 assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne assert m.UnscopedEnum.ETwo > 1 assert m.UnscopedEnum.ETwo <= 2 assert m.UnscopedEnum.ETwo >= 2 assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo assert m.UnscopedEnum.EOne <= 2 assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne assert m.UnscopedEnum.ETwo >= 1 assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne) assert not (2 < m.UnscopedEnum.EOne) # arithmetic assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo def test_scoped_enum(): assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three" z = m.ScopedEnum.Two assert m.test_scoped_enum(z) == "ScopedEnum::Two" # Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False) assert not z == 3 assert not 3 == z assert z != 3 assert 3 != z # Compare with None assert z != None # noqa: E711 assert not (z == None) # noqa: E711 # Compare with an object assert z != object() assert not (z == object()) # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions) with pytest.raises(TypeError): z > 3 # noqa: B015 with pytest.raises(TypeError): z < 3 # noqa: B015 with pytest.raises(TypeError): z >= 3 # noqa: B015 with pytest.raises(TypeError): z <= 3 # noqa: B015 # order assert m.ScopedEnum.Two < m.ScopedEnum.Three assert m.ScopedEnum.Three > m.ScopedEnum.Two assert m.ScopedEnum.Two <= m.ScopedEnum.Three assert m.ScopedEnum.Two <= m.ScopedEnum.Two assert m.ScopedEnum.Two >= m.ScopedEnum.Two assert m.ScopedEnum.Three >= m.ScopedEnum.Two def test_implicit_conversion(): assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode" assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" assert repr(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "" assert repr(m.ClassWithUnscopedEnum.EFirstMode) == "" f = m.ClassWithUnscopedEnum.test_function first = m.ClassWithUnscopedEnum.EFirstMode second = m.ClassWithUnscopedEnum.ESecondMode assert f(first) == 1 assert f(first) == f(first) assert not f(first) != f(first) assert f(first) != f(second) assert not f(first) == f(second) assert f(first) == int(f(first)) assert not f(first) != int(f(first)) assert f(first) != int(f(second)) assert not f(first) == int(f(second)) # noinspection PyDictCreation x = {f(first): 1, f(second): 2} x[f(first)] = 3 x[f(second)] = 4 # Hashing test assert repr(x) == "{: 3, : 4}" def test_binary_operators(): assert int(m.Flags.Read) == 4 assert int(m.Flags.Write) == 2 assert int(m.Flags.Execute) == 1 assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7 assert int(m.Flags.Read | m.Flags.Write) == 6 assert int(m.Flags.Read | m.Flags.Execute) == 5 assert int(m.Flags.Write | m.Flags.Execute) == 3 assert int(m.Flags.Write | 1) == 3 assert ~m.Flags.Write == -3 state = m.Flags.Read | m.Flags.Write assert (state & m.Flags.Read) != 0 assert (state & m.Flags.Write) != 0 assert (state & m.Flags.Execute) == 0 assert (state & 1) == 0 state2 = ~state assert state2 == -7 assert int(state ^ state2) == -1 def test_enum_to_int(): m.test_enum_to_int(m.Flags.Read) m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) m.test_enum_to_int(m.ScopedCharEnum.Positive) m.test_enum_to_int(m.ScopedBoolEnum.TRUE) m.test_enum_to_uint(m.Flags.Read) m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) m.test_enum_to_uint(m.ScopedCharEnum.Positive) m.test_enum_to_uint(m.ScopedBoolEnum.TRUE) m.test_enum_to_long_long(m.Flags.Read) m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) m.test_enum_to_long_long(m.ScopedCharEnum.Positive) m.test_enum_to_long_long(m.ScopedBoolEnum.TRUE) def test_duplicate_enum_name(): with pytest.raises(ValueError) as excinfo: m.register_bad_enum() assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!' def test_char_underlying_enum(): # Issue #1331/PR #1334: assert type(m.ScopedCharEnum.Positive.__int__()) is int assert int(m.ScopedChar16Enum.Zero) == 0 assert hash(m.ScopedChar32Enum.Positive) == 1 assert type(m.ScopedCharEnum.Positive.__getstate__()) is int assert m.ScopedWCharEnum(1) == m.ScopedWCharEnum.Positive with pytest.raises(TypeError): # Even if the underlying type is char, only an int can be used to construct the enum: m.ScopedCharEnum("0") def test_bool_underlying_enum(): assert type(m.ScopedBoolEnum.TRUE.__int__()) is int assert int(m.ScopedBoolEnum.FALSE) == 0 assert hash(m.ScopedBoolEnum.TRUE) == 1 assert type(m.ScopedBoolEnum.TRUE.__getstate__()) is int assert m.ScopedBoolEnum(1) == m.ScopedBoolEnum.TRUE # Enum could construct with a bool # (bool is a strict subclass of int, and False will be converted to 0) assert m.ScopedBoolEnum(False) == m.ScopedBoolEnum.FALSE def test_docstring_signatures(): for enum_type in [m.ScopedEnum, m.UnscopedEnum]: for attr in enum_type.__dict__.values(): # Issue #2623/PR #2637: Add argument names to enum_ methods assert "arg0" not in (attr.__doc__ or "") aoflagger-v3.4.0/external/pybind11/tests/test_iostream.py0000644000175000017500000001604214507760431022202 0ustar olesolesfrom contextlib import redirect_stderr, redirect_stdout from io import StringIO from pybind11_tests import iostream as m def test_captured(capsys): msg = "I've been redirected to Python, I hope!" m.captured_output(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" m.captured_err(msg) stdout, stderr = capsys.readouterr() assert stdout == "" assert stderr == msg def test_captured_large_string(capsys): # Make this bigger than the buffer used on the C++ side: 1024 chars msg = "I've been redirected to Python, I hope!" msg = msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_2byte_offset0(capsys): msg = "\u07FF" msg = "" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_2byte_offset1(capsys): msg = "\u07FF" msg = "1" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_3byte_offset0(capsys): msg = "\uFFFF" msg = "" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_3byte_offset1(capsys): msg = "\uFFFF" msg = "1" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_3byte_offset2(capsys): msg = "\uFFFF" msg = "12" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_4byte_offset0(capsys): msg = "\U0010FFFF" msg = "" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_4byte_offset1(capsys): msg = "\U0010FFFF" msg = "1" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_4byte_offset2(capsys): msg = "\U0010FFFF" msg = "12" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_captured_utf8_4byte_offset3(capsys): msg = "\U0010FFFF" msg = "123" + msg * (1024 // len(msg) + 1) m.captured_output_default(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_guard_capture(capsys): msg = "I've been redirected to Python, I hope!" m.guard_output(msg) stdout, stderr = capsys.readouterr() assert stdout == msg assert stderr == "" def test_series_captured(capture): with capture: m.captured_output("a") m.captured_output("b") assert capture == "ab" def test_flush(capfd): msg = "(not flushed)" msg2 = "(flushed)" with m.ostream_redirect(): m.noisy_function(msg, flush=False) stdout, stderr = capfd.readouterr() assert stdout == "" m.noisy_function(msg2, flush=True) stdout, stderr = capfd.readouterr() assert stdout == msg + msg2 m.noisy_function(msg, flush=False) stdout, stderr = capfd.readouterr() assert stdout == msg def test_not_captured(capfd): msg = "Something that should not show up in log" stream = StringIO() with redirect_stdout(stream): m.raw_output(msg) stdout, stderr = capfd.readouterr() assert stdout == msg assert stderr == "" assert stream.getvalue() == "" stream = StringIO() with redirect_stdout(stream): m.captured_output(msg) stdout, stderr = capfd.readouterr() assert stdout == "" assert stderr == "" assert stream.getvalue() == msg def test_err(capfd): msg = "Something that should not show up in log" stream = StringIO() with redirect_stderr(stream): m.raw_err(msg) stdout, stderr = capfd.readouterr() assert stdout == "" assert stderr == msg assert stream.getvalue() == "" stream = StringIO() with redirect_stderr(stream): m.captured_err(msg) stdout, stderr = capfd.readouterr() assert stdout == "" assert stderr == "" assert stream.getvalue() == msg def test_multi_captured(capfd): stream = StringIO() with redirect_stdout(stream): m.captured_output("a") m.raw_output("b") m.captured_output("c") m.raw_output("d") stdout, stderr = capfd.readouterr() assert stdout == "bd" assert stream.getvalue() == "ac" def test_dual(capsys): m.captured_dual("a", "b") stdout, stderr = capsys.readouterr() assert stdout == "a" assert stderr == "b" def test_redirect(capfd): msg = "Should not be in log!" stream = StringIO() with redirect_stdout(stream): m.raw_output(msg) stdout, stderr = capfd.readouterr() assert stdout == msg assert stream.getvalue() == "" stream = StringIO() with redirect_stdout(stream), m.ostream_redirect(): m.raw_output(msg) stdout, stderr = capfd.readouterr() assert stdout == "" assert stream.getvalue() == msg stream = StringIO() with redirect_stdout(stream): m.raw_output(msg) stdout, stderr = capfd.readouterr() assert stdout == msg assert stream.getvalue() == "" def test_redirect_err(capfd): msg = "StdOut" msg2 = "StdErr" stream = StringIO() with redirect_stderr(stream), m.ostream_redirect(stdout=False): m.raw_output(msg) m.raw_err(msg2) stdout, stderr = capfd.readouterr() assert stdout == msg assert stderr == "" assert stream.getvalue() == msg2 def test_redirect_both(capfd): msg = "StdOut" msg2 = "StdErr" stream = StringIO() stream2 = StringIO() with redirect_stdout(stream), redirect_stderr(stream2), m.ostream_redirect(): m.raw_output(msg) m.raw_err(msg2) stdout, stderr = capfd.readouterr() assert stdout == "" assert stderr == "" assert stream.getvalue() == msg assert stream2.getvalue() == msg2 def test_threading(): with m.ostream_redirect(stdout=True, stderr=False): # start some threads threads = [] # start some threads for _j in range(20): threads.append(m.TestThread()) # give the threads some time to fail threads[0].sleep() # stop all the threads for t in threads: t.stop() for t in threads: t.join() # if a thread segfaults, we don't get here assert True aoflagger-v3.4.0/external/pybind11/tests/test_custom_type_setup.py0000644000175000017500000000210314507760431024143 0ustar olesolesimport gc import weakref import pytest import env # noqa: F401 from pybind11_tests import custom_type_setup as m @pytest.fixture() def gc_tester(): """Tests that an object is garbage collected. Assumes that any unreferenced objects are fully collected after calling `gc.collect()`. That is true on CPython, but does not appear to reliably hold on PyPy. """ weak_refs = [] def add_ref(obj): # PyPy does not support `gc.is_tracked`. if hasattr(gc, "is_tracked"): assert gc.is_tracked(obj) weak_refs.append(weakref.ref(obj)) yield add_ref gc.collect() for ref in weak_refs: assert ref() is None # PyPy does not seem to reliably garbage collect. @pytest.mark.skipif("env.PYPY") def test_self_cycle(gc_tester): obj = m.OwnsPythonObjects() obj.value = obj gc_tester(obj) # PyPy does not seem to reliably garbage collect. @pytest.mark.skipif("env.PYPY") def test_indirect_cycle(gc_tester): obj = m.OwnsPythonObjects() obj_list = [obj] obj.value = obj_list gc_tester(obj) aoflagger-v3.4.0/external/pybind11/tests/extra_python_package/0000755000175000017500000000000014516225226023140 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/extra_python_package/test_files.py0000644000175000017500000002014614507760431025660 0ustar olesolesimport contextlib import os import string import subprocess import sys import tarfile import zipfile # These tests must be run explicitly # They require CMake 3.15+ (--install) DIR = os.path.abspath(os.path.dirname(__file__)) MAIN_DIR = os.path.dirname(os.path.dirname(DIR)) PKGCONFIG = """\ prefix=${{pcfiledir}}/../../ includedir=${{prefix}}/include Name: pybind11 Description: Seamless operability between C++11 and Python Version: {VERSION} Cflags: -I${{includedir}} """ main_headers = { "include/pybind11/attr.h", "include/pybind11/buffer_info.h", "include/pybind11/cast.h", "include/pybind11/chrono.h", "include/pybind11/common.h", "include/pybind11/complex.h", "include/pybind11/eigen.h", "include/pybind11/embed.h", "include/pybind11/eval.h", "include/pybind11/functional.h", "include/pybind11/gil.h", "include/pybind11/iostream.h", "include/pybind11/numpy.h", "include/pybind11/operators.h", "include/pybind11/options.h", "include/pybind11/pybind11.h", "include/pybind11/pytypes.h", "include/pybind11/stl.h", "include/pybind11/stl_bind.h", } detail_headers = { "include/pybind11/detail/class.h", "include/pybind11/detail/common.h", "include/pybind11/detail/descr.h", "include/pybind11/detail/init.h", "include/pybind11/detail/internals.h", "include/pybind11/detail/type_caster_base.h", "include/pybind11/detail/typeid.h", } eigen_headers = { "include/pybind11/eigen/matrix.h", "include/pybind11/eigen/tensor.h", } stl_headers = { "include/pybind11/stl/filesystem.h", } cmake_files = { "share/cmake/pybind11/FindPythonLibsNew.cmake", "share/cmake/pybind11/pybind11Common.cmake", "share/cmake/pybind11/pybind11Config.cmake", "share/cmake/pybind11/pybind11ConfigVersion.cmake", "share/cmake/pybind11/pybind11NewTools.cmake", "share/cmake/pybind11/pybind11Targets.cmake", "share/cmake/pybind11/pybind11Tools.cmake", } pkgconfig_files = { "share/pkgconfig/pybind11.pc", } py_files = { "__init__.py", "__main__.py", "_version.py", "commands.py", "py.typed", "setup_helpers.py", } headers = main_headers | detail_headers | eigen_headers | stl_headers src_files = headers | cmake_files | pkgconfig_files all_files = src_files | py_files sdist_files = { "pybind11", "pybind11/include", "pybind11/include/pybind11", "pybind11/include/pybind11/detail", "pybind11/include/pybind11/eigen", "pybind11/include/pybind11/stl", "pybind11/share", "pybind11/share/cmake", "pybind11/share/cmake/pybind11", "pybind11/share/pkgconfig", "pyproject.toml", "setup.cfg", "setup.py", "LICENSE", "MANIFEST.in", "README.rst", "PKG-INFO", } local_sdist_files = { ".egg-info", ".egg-info/PKG-INFO", ".egg-info/SOURCES.txt", ".egg-info/dependency_links.txt", ".egg-info/not-zip-safe", ".egg-info/top_level.txt", } def read_tz_file(tar: tarfile.TarFile, name: str) -> bytes: start = tar.getnames()[0] + "/" inner_file = tar.extractfile(tar.getmember(f"{start}{name}")) assert inner_file with contextlib.closing(inner_file) as f: return f.read() def normalize_line_endings(value: bytes) -> bytes: return value.replace(os.linesep.encode("utf-8"), b"\n") def test_build_sdist(monkeypatch, tmpdir): monkeypatch.chdir(MAIN_DIR) subprocess.run( [sys.executable, "-m", "build", "--sdist", f"--outdir={tmpdir}"], check=True ) (sdist,) = tmpdir.visit("*.tar.gz") with tarfile.open(str(sdist), "r:gz") as tar: start = tar.getnames()[0] + "/" version = start[9:-1] simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]} setup_py = read_tz_file(tar, "setup.py") pyproject_toml = read_tz_file(tar, "pyproject.toml") pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc") cmake_cfg = read_tz_file( tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake" ) assert ( 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in cmake_cfg.decode("utf-8") ) files = {f"pybind11/{n}" for n in all_files} files |= sdist_files files |= {f"pybind11{n}" for n in local_sdist_files} files.add("pybind11.egg-info/entry_points.txt") files.add("pybind11.egg-info/requires.txt") assert simpler == files with open(os.path.join(MAIN_DIR, "tools", "setup_main.py.in"), "rb") as f: contents = ( string.Template(f.read().decode("utf-8")) .substitute(version=version, extra_cmd="") .encode("utf-8") ) assert setup_py == contents with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f: contents = f.read() assert pyproject_toml == contents simple_version = ".".join(version.split(".")[:3]) pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8") assert normalize_line_endings(pkgconfig) == pkgconfig_expected def test_build_global_dist(monkeypatch, tmpdir): monkeypatch.chdir(MAIN_DIR) monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1") subprocess.run( [sys.executable, "-m", "build", "--sdist", "--outdir", str(tmpdir)], check=True ) (sdist,) = tmpdir.visit("*.tar.gz") with tarfile.open(str(sdist), "r:gz") as tar: start = tar.getnames()[0] + "/" version = start[16:-1] simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]} setup_py = read_tz_file(tar, "setup.py") pyproject_toml = read_tz_file(tar, "pyproject.toml") pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc") cmake_cfg = read_tz_file( tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake" ) assert ( 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in cmake_cfg.decode("utf-8") ) files = {f"pybind11/{n}" for n in all_files} files |= sdist_files files |= {f"pybind11_global{n}" for n in local_sdist_files} assert simpler == files with open(os.path.join(MAIN_DIR, "tools", "setup_global.py.in"), "rb") as f: contents = ( string.Template(f.read().decode()) .substitute(version=version, extra_cmd="") .encode("utf-8") ) assert setup_py == contents with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f: contents = f.read() assert pyproject_toml == contents simple_version = ".".join(version.split(".")[:3]) pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8") assert normalize_line_endings(pkgconfig) == pkgconfig_expected def tests_build_wheel(monkeypatch, tmpdir): monkeypatch.chdir(MAIN_DIR) subprocess.run( [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True ) (wheel,) = tmpdir.visit("*.whl") files = {f"pybind11/{n}" for n in all_files} files |= { "dist-info/LICENSE", "dist-info/METADATA", "dist-info/RECORD", "dist-info/WHEEL", "dist-info/entry_points.txt", "dist-info/top_level.txt", } with zipfile.ZipFile(str(wheel)) as z: names = z.namelist() trimmed = {n for n in names if "dist-info" not in n} trimmed |= {f"dist-info/{n.split('/', 1)[-1]}" for n in names if "dist-info" in n} assert files == trimmed def tests_build_global_wheel(monkeypatch, tmpdir): monkeypatch.chdir(MAIN_DIR) monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1") subprocess.run( [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True ) (wheel,) = tmpdir.visit("*.whl") files = {f"data/data/{n}" for n in src_files} files |= {f"data/headers/{n[8:]}" for n in headers} files |= { "dist-info/LICENSE", "dist-info/METADATA", "dist-info/WHEEL", "dist-info/top_level.txt", "dist-info/RECORD", } with zipfile.ZipFile(str(wheel)) as z: names = z.namelist() beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0] trimmed = {n[len(beginning) + 1 :] for n in names} assert files == trimmed aoflagger-v3.4.0/external/pybind11/tests/extra_python_package/pytest.ini0000644000175000017500000000000014507760431025161 0ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_docstring_options.cpp0000644000175000017500000001071514507760431024261 0ustar olesoles/* tests/test_docstring_options.cpp -- generation of docstrings and signatures Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "pybind11_tests.h" TEST_SUBMODULE(docstring_options, m) { // test_docstring_options { py::options options; options.disable_function_signatures(); m.def( "test_function1", [](int, int) {}, py::arg("a"), py::arg("b")); m.def( "test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); m.def( "test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring"); m.def( "test_overloaded1", [](double) {}, py::arg("d")); m.def( "test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1"); m.def( "test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2"); m.def( "test_overloaded3", [](int) {}, py::arg("i")); m.def( "test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr"); options.enable_function_signatures(); m.def( "test_function3", [](int, int) {}, py::arg("a"), py::arg("b")); m.def( "test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); options.disable_function_signatures().disable_user_defined_docstrings(); m.def( "test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); { py::options nested_options; nested_options.enable_user_defined_docstrings(); m.def( "test_function6", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); } } m.def( "test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); { py::options options; options.disable_user_defined_docstrings(); options.disable_function_signatures(); m.def("test_function8", []() {}); } { py::options options; options.disable_user_defined_docstrings(); struct DocstringTestFoo { int value; void setValue(int v) { value = v; } int getValue() const { return value; } }; py::class_(m, "DocstringTestFoo", "This is a class docstring") .def_property("value_prop", &DocstringTestFoo::getValue, &DocstringTestFoo::setValue, "This is a property docstring"); } { enum class DocstringTestEnum1 { Member1, Member2 }; py::enum_(m, "DocstringTestEnum1", "Enum docstring") .value("Member1", DocstringTestEnum1::Member1) .value("Member2", DocstringTestEnum1::Member2); } { py::options options; options.enable_enum_members_docstring(); enum class DocstringTestEnum2 { Member1, Member2 }; py::enum_(m, "DocstringTestEnum2", "Enum docstring") .value("Member1", DocstringTestEnum2::Member1) .value("Member2", DocstringTestEnum2::Member2); } { py::options options; options.disable_enum_members_docstring(); enum class DocstringTestEnum3 { Member1, Member2 }; py::enum_(m, "DocstringTestEnum3", "Enum docstring") .value("Member1", DocstringTestEnum3::Member1) .value("Member2", DocstringTestEnum3::Member2); } { py::options options; options.disable_user_defined_docstrings(); enum class DocstringTestEnum4 { Member1, Member2 }; py::enum_(m, "DocstringTestEnum4", "Enum docstring") .value("Member1", DocstringTestEnum4::Member1) .value("Member2", DocstringTestEnum4::Member2); } { py::options options; options.disable_user_defined_docstrings(); options.disable_enum_members_docstring(); enum class DocstringTestEnum5 { Member1, Member2 }; py::enum_(m, "DocstringTestEnum5", "Enum docstring") .value("Member1", DocstringTestEnum5::Member1) .value("Member2", DocstringTestEnum5::Member2); } } aoflagger-v3.4.0/external/pybind11/tests/test_numpy_array.py0000644000175000017500000004767614507760431022746 0ustar olesolesimport pytest import env # noqa: F401 from pybind11_tests import numpy_array as m np = pytest.importorskip("numpy") def test_dtypes(): # See issue #1328. # - Platform-dependent sizes. for size_check in m.get_platform_dtype_size_checks(): print(size_check) assert size_check.size_cpp == size_check.size_numpy, size_check # - Concrete sizes. for check in m.get_concrete_dtype_checks(): print(check) assert check.numpy == check.pybind11, check if check.numpy.num != check.pybind11.num: print( f"NOTE: typenum mismatch for {check}: {check.numpy.num} != {check.pybind11.num}" ) @pytest.fixture() def arr(): return np.array([[1, 2, 3], [4, 5, 6]], "=u2") def test_array_attributes(): a = np.array(0, "f8") assert m.ndim(a) == 0 assert all(m.shape(a) == []) assert all(m.strides(a) == []) with pytest.raises(IndexError) as excinfo: m.shape(a, 0) assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)" with pytest.raises(IndexError) as excinfo: m.strides(a, 0) assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)" assert m.writeable(a) assert m.size(a) == 1 assert m.itemsize(a) == 8 assert m.nbytes(a) == 8 assert m.owndata(a) a = np.array([[1, 2, 3], [4, 5, 6]], "u2").view() a.flags.writeable = False assert m.ndim(a) == 2 assert all(m.shape(a) == [2, 3]) assert m.shape(a, 0) == 2 assert m.shape(a, 1) == 3 assert all(m.strides(a) == [6, 2]) assert m.strides(a, 0) == 6 assert m.strides(a, 1) == 2 with pytest.raises(IndexError) as excinfo: m.shape(a, 2) assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)" with pytest.raises(IndexError) as excinfo: m.strides(a, 2) assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)" assert not m.writeable(a) assert m.size(a) == 6 assert m.itemsize(a) == 2 assert m.nbytes(a) == 12 assert not m.owndata(a) @pytest.mark.parametrize( ("args", "ret"), [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)] ) def test_index_offset(arr, args, ret): assert m.index_at(arr, *args) == ret assert m.index_at_t(arr, *args) == ret assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize def test_dim_check_fail(arr): for func in ( m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t, m.mutate_data, m.mutate_data_t, ): with pytest.raises(IndexError) as excinfo: func(arr, 1, 2, 3) assert str(excinfo.value) == "too many indices for an array: 3 (ndim = 2)" @pytest.mark.parametrize( ("args", "ret"), [ ([], [1, 2, 3, 4, 5, 6]), ([1], [4, 5, 6]), ([0, 1], [2, 3, 4, 5, 6]), ([1, 2], [6]), ], ) def test_data(arr, args, ret): from sys import byteorder assert all(m.data_t(arr, *args) == ret) assert all(m.data(arr, *args)[(0 if byteorder == "little" else 1) :: 2] == ret) assert all(m.data(arr, *args)[(1 if byteorder == "little" else 0) :: 2] == 0) @pytest.mark.parametrize("dim", [0, 1, 3]) def test_at_fail(arr, dim): for func in m.at_t, m.mutate_at_t: with pytest.raises(IndexError) as excinfo: func(arr, *([0] * dim)) assert str(excinfo.value) == f"index dimension mismatch: {dim} (ndim = 2)" def test_at(arr): assert m.at_t(arr, 0, 2) == 3 assert m.at_t(arr, 1, 0) == 4 assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6]) assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6]) def test_mutate_readonly(arr): arr.flags.writeable = False for func, args in ( (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)), ): with pytest.raises(ValueError) as excinfo: func(arr, *args) assert str(excinfo.value) == "array is not writeable" def test_mutate_data(arr): assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12]) assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24]) assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48]) assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96]) assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192]) assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193]) assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194]) assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195]) assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196]) assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197]) def test_bounds_check(arr): for func in ( m.index_at, m.index_at_t, m.data, m.data_t, m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t, ): with pytest.raises(IndexError) as excinfo: func(arr, 2, 0) assert str(excinfo.value) == "index 2 is out of bounds for axis 0 with size 2" with pytest.raises(IndexError) as excinfo: func(arr, 0, 4) assert str(excinfo.value) == "index 4 is out of bounds for axis 1 with size 3" def test_make_c_f_array(): assert m.make_c_array().flags.c_contiguous assert not m.make_c_array().flags.f_contiguous assert m.make_f_array().flags.f_contiguous assert not m.make_f_array().flags.c_contiguous def test_make_empty_shaped_array(): m.make_empty_shaped_array() # empty shape means numpy scalar, PEP 3118 assert m.scalar_int().ndim == 0 assert m.scalar_int().shape == () assert m.scalar_int() == 42 def test_wrap(): def assert_references(a, b, base=None): if base is None: base = a assert a is not b assert a.__array_interface__["data"][0] == b.__array_interface__["data"][0] assert a.shape == b.shape assert a.strides == b.strides assert a.flags.c_contiguous == b.flags.c_contiguous assert a.flags.f_contiguous == b.flags.f_contiguous assert a.flags.writeable == b.flags.writeable assert a.flags.aligned == b.flags.aligned # 1.13 supported Python 3.6 if tuple(int(x) for x in np.__version__.split(".")[:2]) >= (1, 14): assert a.flags.writebackifcopy == b.flags.writebackifcopy else: assert a.flags.updateifcopy == b.flags.updateifcopy assert np.all(a == b) assert not b.flags.owndata assert b.base is base if a.flags.writeable and a.ndim == 2: a[0, 0] = 1234 assert b[0, 0] == 1234 a1 = np.array([1, 2], dtype=np.int16) assert a1.flags.owndata assert a1.base is None a2 = m.wrap(a1) assert_references(a1, a2) a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="F") assert a1.flags.owndata assert a1.base is None a2 = m.wrap(a1) assert_references(a1, a2) a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="C") a1.flags.writeable = False a2 = m.wrap(a1) assert_references(a1, a2) a1 = np.random.random((4, 4, 4)) a2 = m.wrap(a1) assert_references(a1, a2) a1t = a1.transpose() a2 = m.wrap(a1t) assert_references(a1t, a2, a1) a1d = a1.diagonal() a2 = m.wrap(a1d) assert_references(a1d, a2, a1) a1m = a1[::-1, ::-1, ::-1] a2 = m.wrap(a1m) assert_references(a1m, a2, a1) def test_numpy_view(capture): with capture: ac = m.ArrayClass() ac_view_1 = ac.numpy_view() ac_view_2 = ac.numpy_view() assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32)) del ac pytest.gc_collect() assert ( capture == """ ArrayClass() ArrayClass::numpy_view() ArrayClass::numpy_view() """ ) ac_view_1[0] = 4 ac_view_1[1] = 3 assert ac_view_2[0] == 4 assert ac_view_2[1] == 3 with capture: del ac_view_1 del ac_view_2 pytest.gc_collect() pytest.gc_collect() assert ( capture == """ ~ArrayClass() """ ) def test_cast_numpy_int64_to_uint64(): m.function_taking_uint64(123) m.function_taking_uint64(np.uint64(123)) def test_isinstance(): assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array") assert m.isinstance_typed(np.array([1.0, 2.0, 3.0])) def test_constructors(): defaults = m.default_constructors() for a in defaults.values(): assert a.size == 0 assert defaults["array"].dtype == np.array([]).dtype assert defaults["array_t"].dtype == np.int32 assert defaults["array_t"].dtype == np.float64 results = m.converting_constructors([1, 2, 3]) for a in results.values(): np.testing.assert_array_equal(a, [1, 2, 3]) assert results["array"].dtype == np.int_ assert results["array_t"].dtype == np.int32 assert results["array_t"].dtype == np.float64 def test_overload_resolution(msg): # Exact overload matches: assert m.overloaded(np.array([1], dtype="float64")) == "double" assert m.overloaded(np.array([1], dtype="float32")) == "float" assert m.overloaded(np.array([1], dtype="ushort")) == "unsigned short" assert m.overloaded(np.array([1], dtype="intc")) == "int" assert m.overloaded(np.array([1], dtype="longlong")) == "long long" assert m.overloaded(np.array([1], dtype="complex")) == "double complex" assert m.overloaded(np.array([1], dtype="csingle")) == "float complex" # No exact match, should call first convertible version: assert m.overloaded(np.array([1], dtype="uint8")) == "double" with pytest.raises(TypeError) as excinfo: m.overloaded("not an array") assert ( msg(excinfo.value) == """ overloaded(): incompatible function arguments. The following argument types are supported: 1. (arg0: numpy.ndarray[numpy.float64]) -> str 2. (arg0: numpy.ndarray[numpy.float32]) -> str 3. (arg0: numpy.ndarray[numpy.int32]) -> str 4. (arg0: numpy.ndarray[numpy.uint16]) -> str 5. (arg0: numpy.ndarray[numpy.int64]) -> str 6. (arg0: numpy.ndarray[numpy.complex128]) -> str 7. (arg0: numpy.ndarray[numpy.complex64]) -> str Invoked with: 'not an array' """ ) assert m.overloaded2(np.array([1], dtype="float64")) == "double" assert m.overloaded2(np.array([1], dtype="float32")) == "float" assert m.overloaded2(np.array([1], dtype="complex64")) == "float complex" assert m.overloaded2(np.array([1], dtype="complex128")) == "double complex" assert m.overloaded2(np.array([1], dtype="float32")) == "float" assert m.overloaded3(np.array([1], dtype="float64")) == "double" assert m.overloaded3(np.array([1], dtype="intc")) == "int" expected_exc = """ overloaded3(): incompatible function arguments. The following argument types are supported: 1. (arg0: numpy.ndarray[numpy.int32]) -> str 2. (arg0: numpy.ndarray[numpy.float64]) -> str Invoked with: """ with pytest.raises(TypeError) as excinfo: m.overloaded3(np.array([1], dtype="uintc")) assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype="uint32")) with pytest.raises(TypeError) as excinfo: m.overloaded3(np.array([1], dtype="float32")) assert msg(excinfo.value) == expected_exc + repr(np.array([1.0], dtype="float32")) with pytest.raises(TypeError) as excinfo: m.overloaded3(np.array([1], dtype="complex")) assert msg(excinfo.value) == expected_exc + repr(np.array([1.0 + 0.0j])) # Exact matches: assert m.overloaded4(np.array([1], dtype="double")) == "double" assert m.overloaded4(np.array([1], dtype="longlong")) == "long long" # Non-exact matches requiring conversion. Since float to integer isn't a # save conversion, it should go to the double overload, but short can go to # either (and so should end up on the first-registered, the long long). assert m.overloaded4(np.array([1], dtype="float32")) == "double" assert m.overloaded4(np.array([1], dtype="short")) == "long long" assert m.overloaded5(np.array([1], dtype="double")) == "double" assert m.overloaded5(np.array([1], dtype="uintc")) == "unsigned int" assert m.overloaded5(np.array([1], dtype="float32")) == "unsigned int" def test_greedy_string_overload(): """Tests fix for #685 - ndarray shouldn't go to std::string overload""" assert m.issue685("abc") == "string" assert m.issue685(np.array([97, 98, 99], dtype="b")) == "array" assert m.issue685(123) == "other" def test_array_unchecked_fixed_dims(msg): z1 = np.array([[1, 2], [3, 4]], dtype="float64") m.proxy_add2(z1, 10) assert np.all(z1 == [[11, 12], [13, 14]]) with pytest.raises(ValueError) as excinfo: m.proxy_add2(np.array([1.0, 2, 3]), 5.0) assert ( msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2" ) expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int") assert np.all(m.proxy_init3(3.0) == expect_c) expect_f = np.transpose(expect_c) assert np.all(m.proxy_init3F(3.0) == expect_f) assert m.proxy_squared_L2_norm(np.array(range(6))) == 55 assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55 assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1) assert m.proxy_auxiliaries1_const_ref(z1[0, :]) assert m.proxy_auxiliaries2_const_ref(z1) def test_array_unchecked_dyn_dims(): z1 = np.array([[1, 2], [3, 4]], dtype="float64") m.proxy_add2_dyn(z1, 10) assert np.all(z1 == [[11, 12], [13, 14]]) expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int") assert np.all(m.proxy_init3_dyn(3.0) == expect_c) assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1) def test_array_failure(): with pytest.raises(ValueError) as excinfo: m.array_fail_test() assert str(excinfo.value) == "cannot create a pybind11::array from a nullptr" with pytest.raises(ValueError) as excinfo: m.array_t_fail_test() assert str(excinfo.value) == "cannot create a pybind11::array_t from a nullptr" with pytest.raises(ValueError) as excinfo: m.array_fail_test_negative_size() assert str(excinfo.value) == "negative dimensions are not allowed" def test_initializer_list(): assert m.array_initializer_list1().shape == (1,) assert m.array_initializer_list2().shape == (1, 2) assert m.array_initializer_list3().shape == (1, 2, 3) assert m.array_initializer_list4().shape == (1, 2, 3, 4) def test_array_resize(): a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype="float64") m.array_reshape2(a) assert a.size == 9 assert np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # total size change should succced with refcheck off m.array_resize3(a, 4, False) assert a.size == 64 # ... and fail with refcheck on try: m.array_resize3(a, 3, True) except ValueError as e: assert str(e).startswith("cannot resize an array") # noqa: PT017 # transposed array doesn't own data b = a.transpose() try: m.array_resize3(b, 3, False) except ValueError as e: assert str(e).startswith( # noqa: PT017 "cannot resize this array: it does not own its data" ) # ... but reshape should be fine m.array_reshape2(b) assert b.shape == (8, 8) @pytest.mark.xfail("env.PYPY") def test_array_create_and_resize(): a = m.create_and_resize(2) assert a.size == 4 assert np.all(a == 42.0) def test_array_view(): a = np.ones(100 * 4).astype("uint8") a_float_view = m.array_view(a, "float32") assert a_float_view.shape == (100 * 1,) # 1 / 4 bytes = 8 / 32 a_int16_view = m.array_view(a, "int16") # 1 / 2 bytes = 16 / 32 assert a_int16_view.shape == (100 * 2,) def test_array_view_invalid(): a = np.ones(100 * 4).astype("uint8") with pytest.raises(TypeError): m.array_view(a, "deadly_dtype") def test_reshape_initializer_list(): a = np.arange(2 * 7 * 3) + 1 x = m.reshape_initializer_list(a, 2, 7, 3) assert x.shape == (2, 7, 3) assert list(x[1][4]) == [34, 35, 36] with pytest.raises(ValueError) as excinfo: m.reshape_initializer_list(a, 1, 7, 3) assert str(excinfo.value) == "cannot reshape array of size 42 into shape (1,7,3)" def test_reshape_tuple(): a = np.arange(3 * 7 * 2) + 1 x = m.reshape_tuple(a, (3, 7, 2)) assert x.shape == (3, 7, 2) assert list(x[1][4]) == [23, 24] y = m.reshape_tuple(x, (x.size,)) assert y.shape == (42,) with pytest.raises(ValueError) as excinfo: m.reshape_tuple(a, (3, 7, 1)) assert str(excinfo.value) == "cannot reshape array of size 42 into shape (3,7,1)" with pytest.raises(ValueError) as excinfo: m.reshape_tuple(a, ()) assert str(excinfo.value) == "cannot reshape array of size 42 into shape ()" def test_index_using_ellipsis(): a = m.index_using_ellipsis(np.zeros((5, 6, 7))) assert a.shape == (6,) @pytest.mark.parametrize( "test_func", [ m.test_fmt_desc_float, m.test_fmt_desc_double, m.test_fmt_desc_const_float, m.test_fmt_desc_const_double, ], ) def test_format_descriptors_for_floating_point_types(test_func): assert "numpy.ndarray[numpy.float" in test_func.__doc__ @pytest.mark.parametrize("forcecast", [False, True]) @pytest.mark.parametrize("contiguity", [None, "C", "F"]) @pytest.mark.parametrize("noconvert", [False, True]) @pytest.mark.filterwarnings( "ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning" ) def test_argument_conversions(forcecast, contiguity, noconvert): function_name = "accept_double" if contiguity == "C": function_name += "_c_style" elif contiguity == "F": function_name += "_f_style" if forcecast: function_name += "_forcecast" if noconvert: function_name += "_noconvert" function = getattr(m, function_name) for dtype in [np.dtype("float32"), np.dtype("float64"), np.dtype("complex128")]: for order in ["C", "F"]: for shape in [(2, 2), (1, 3, 1, 1), (1, 1, 1), (0,)]: if not noconvert: # If noconvert is not passed, only complex128 needs to be truncated and # "cannot be safely obtained". So without `forcecast`, the argument shouldn't # be accepted. should_raise = dtype.name == "complex128" and not forcecast else: # If noconvert is passed, only float64 and the matching order is accepted. # If at most one dimension has a size greater than 1, the array is also # trivially contiguous. trivially_contiguous = sum(1 for d in shape if d > 1) <= 1 should_raise = dtype.name != "float64" or ( contiguity is not None and contiguity != order and not trivially_contiguous ) array = np.zeros(shape, dtype=dtype, order=order) if not should_raise: function(array) else: with pytest.raises( TypeError, match="incompatible function arguments" ): function(array) @pytest.mark.xfail("env.PYPY") def test_dtype_refcount_leak(): from sys import getrefcount dtype = np.dtype(np.float_) a = np.array([1], dtype=dtype) before = getrefcount(dtype) m.ndim(a) after = getrefcount(dtype) assert after == before def test_round_trip_float(): arr = np.zeros((), np.float64) arr[()] = 37.2 assert m.round_trip_float(arr) == 37.2 aoflagger-v3.4.0/external/pybind11/tests/test_union.py0000644000175000017500000000022414507760431021502 0ustar olesolesfrom pybind11_tests import union_ as m def test_union(): instance = m.TestUnion() instance.as_uint = 10 assert instance.as_int == 10 aoflagger-v3.4.0/external/pybind11/tests/env.py0000644000175000017500000000163614507760431020113 0ustar olesolesimport platform import sys import pytest LINUX = sys.platform.startswith("linux") MACOS = sys.platform.startswith("darwin") WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin") CPYTHON = platform.python_implementation() == "CPython" PYPY = platform.python_implementation() == "PyPy" def deprecated_call(): """ pytest.deprecated_call() seems broken in pytest<3.9.x; concretely, it doesn't work on CPython 3.8.0 with pytest==3.3.2 on Ubuntu 18.04 (#2922). This is a narrowed reimplementation of the following PR :( https://github.com/pytest-dev/pytest/pull/4104 """ # TODO: Remove this when testing requires pytest>=3.9. pieces = pytest.__version__.split(".") pytest_major_minor = (int(pieces[0]), int(pieces[1])) if pytest_major_minor < (3, 9): return pytest.warns((DeprecationWarning, PendingDeprecationWarning)) return pytest.deprecated_call() aoflagger-v3.4.0/external/pybind11/tests/test_eval_call.py0000644000175000017500000000016714507760431022302 0ustar olesoles# This file is called from 'test_eval.py' if "call_test2" in locals(): call_test2(y) # noqa: F821 undefined name aoflagger-v3.4.0/external/pybind11/tests/test_opaque_types.cpp0000644000175000017500000000533114507760431023226 0ustar olesoles/* tests/test_opaque_types.cpp -- opaque types, passing void pointers Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "pybind11_tests.h" #include // IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures // // This also deliberately doesn't use the below StringList type alias to test // that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator` // bit is just the default `std::vector` allocator). PYBIND11_MAKE_OPAQUE(std::vector>); using StringList = std::vector>; TEST_SUBMODULE(opaque_types, m) { // test_string_list py::class_(m, "StringList") .def(py::init<>()) .def("pop_back", &StringList::pop_back) /* There are multiple versions of push_back(), etc. Select the right ones. */ .def("push_back", (void(StringList::*)(const std::string &)) & StringList::push_back) .def("back", (std::string & (StringList::*) ()) & StringList::back) .def("__len__", [](const StringList &v) { return v.size(); }) .def( "__iter__", [](StringList &v) { return py::make_iterator(v.begin(), v.end()); }, py::keep_alive<0, 1>()); class ClassWithSTLVecProperty { public: StringList stringList; }; py::class_(m, "ClassWithSTLVecProperty") .def(py::init<>()) .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList); m.def("print_opaque_list", [](const StringList &l) { std::string ret = "Opaque list: ["; bool first = true; for (const auto &entry : l) { if (!first) { ret += ", "; } ret += entry; first = false; } return ret + "]"; }); // test_pointers m.def("return_void_ptr", []() { return (void *) 0x1234; }); m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast(ptr); }); m.def("return_null_str", []() { return (char *) nullptr; }); m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast(ptr); }); m.def("return_unique_ptr", []() -> std::unique_ptr { auto *result = new StringList(); result->push_back("some value"); return std::unique_ptr(result); }); // test unions py::class_(m, "IntFloat") .def(py::init<>()) .def_readwrite("i", &IntFloat::i) .def_readwrite("f", &IntFloat::f); } aoflagger-v3.4.0/external/pybind11/tests/test_constants_and_functions.py0000644000175000017500000000273214507760431025306 0ustar olesolesimport pytest m = pytest.importorskip("pybind11_tests.constants_and_functions") def test_constants(): assert m.some_constant == 14 def test_function_overloading(): assert m.test_function() == "test_function()" assert m.test_function(7) == "test_function(7)" assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)" assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)" assert m.test_function() == "test_function()" assert m.test_function("abcd") == "test_function(char *)" assert m.test_function(1, 1.0) == "test_function(int, float)" assert m.test_function(1, 1.0) == "test_function(int, float)" assert m.test_function(2.0, 2) == "test_function(float, int)" def test_bytes(): assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]" def test_exception_specifiers(): c = m.C() assert c.m1(2) == 1 assert c.m2(3) == 1 assert c.m3(5) == 2 assert c.m4(7) == 3 assert c.m5(10) == 5 assert c.m6(14) == 8 assert c.m7(20) == 13 assert c.m8(29) == 21 assert m.f1(33) == 34 assert m.f2(53) == 55 assert m.f3(86) == 89 assert m.f4(140) == 144 def test_function_record_leaks(): class RaisingRepr: def __repr__(self): raise RuntimeError("Surprise!") with pytest.raises(RuntimeError): m.register_large_capture_with_invalid_arguments(m) with pytest.raises(RuntimeError): m.register_with_raising_repr(m, RaisingRepr()) aoflagger-v3.4.0/external/pybind11/tests/test_local_bindings.py0000644000175000017500000001756614507760431023342 0ustar olesolesimport pytest import env # noqa: F401 from pybind11_tests import local_bindings as m def test_load_external(): """Load a `py::module_local` type that's only registered in an external module""" import pybind11_cross_module_tests as cm assert m.load_external1(cm.ExternalType1(11)) == 11 assert m.load_external2(cm.ExternalType2(22)) == 22 with pytest.raises(TypeError) as excinfo: assert m.load_external2(cm.ExternalType1(21)) == 21 assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: assert m.load_external1(cm.ExternalType2(12)) == 12 assert "incompatible function arguments" in str(excinfo.value) def test_local_bindings(): """Tests that duplicate `py::module_local` class bindings work across modules""" # Make sure we can load the second module with the conflicting (but local) definition: import pybind11_cross_module_tests as cm i1 = m.LocalType(5) assert i1.get() == 4 assert i1.get3() == 8 i2 = cm.LocalType(10) assert i2.get() == 11 assert i2.get2() == 12 assert not hasattr(i1, "get2") assert not hasattr(i2, "get3") # Loading within the local module assert m.local_value(i1) == 5 assert cm.local_value(i2) == 10 # Cross-module loading works as well (on failure, the type loader looks for # external module-local converters): assert m.local_value(i2) == 10 assert cm.local_value(i1) == 5 def test_nonlocal_failure(): """Tests that attempting to register a non-local type in multiple modules fails""" import pybind11_cross_module_tests as cm with pytest.raises(RuntimeError) as excinfo: cm.register_nonlocal() assert ( str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!' ) def test_duplicate_local(): """Tests expected failure when registering a class twice with py::local in the same module""" with pytest.raises(RuntimeError) as excinfo: m.register_local_external() import pybind11_tests assert str(excinfo.value) == ( 'generic_type: type "LocalExternal" is already registered!' if hasattr(pybind11_tests, "class_") else "test_class not enabled" ) def test_stl_bind_local(): import pybind11_cross_module_tests as cm v1, v2 = m.LocalVec(), cm.LocalVec() v1.append(m.LocalType(1)) v1.append(m.LocalType(2)) v2.append(cm.LocalType(1)) v2.append(cm.LocalType(2)) # Cross module value loading: v1.append(cm.LocalType(3)) v2.append(m.LocalType(3)) assert [i.get() for i in v1] == [0, 1, 2] assert [i.get() for i in v2] == [2, 3, 4] v3, v4 = m.NonLocalVec(), cm.NonLocalVec2() v3.append(m.NonLocalType(1)) v3.append(m.NonLocalType(2)) v4.append(m.NonLocal2(3)) v4.append(m.NonLocal2(4)) assert [i.get() for i in v3] == [1, 2] assert [i.get() for i in v4] == [13, 14] d1, d2 = m.LocalMap(), cm.LocalMap() d1["a"] = v1[0] d1["b"] = v1[1] d2["c"] = v2[0] d2["d"] = v2[1] assert {i: d1[i].get() for i in d1} == {"a": 0, "b": 1} assert {i: d2[i].get() for i in d2} == {"c": 2, "d": 3} def test_stl_bind_global(): import pybind11_cross_module_tests as cm with pytest.raises(RuntimeError) as excinfo: cm.register_nonlocal_map() assert ( str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!' ) with pytest.raises(RuntimeError) as excinfo: cm.register_nonlocal_vec() assert ( str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!' ) with pytest.raises(RuntimeError) as excinfo: cm.register_nonlocal_map2() assert ( str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!' ) def test_mixed_local_global(): """Local types take precedence over globally registered types: a module with a `module_local` type can be registered even if the type is already registered globally. With the module, casting will go to the local type; outside the module casting goes to the global type. """ import pybind11_cross_module_tests as cm m.register_mixed_global() m.register_mixed_local() a = [] a.append(m.MixedGlobalLocal(1)) a.append(m.MixedLocalGlobal(2)) a.append(m.get_mixed_gl(3)) a.append(m.get_mixed_lg(4)) assert [x.get() for x in a] == [101, 1002, 103, 1004] cm.register_mixed_global_local() cm.register_mixed_local_global() a.append(m.MixedGlobalLocal(5)) a.append(m.MixedLocalGlobal(6)) a.append(cm.MixedGlobalLocal(7)) a.append(cm.MixedLocalGlobal(8)) a.append(m.get_mixed_gl(9)) a.append(m.get_mixed_lg(10)) a.append(cm.get_mixed_gl(11)) a.append(cm.get_mixed_lg(12)) assert [x.get() for x in a] == [ 101, 1002, 103, 1004, 105, 1006, 207, 2008, 109, 1010, 211, 2012, ] def test_internal_locals_differ(): """Makes sure the internal local type map differs across the two modules""" import pybind11_cross_module_tests as cm assert m.local_cpp_types_addr() != cm.local_cpp_types_addr() @pytest.mark.xfail("env.PYPY and sys.pypy_version_info < (7, 3, 2)") def test_stl_caster_vs_stl_bind(msg): """One module uses a generic vector caster from `` while the other exports `std::vector` via `py:bind_vector` and `py::module_local`""" import pybind11_cross_module_tests as cm v1 = cm.VectorInt([1, 2, 3]) assert m.load_vector_via_caster(v1) == 6 assert cm.load_vector_via_binding(v1) == 6 v2 = [1, 2, 3] assert m.load_vector_via_caster(v2) == 6 with pytest.raises(TypeError) as excinfo: cm.load_vector_via_binding(v2) assert ( msg(excinfo.value) == """ load_vector_via_binding(): incompatible function arguments. The following argument types are supported: 1. (arg0: pybind11_cross_module_tests.VectorInt) -> int Invoked with: [1, 2, 3] """ ) def test_cross_module_calls(): import pybind11_cross_module_tests as cm v1 = m.LocalVec() v1.append(m.LocalType(1)) v2 = cm.LocalVec() v2.append(cm.LocalType(2)) # Returning the self pointer should get picked up as returning an existing # instance (even when that instance is of a foreign, non-local type). assert m.return_self(v1) is v1 assert cm.return_self(v2) is v2 assert m.return_self(v2) is v2 assert cm.return_self(v1) is v1 assert m.LocalVec is not cm.LocalVec # Returning a copy, on the other hand, always goes to the local type, # regardless of where the source type came from. assert type(m.return_copy(v1)) is m.LocalVec assert type(m.return_copy(v2)) is m.LocalVec assert type(cm.return_copy(v1)) is cm.LocalVec assert type(cm.return_copy(v2)) is cm.LocalVec # Test the example given in the documentation (which also tests inheritance casting): mycat = m.Cat("Fluffy") mydog = cm.Dog("Rover") assert mycat.get_name() == "Fluffy" assert mydog.name() == "Rover" assert m.Cat.__base__.__name__ == "Pet" assert cm.Dog.__base__.__name__ == "Pet" assert m.Cat.__base__ is not cm.Dog.__base__ assert m.pet_name(mycat) == "Fluffy" assert m.pet_name(mydog) == "Rover" assert cm.pet_name(mycat) == "Fluffy" assert cm.pet_name(mydog) == "Rover" assert m.MixGL is not cm.MixGL a = m.MixGL(1) b = cm.MixGL(2) assert m.get_gl_value(a) == 11 assert m.get_gl_value(b) == 12 assert cm.get_gl_value(a) == 101 assert cm.get_gl_value(b) == 102 c, d = m.MixGL2(3), cm.MixGL2(4) with pytest.raises(TypeError) as excinfo: m.get_gl_value(c) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.get_gl_value(d) assert "incompatible function arguments" in str(excinfo.value) aoflagger-v3.4.0/external/pybind11/tests/test_builtin_casters.cpp0000644000175000017500000003723114507760431023706 0ustar olesoles/* tests/test_builtin_casters.cpp -- Casters available without any additional headers Copyright (c) 2017 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "pybind11_tests.h" struct ConstRefCasted { int tag; }; PYBIND11_NAMESPACE_BEGIN(pybind11) PYBIND11_NAMESPACE_BEGIN(detail) template <> class type_caster { public: static constexpr auto name = const_name(); // Input is unimportant, a new value will always be constructed based on the // cast operator. bool load(handle, bool) { return true; } explicit operator ConstRefCasted &&() { value = {1}; // NOLINTNEXTLINE(performance-move-const-arg) return std::move(value); } explicit operator ConstRefCasted &() { value = {2}; return value; } explicit operator ConstRefCasted *() { value = {3}; return &value; } explicit operator const ConstRefCasted &() { value = {4}; return value; } explicit operator const ConstRefCasted *() { value = {5}; return &value; } // custom cast_op to explicitly propagate types to the conversion operators. template using cast_op_type = /// const conditional_t< std::is_same, const ConstRefCasted *>::value, const ConstRefCasted *, conditional_t< std::is_same::value, const ConstRefCasted &, /// non-const conditional_t, ConstRefCasted *>::value, ConstRefCasted *, conditional_t::value, ConstRefCasted &, /* else */ ConstRefCasted &&>>>>; private: ConstRefCasted value = {0}; }; PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(pybind11) TEST_SUBMODULE(builtin_casters, m) { PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_MSVC(4127) // test_simple_string m.def("string_roundtrip", [](const char *s) { return s; }); // test_unicode_conversion // Some test characters in utf16 and utf32 encodings. The last one (the ð€) contains a null // byte char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*ð€*/; char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00; std::wstring wstr; wstr.push_back(0x61); // a wstr.push_back(0x2e18); // ⸘ if (sizeof(wchar_t) == 2) { wstr.push_back(mathbfA16_1); wstr.push_back(mathbfA16_2); } // ð€, utf16 else { wstr.push_back((wchar_t) mathbfA32); } // ð€, utf32 wstr.push_back(0x7a); // z m.def("good_utf8_string", []() { return std::string((const char *) u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 ð€ m.def("good_utf16_string", [=]() { return std::u16string({b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16}); }); // b‽🎂ð€z m.def("good_utf32_string", [=]() { return std::u32string({a32, mathbfA32, cake32, ib32, z32}); }); // að€ðŸŽ‚‽z m.def("good_wchar_string", [=]() { return wstr; }); // a‽ð€z m.def("bad_utf8_string", []() { return std::string("abc\xd0" "def"); }); m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); }); // Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger // UnicodeDecodeError m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); }); if (sizeof(wchar_t) == 2) { m.def("bad_wchar_string", [=]() { return std::wstring({wchar_t(0x61), wchar_t(0xd800)}); }); } m.def("u8_Z", []() -> char { return 'Z'; }); m.def("u8_eacute", []() -> char { return '\xe9'; }); m.def("u16_ibang", [=]() -> char16_t { return ib16; }); m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; }); m.def("wchar_heart", []() -> wchar_t { return 0x2665; }); // test_single_char_arguments m.attr("wchar_size") = py::cast(sizeof(wchar_t)); m.def("ord_char", [](char c) -> int { return static_cast(c); }); m.def("ord_char_lv", [](char &c) -> int { return static_cast(c); }); m.def("ord_char16", [](char16_t c) -> uint16_t { return c; }); m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; }); m.def("ord_char32", [](char32_t c) -> uint32_t { return c; }); m.def("ord_wchar", [](wchar_t c) -> int { return c; }); // test_bytes_to_string m.def("strlen", [](char *s) { return strlen(s); }); m.def("string_length", [](const std::string &s) { return s.length(); }); #ifdef PYBIND11_HAS_U8STRING m.attr("has_u8string") = true; m.def("good_utf8_u8string", []() { return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 ð€ m.def("bad_utf8_u8string", []() { return std::u8string((const char8_t *) "abc\xd0" "def"); }); m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; }); // test_single_char_arguments m.def("ord_char8", [](char8_t c) -> int { return static_cast(c); }); m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast(c); }); #endif // test_string_view #ifdef PYBIND11_HAS_STRING_VIEW m.attr("has_string_view") = true; m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); }); m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); }); m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); }); m.def("string_view_chars", [](std::string_view s) { py::list l; for (auto c : s) { l.append((std::uint8_t) c); } return l; }); m.def("string_view16_chars", [](std::u16string_view s) { py::list l; for (auto c : s) { l.append((int) c); } return l; }); m.def("string_view32_chars", [](std::u32string_view s) { py::list l; for (auto c : s) { l.append((int) c); } return l; }); m.def("string_view_return", []() { return std::string_view((const char *) u8"utf8 secret \U0001f382"); }); m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); }); m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); }); // The inner lambdas here are to also test implicit conversion using namespace std::literals; m.def("string_view_bytes", []() { return [](py::bytes b) { return b; }("abc \x80\x80 def"sv); }); m.def("string_view_str", []() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); }); m.def("string_view_from_bytes", [](const py::bytes &b) { return [](std::string_view s) { return s; }(b); }); m.def("string_view_memoryview", []() { static constexpr auto val = "Have some \360\237\216\202"sv; return py::memoryview::from_memory(val); }); # ifdef PYBIND11_HAS_U8STRING m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); }); m.def("string_view8_chars", [](std::u8string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; }); m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); }); m.def("string_view8_str", []() { return py::str{std::u8string_view{u8"abc ‽ def"}}; }); # endif struct TypeWithBothOperatorStringAndStringView { // NOLINTNEXTLINE(google-explicit-constructor) operator std::string() const { return "success"; } // NOLINTNEXTLINE(google-explicit-constructor) operator std::string_view() const { return "failure"; } }; m.def("bytes_from_type_with_both_operator_string_and_string_view", []() { return py::bytes(TypeWithBothOperatorStringAndStringView()); }); m.def("str_from_type_with_both_operator_string_and_string_view", []() { return py::str(TypeWithBothOperatorStringAndStringView()); }); #endif // test_integer_casting m.def("i32_str", [](std::int32_t v) { return std::to_string(v); }); m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); }); m.def("i64_str", [](std::int64_t v) { return std::to_string(v); }); m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); }); // test_int_convert m.def("int_passthrough", [](int arg) { return arg; }); m.def( "int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert()); // test_tuple m.def( "pair_passthrough", [](const std::pair &input) { return std::make_pair(input.second, input.first); }, "Return a pair in reversed order"); m.def( "tuple_passthrough", [](std::tuple input) { return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input)); }, "Return a triple in reversed order"); m.def("empty_tuple", []() { return std::tuple<>(); }); static std::pair lvpair; static std::tuple lvtuple; static std::pair>> lvnested; m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); }); m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; }); m.def("rvalue_tuple", []() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); }); m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; }); m.def("rvalue_nested", []() { return std::make_pair( RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); }); m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; }); m.def( "int_string_pair", []() { // Using no-destructor idiom to side-step warnings from overzealous compilers. static auto *int_string_pair = new std::pair{2, "items"}; return int_string_pair; }, py::return_value_policy::reference); // test_builtins_cast_return_none m.def("return_none_string", []() -> std::string * { return nullptr; }); m.def("return_none_char", []() -> const char * { return nullptr; }); m.def("return_none_bool", []() -> bool * { return nullptr; }); m.def("return_none_int", []() -> int * { return nullptr; }); m.def("return_none_float", []() -> float * { return nullptr; }); m.def("return_none_pair", []() -> std::pair * { return nullptr; }); // test_none_deferred m.def("defer_none_cstring", [](char *) { return false; }); m.def("defer_none_cstring", [](const py::none &) { return true; }); m.def("defer_none_custom", [](UserType *) { return false; }); m.def("defer_none_custom", [](const py::none &) { return true; }); m.def("nodefer_none_void", [](void *) { return true; }); m.def("nodefer_none_void", [](const py::none &) { return false; }); // test_void_caster m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile m.def("cast_nullptr_t", []() { return std::nullptr_t{}; }); // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // test_bool_caster m.def("bool_passthrough", [](bool arg) { return arg; }); m.def( "bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert()); // TODO: This should be disabled and fixed in future Intel compilers #if !defined(__INTEL_COMPILER) // Test "bool_passthrough_noconvert" again, but using () instead of {} to construct py::arg // When compiled with the Intel compiler, this results in segmentation faults when importing // the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when // a newer version of icc is available. m.def( "bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert()); #endif // test_reference_wrapper m.def("refwrap_builtin", [](std::reference_wrapper p) { return 10 * p.get(); }); m.def("refwrap_usertype", [](std::reference_wrapper p) { return p.get().value(); }); m.def("refwrap_usertype_const", [](std::reference_wrapper p) { return p.get().value(); }); m.def("refwrap_lvalue", []() -> std::reference_wrapper { static UserType x(1); return std::ref(x); }); m.def("refwrap_lvalue_const", []() -> std::reference_wrapper { static UserType x(1); return std::cref(x); }); // Not currently supported (std::pair caster has return-by-value cast operator); // triggers static_assert failure. // m.def("refwrap_pair", [](std::reference_wrapper>) { }); m.def( "refwrap_list", [](bool copy) { static IncType x1(1), x2(2); py::list l; for (const auto &f : {std::ref(x1), std::ref(x2)}) { l.append(py::cast( f, copy ? py::return_value_policy::copy : py::return_value_policy::reference)); } return l; }, "copy"_a); m.def("refwrap_iiw", [](const IncType &w) { return w.value(); }); m.def("refwrap_call_iiw", [](IncType &w, const py::function &f) { py::list l; l.append(f(std::ref(w))); l.append(f(std::cref(w))); IncType x(w.value()); l.append(f(std::ref(x))); IncType y(w.value()); auto r3 = std::ref(y); l.append(f(r3)); return l; }); // test_complex m.def("complex_cast", [](float x) { return "{}"_s.format(x); }); m.def("complex_cast", [](std::complex x) { return "({}, {})"_s.format(x.real(), x.imag()); }); // test int vs. long (Python 2) m.def("int_cast", []() { return (int) 42; }); m.def("long_cast", []() { return (long) 42; }); m.def("longlong_cast", []() { return ULLONG_MAX; }); /// test void* cast operator m.def("test_void_caster", []() -> bool { void *v = (void *) 0xabcd; py::object o = py::cast(v); return py::cast(o) == v; }); // Tests const/non-const propagation in cast_op. m.def("takes", [](ConstRefCasted x) { return x.tag; }); m.def("takes_move", [](ConstRefCasted &&x) { return x.tag; }); m.def("takes_ptr", [](ConstRefCasted *x) { return x->tag; }); m.def("takes_ref", [](ConstRefCasted &x) { return x.tag; }); m.def("takes_ref_wrap", [](std::reference_wrapper x) { return x.get().tag; }); m.def("takes_const_ptr", [](const ConstRefCasted *x) { return x->tag; }); m.def("takes_const_ref", [](const ConstRefCasted &x) { return x.tag; }); m.def("takes_const_ref_wrap", [](std::reference_wrapper x) { return x.get().tag; }); PYBIND11_WARNING_POP } aoflagger-v3.4.0/external/pybind11/tests/pybind11_tests.h0000644000175000017500000000517514507760431021775 0ustar olesoles#pragma once #include #include namespace py = pybind11; using namespace pybind11::literals; class test_initializer { using Initializer = void (*)(py::module_ &); public: explicit test_initializer(Initializer init); test_initializer(const char *submodule_name, Initializer init); }; #define TEST_SUBMODULE(name, variable) \ void test_submodule_##name(py::module_ &); \ test_initializer name(#name, test_submodule_##name); \ void test_submodule_##name(py::module_ &(variable)) /// Dummy type which is not exported anywhere -- something to trigger a conversion error struct UnregisteredType {}; /// A user-defined type which is exported and can be used by any test class UserType { public: UserType() = default; explicit UserType(int i) : i(i) {} int value() const { return i; } void set(int set) { i = set; } private: int i = -1; }; /// Like UserType, but increments `value` on copy for quick reference vs. copy tests class IncType : public UserType { public: using UserType::UserType; IncType() = default; IncType(const IncType &other) : IncType(other.value() + 1) {} IncType(IncType &&) = delete; IncType &operator=(const IncType &) = delete; IncType &operator=(IncType &&) = delete; }; /// A simple union for basic testing union IntFloat { int i; float f; }; /// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast /// context. Used to test recursive casters (e.g. std::tuple, stl containers). struct RValueCaster {}; PYBIND11_NAMESPACE_BEGIN(pybind11) PYBIND11_NAMESPACE_BEGIN(detail) template <> class type_caster { public: PYBIND11_TYPE_CASTER(RValueCaster, const_name("RValueCaster")); static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); } static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); } }; PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(pybind11) template void ignoreOldStyleInitWarnings(F &&body) { py::exec(R"( message = "pybind11-bound class '.+' is using an old-style placement-new '(?:__init__|__setstate__)' which has been deprecated" import warnings with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=message, category=FutureWarning) body() )", py::dict(py::arg("body") = py::cpp_function(body))); } aoflagger-v3.4.0/external/pybind11/tests/object.h0000644000175000017500000001315714507760431020371 0ustar olesoles#if !defined(__OBJECT_H) # define __OBJECT_H # include "constructor_stats.h" # include /// Reference counted object base class class Object { public: /// Default constructor Object() { print_default_created(this); } /// Copy constructor Object(const Object &) : m_refCount(0) { print_copy_created(this); } /// Return the current reference count int getRefCount() const { return m_refCount; }; /// Increase the object's reference count by one void incRef() const { ++m_refCount; } /** \brief Decrease the reference count of * the object and possibly deallocate it. * * The object will automatically be deallocated once * the reference count reaches zero. */ void decRef(bool dealloc = true) const { --m_refCount; if (m_refCount == 0 && dealloc) { delete this; } else if (m_refCount < 0) { throw std::runtime_error("Internal error: reference count < 0!"); } } virtual std::string toString() const = 0; protected: /** \brief Virtual protected deconstructor. * (Will only be called by \ref ref) */ virtual ~Object() { print_destroyed(this); } private: mutable std::atomic m_refCount{0}; }; // Tag class used to track constructions of ref objects. When we track constructors, below, we // track and print out the actual class (e.g. ref), and *also* add a fake tracker for // ref_tag. This lets us check that the total number of ref constructors/destructors is // correct without having to check each individual ref type individually. class ref_tag {}; /** * \brief Reference counting helper * * The \a ref refeference template is a simple wrapper to store a * pointer to an object. It takes care of increasing and decreasing * the reference count of the object. When the last reference goes * out of scope, the associated object will be deallocated. * * \ingroup libcore */ template class ref { public: /// Create a nullptr reference ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag *) this); } /// Construct a reference from a pointer explicit ref(T *ptr) : m_ptr(ptr) { if (m_ptr) { ((Object *) m_ptr)->incRef(); } print_created(this, "from pointer", m_ptr); track_created((ref_tag *) this, "from pointer"); } /// Copy constructor ref(const ref &r) : m_ptr(r.m_ptr) { if (m_ptr) { ((Object *) m_ptr)->incRef(); } print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag *) this); } /// Move constructor ref(ref &&r) noexcept : m_ptr(r.m_ptr) { r.m_ptr = nullptr; print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag *) this); } /// Destroy this reference ~ref() { if (m_ptr) { ((Object *) m_ptr)->decRef(); } print_destroyed(this); track_destroyed((ref_tag *) this); } /// Move another reference into the current one ref &operator=(ref &&r) noexcept { print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag *) this); if (*this == r) { return *this; } if (m_ptr) { ((Object *) m_ptr)->decRef(); } m_ptr = r.m_ptr; r.m_ptr = nullptr; return *this; } /// Overwrite this reference with another reference ref &operator=(const ref &r) { if (this == &r) { return *this; } print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag *) this); if (m_ptr == r.m_ptr) { return *this; } if (m_ptr) { ((Object *) m_ptr)->decRef(); } m_ptr = r.m_ptr; if (m_ptr) { ((Object *) m_ptr)->incRef(); } return *this; } /// Overwrite this reference with a pointer to another object ref &operator=(T *ptr) { print_values(this, "assigned pointer"); track_values((ref_tag *) this, "assigned pointer"); if (m_ptr == ptr) { return *this; } if (m_ptr) { ((Object *) m_ptr)->decRef(); } m_ptr = ptr; if (m_ptr) { ((Object *) m_ptr)->incRef(); } return *this; } /// Compare this reference with another reference bool operator==(const ref &r) const { return m_ptr == r.m_ptr; } /// Compare this reference with another reference bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; } /// Compare this reference with a pointer bool operator==(const T *ptr) const { return m_ptr == ptr; } /// Compare this reference with a pointer bool operator!=(const T *ptr) const { return m_ptr != ptr; } /// Access the object referenced by this reference T *operator->() { return m_ptr; } /// Access the object referenced by this reference const T *operator->() const { return m_ptr; } /// Return a C++ reference to the referenced object T &operator*() { return *m_ptr; } /// Return a const C++ reference to the referenced object const T &operator*() const { return *m_ptr; } /// Return a pointer to the referenced object explicit operator T *() { return m_ptr; } /// Return a const pointer to the referenced object T *get_ptr() { return m_ptr; } /// Return a pointer to the referenced object const T *get_ptr() const { return m_ptr; } private: T *m_ptr; }; #endif /* __OBJECT_H */ aoflagger-v3.4.0/external/pybind11/tests/test_thread.py0000644000175000017500000000147214507760431021627 0ustar olesolesimport threading from pybind11_tests import thread as m class Thread(threading.Thread): def __init__(self, fn): super().__init__() self.fn = fn self.e = None def run(self): try: for i in range(10): self.fn(i, i) except Exception as e: self.e = e def join(self): super().join() if self.e: raise self.e def test_implicit_conversion(): a = Thread(m.test) b = Thread(m.test) c = Thread(m.test) for x in [a, b, c]: x.start() for x in [c, b, a]: x.join() def test_implicit_conversion_no_gil(): a = Thread(m.test_no_gil) b = Thread(m.test_no_gil) c = Thread(m.test_no_gil) for x in [a, b, c]: x.start() for x in [c, b, a]: x.join() aoflagger-v3.4.0/external/pybind11/tests/test_eigen_tensor.py0000644000175000017500000002230614507760431023040 0ustar olesolesimport sys import pytest np = pytest.importorskip("numpy") eigen_tensor = pytest.importorskip("pybind11_tests.eigen_tensor") submodules = [eigen_tensor.c_style, eigen_tensor.f_style] try: import eigen_tensor_avoid_stl_array as avoid submodules += [avoid.c_style, avoid.f_style] except ImportError as e: # Ensure config, build, toolchain, etc. issues are not masked here: msg = ( "import eigen_tensor_avoid_stl_array FAILED, while " "import pybind11_tests.eigen_tensor succeeded. " "Please ensure that " "test_eigen_tensor.cpp & " "eigen_tensor_avoid_stl_array.cpp " "are built together (or both are not built if Eigen is not available)." ) raise RuntimeError(msg) from e tensor_ref = np.empty((3, 5, 2), dtype=np.int64) for i in range(tensor_ref.shape[0]): for j in range(tensor_ref.shape[1]): for k in range(tensor_ref.shape[2]): tensor_ref[i, j, k] = i * (5 * 2) + j * 2 + k indices = (2, 3, 1) @pytest.fixture(autouse=True) def cleanup(): for module in submodules: module.setup() yield for module in submodules: assert module.is_ok() def test_import_avoid_stl_array(): pytest.importorskip("eigen_tensor_avoid_stl_array") assert len(submodules) == 4 def assert_equal_tensor_ref(mat, writeable=True, modified=None): assert mat.flags.writeable == writeable copy = np.array(tensor_ref) if modified is not None: copy[indices] = modified np.testing.assert_array_equal(mat, copy) @pytest.mark.parametrize("m", submodules) @pytest.mark.parametrize("member_name", ["member", "member_view"]) def test_reference_internal(m, member_name): if not hasattr(sys, "getrefcount"): pytest.skip("No reference counting") foo = m.CustomExample() counts = sys.getrefcount(foo) mem = getattr(foo, member_name) assert_equal_tensor_ref(mem, writeable=False) new_counts = sys.getrefcount(foo) assert new_counts == counts + 1 assert_equal_tensor_ref(mem, writeable=False) del mem assert sys.getrefcount(foo) == counts assert_equal_funcs = [ "copy_tensor", "copy_fixed_tensor", "copy_const_tensor", "move_tensor_copy", "move_fixed_tensor_copy", "take_tensor", "take_fixed_tensor", "reference_tensor", "reference_tensor_v2", "reference_fixed_tensor", "reference_view_of_tensor", "reference_view_of_tensor_v3", "reference_view_of_tensor_v5", "reference_view_of_fixed_tensor", ] assert_equal_const_funcs = [ "reference_view_of_tensor_v2", "reference_view_of_tensor_v4", "reference_view_of_tensor_v6", "reference_const_tensor", "reference_const_tensor_v2", ] @pytest.mark.parametrize("m", submodules) @pytest.mark.parametrize("func_name", assert_equal_funcs + assert_equal_const_funcs) def test_convert_tensor_to_py(m, func_name): writeable = func_name in assert_equal_funcs assert_equal_tensor_ref(getattr(m, func_name)(), writeable=writeable) @pytest.mark.parametrize("m", submodules) def test_bad_cpp_to_python_casts(m): with pytest.raises( RuntimeError, match="Cannot use reference internal when there is no parent" ): m.reference_tensor_internal() with pytest.raises(RuntimeError, match="Cannot move from a constant reference"): m.move_const_tensor() with pytest.raises( RuntimeError, match="Cannot take ownership of a const reference" ): m.take_const_tensor() with pytest.raises( RuntimeError, match="Invalid return_value_policy for Eigen Map type, must be either reference or reference_internal", ): m.take_view_tensor() @pytest.mark.parametrize("m", submodules) def test_bad_python_to_cpp_casts(m): with pytest.raises( TypeError, match=r"^round_trip_tensor\(\): incompatible function arguments" ): m.round_trip_tensor(np.zeros((2, 3))) with pytest.raises(TypeError, match=r"^Cannot cast array data from dtype"): m.round_trip_tensor(np.zeros(dtype=np.str_, shape=(2, 3, 1))) with pytest.raises( TypeError, match=r"^round_trip_tensor_noconvert\(\): incompatible function arguments", ): m.round_trip_tensor_noconvert(tensor_ref) assert_equal_tensor_ref( m.round_trip_tensor_noconvert(tensor_ref.astype(np.float64)) ) bad_options = "C" if m.needed_options == "F" else "F" # Shape, dtype and the order need to be correct for a TensorMap cast with pytest.raises( TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" ): m.round_trip_view_tensor( np.zeros((3, 5, 2), dtype=np.float64, order=bad_options) ) with pytest.raises( TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" ): m.round_trip_view_tensor( np.zeros((3, 5, 2), dtype=np.float32, order=m.needed_options) ) with pytest.raises( TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" ): m.round_trip_view_tensor( np.zeros((3, 5), dtype=np.float64, order=m.needed_options) ) temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options) with pytest.raises( TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" ): m.round_trip_view_tensor( temp[:, ::-1, :], ) temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options) temp.setflags(write=False) with pytest.raises( TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" ): m.round_trip_view_tensor(temp) @pytest.mark.parametrize("m", submodules) def test_references_actually_refer(m): a = m.reference_tensor() temp = a[indices] a[indices] = 100 assert_equal_tensor_ref(m.copy_const_tensor(), modified=100) a[indices] = temp assert_equal_tensor_ref(m.copy_const_tensor()) a = m.reference_view_of_tensor() a[indices] = 100 assert_equal_tensor_ref(m.copy_const_tensor(), modified=100) a[indices] = temp assert_equal_tensor_ref(m.copy_const_tensor()) @pytest.mark.parametrize("m", submodules) def test_round_trip(m): assert_equal_tensor_ref(m.round_trip_tensor(tensor_ref)) with pytest.raises(TypeError, match="^Cannot cast array data from"): assert_equal_tensor_ref(m.round_trip_tensor2(tensor_ref)) assert_equal_tensor_ref(m.round_trip_tensor2(np.array(tensor_ref, dtype=np.int32))) assert_equal_tensor_ref(m.round_trip_fixed_tensor(tensor_ref)) assert_equal_tensor_ref(m.round_trip_aligned_view_tensor(m.reference_tensor())) copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options) assert_equal_tensor_ref(m.round_trip_view_tensor(copy)) assert_equal_tensor_ref(m.round_trip_view_tensor_ref(copy)) assert_equal_tensor_ref(m.round_trip_view_tensor_ptr(copy)) copy.setflags(write=False) assert_equal_tensor_ref(m.round_trip_const_view_tensor(copy)) np.testing.assert_array_equal( tensor_ref[:, ::-1, :], m.round_trip_tensor(tensor_ref[:, ::-1, :]) ) assert m.round_trip_rank_0(np.float64(3.5)) == 3.5 assert m.round_trip_rank_0(3.5) == 3.5 with pytest.raises( TypeError, match=r"^round_trip_rank_0_noconvert\(\): incompatible function arguments", ): m.round_trip_rank_0_noconvert(np.float64(3.5)) with pytest.raises( TypeError, match=r"^round_trip_rank_0_noconvert\(\): incompatible function arguments", ): m.round_trip_rank_0_noconvert(3.5) with pytest.raises( TypeError, match=r"^round_trip_rank_0_view\(\): incompatible function arguments" ): m.round_trip_rank_0_view(np.float64(3.5)) with pytest.raises( TypeError, match=r"^round_trip_rank_0_view\(\): incompatible function arguments" ): m.round_trip_rank_0_view(3.5) @pytest.mark.parametrize("m", submodules) def test_round_trip_references_actually_refer(m): # Need to create a copy that matches the type on the C side copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options) a = m.round_trip_view_tensor(copy) temp = a[indices] a[indices] = 100 assert_equal_tensor_ref(copy, modified=100) a[indices] = temp assert_equal_tensor_ref(copy) @pytest.mark.parametrize("m", submodules) def test_doc_string(m, doc): assert ( doc(m.copy_tensor) == "copy_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]" ) assert ( doc(m.copy_fixed_tensor) == "copy_fixed_tensor() -> numpy.ndarray[numpy.float64[3, 5, 2]]" ) assert ( doc(m.reference_const_tensor) == "reference_const_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]" ) order_flag = f"flags.{m.needed_options.lower()}_contiguous" assert doc(m.round_trip_view_tensor) == ( f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])" f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]" ) assert doc(m.round_trip_const_view_tensor) == ( f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])" " -> numpy.ndarray[numpy.float64[?, ?, ?]]" ) aoflagger-v3.4.0/external/pybind11/tests/test_tagbased_polymorphic.cpp0000644000175000017500000001101114507760431024677 0ustar olesoles/* tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook Copyright (c) 2018 Hudson River Trading LLC All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "pybind11_tests.h" struct Animal { // Make this type also a "standard" polymorphic type, to confirm that // specializing polymorphic_type_hook using enable_if_t still works // (https://github.com/pybind/pybind11/pull/2016/). virtual ~Animal() = default; // Enum for tag-based polymorphism. enum class Kind { Unknown = 0, Dog = 100, Labrador, Chihuahua, LastDog = 199, Cat = 200, Panther, LastCat = 299 }; static const std::type_info *type_of_kind(Kind kind); static std::string name_of_kind(Kind kind); const Kind kind; const std::string name; protected: Animal(const std::string &_name, Kind _kind) : kind(_kind), name(_name) {} }; struct Dog : Animal { explicit Dog(const std::string &_name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {} std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; } std::string sound = "WOOF!"; }; struct Labrador : Dog { explicit Labrador(const std::string &_name, int _excitement = 9001) : Dog(_name, Kind::Labrador), excitement(_excitement) {} int excitement; }; struct Chihuahua : Dog { explicit Chihuahua(const std::string &_name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; } std::string bark() const { return Dog::bark() + " and runs in circles"; } }; struct Cat : Animal { explicit Cat(const std::string &_name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {} std::string purr() const { return "mrowr"; } }; struct Panther : Cat { explicit Panther(const std::string &_name) : Cat(_name, Kind::Panther) {} std::string purr() const { return "mrrrRRRRRR"; } }; std::vector> create_zoo() { std::vector> ret; ret.emplace_back(new Labrador("Fido", 15000)); // simulate some new type of Dog that the Python bindings // haven't been updated for; it should still be considered // a Dog, not just an Animal. ret.emplace_back(new Dog("Ginger", Dog::Kind(150))); ret.emplace_back(new Chihuahua("Hertzl")); ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat)); ret.emplace_back(new Panther("Leo")); return ret; } const std::type_info *Animal::type_of_kind(Kind kind) { switch (kind) { case Kind::Unknown: case Kind::Dog: break; case Kind::Labrador: return &typeid(Labrador); case Kind::Chihuahua: return &typeid(Chihuahua); case Kind::LastDog: case Kind::Cat: break; case Kind::Panther: return &typeid(Panther); case Kind::LastCat: break; } if (kind >= Kind::Dog && kind <= Kind::LastDog) { return &typeid(Dog); } if (kind >= Kind::Cat && kind <= Kind::LastCat) { return &typeid(Cat); } return nullptr; } std::string Animal::name_of_kind(Kind kind) { std::string raw_name = type_of_kind(kind)->name(); py::detail::clean_type_id(raw_name); return raw_name; } namespace PYBIND11_NAMESPACE { template struct polymorphic_type_hook::value>> { static const void *get(const itype *src, const std::type_info *&type) { type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; } }; } // namespace PYBIND11_NAMESPACE TEST_SUBMODULE(tagbased_polymorphic, m) { py::class_(m, "Animal").def_readonly("name", &Animal::name); py::class_(m, "Dog") .def(py::init()) .def_readwrite("sound", &Dog::sound) .def("bark", &Dog::bark); py::class_(m, "Labrador") .def(py::init(), "name"_a, "excitement"_a = 9001) .def_readwrite("excitement", &Labrador::excitement); py::class_(m, "Chihuahua") .def(py::init()) .def("bark", &Chihuahua::bark); py::class_(m, "Cat").def(py::init()).def("purr", &Cat::purr); py::class_(m, "Panther") .def(py::init()) .def("purr", &Panther::purr); m.def("create_zoo", &create_zoo); }; aoflagger-v3.4.0/external/pybind11/tests/test_exceptions.cpp0000644000175000017500000002746214507760431022702 0ustar olesoles/* tests/test_custom-exceptions.cpp -- exception translation Copyright (c) 2016 Pim Schellart All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "test_exceptions.h" #include "local_bindings.h" #include "pybind11_tests.h" #include #include #include // A type that should be raised as an exception in Python class MyException : public std::exception { public: explicit MyException(const char *m) : message{m} {} const char *what() const noexcept override { return message.c_str(); } private: std::string message = ""; }; // A type that should be translated to a standard Python exception class MyException2 : public std::exception { public: explicit MyException2(const char *m) : message{m} {} const char *what() const noexcept override { return message.c_str(); } private: std::string message = ""; }; // A type that is not derived from std::exception (and is thus unknown) class MyException3 { public: explicit MyException3(const char *m) : message{m} {} virtual const char *what() const noexcept { return message.c_str(); } // Rule of 5 BEGIN: to preempt compiler warnings. MyException3(const MyException3 &) = default; MyException3(MyException3 &&) = default; MyException3 &operator=(const MyException3 &) = default; MyException3 &operator=(MyException3 &&) = default; virtual ~MyException3() = default; // Rule of 5 END. private: std::string message = ""; }; // A type that should be translated to MyException // and delegated to its exception translator class MyException4 : public std::exception { public: explicit MyException4(const char *m) : message{m} {} const char *what() const noexcept override { return message.c_str(); } private: std::string message = ""; }; // Like the above, but declared via the helper function class MyException5 : public std::logic_error { public: explicit MyException5(const std::string &what) : std::logic_error(what) {} }; // Inherits from MyException5 class MyException5_1 : public MyException5 { using MyException5::MyException5; }; // Exception that will be caught via the module local translator. class MyException6 : public std::exception { public: explicit MyException6(const char *m) : message{m} {} const char *what() const noexcept override { return message.c_str(); } private: std::string message = ""; }; struct PythonCallInDestructor { explicit PythonCallInDestructor(const py::dict &d) : d(d) {} ~PythonCallInDestructor() { d["good"] = true; } py::dict d; }; struct PythonAlreadySetInDestructor { explicit PythonAlreadySetInDestructor(const py::str &s) : s(s) {} ~PythonAlreadySetInDestructor() { py::dict foo; try { // Assign to a py::object to force read access of nonexistent dict entry py::object o = foo["bar"]; } catch (py::error_already_set &ex) { ex.discard_as_unraisable(s); } } py::str s; }; TEST_SUBMODULE(exceptions, m) { m.def("throw_std_exception", []() { throw std::runtime_error("This exception was intentionally thrown."); }); // make a new custom exception and use it as a translation target static py::exception ex(m, "MyException"); py::register_exception_translator([](std::exception_ptr p) { try { if (p) { std::rethrow_exception(p); } } catch (const MyException &e) { // Set MyException as the active python error ex(e.what()); } }); // register new translator for MyException2 // no need to store anything here because this type will // never by visible from Python py::register_exception_translator([](std::exception_ptr p) { try { if (p) { std::rethrow_exception(p); } } catch (const MyException2 &e) { // Translate this exception to a standard RuntimeError PyErr_SetString(PyExc_RuntimeError, e.what()); } }); // register new translator for MyException4 // which will catch it and delegate to the previously registered // translator for MyException by throwing a new exception py::register_exception_translator([](std::exception_ptr p) { try { if (p) { std::rethrow_exception(p); } } catch (const MyException4 &e) { throw MyException(e.what()); } }); // A simple exception translation: auto ex5 = py::register_exception(m, "MyException5"); // A slightly more complicated one that declares MyException5_1 as a subclass of MyException5 py::register_exception(m, "MyException5_1", ex5.ptr()); // py::register_local_exception(m, "LocalSimpleException") py::register_local_exception_translator([](std::exception_ptr p) { try { if (p) { std::rethrow_exception(p); } } catch (const MyException6 &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); } }); m.def("throws1", []() { throw MyException("this error should go to a custom type"); }); m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); }); m.def("throws3", []() { throw MyException3("this error cannot be translated"); }); m.def("throws4", []() { throw MyException4("this error is rethrown"); }); m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); }); m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); }); m.def("throws6", []() { throw MyException6("MyException6 only handled in this module"); }); m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); }); m.def("throws_overflow_error", []() { throw std::overflow_error(""); }); m.def("throws_local_error", []() { throw LocalException("never caught"); }); m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); }); m.def("exception_matches", []() { py::dict foo; try { // Assign to a py::object to force read access of nonexistent dict entry py::object o = foo["bar"]; } catch (py::error_already_set &ex) { if (!ex.matches(PyExc_KeyError)) { throw; } return true; } return false; }); m.def("exception_matches_base", []() { py::dict foo; try { // Assign to a py::object to force read access of nonexistent dict entry py::object o = foo["bar"]; } catch (py::error_already_set &ex) { if (!ex.matches(PyExc_Exception)) { throw; } return true; } return false; }); m.def("modulenotfound_exception_matches_base", []() { try { // On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError py::module_::import("nonexistent"); } catch (py::error_already_set &ex) { if (!ex.matches(PyExc_ImportError)) { throw; } return true; } return false; }); m.def("throw_already_set", [](bool err) { if (err) { PyErr_SetString(PyExc_ValueError, "foo"); } try { throw py::error_already_set(); } catch (const std::runtime_error &e) { if ((err && e.what() != std::string("ValueError: foo")) || (!err && e.what() != std::string("Internal error: pybind11::error_already_set called " "while Python error indicator not set."))) { PyErr_Clear(); throw std::runtime_error("error message mismatch"); } } PyErr_Clear(); if (err) { PyErr_SetString(PyExc_ValueError, "foo"); } throw py::error_already_set(); }); m.def("python_call_in_destructor", [](const py::dict &d) { bool retval = false; try { PythonCallInDestructor set_dict_in_destructor(d); PyErr_SetString(PyExc_ValueError, "foo"); throw py::error_already_set(); } catch (const py::error_already_set &) { retval = true; } return retval; }); m.def("python_alreadyset_in_destructor", [](const py::str &s) { PythonAlreadySetInDestructor alreadyset_in_destructor(s); return true; }); // test_nested_throws m.def("try_catch", [m](const py::object &exc_type, const py::function &f, const py::args &args) { try { f(*args); } catch (py::error_already_set &ex) { if (ex.matches(exc_type)) { py::print(ex.what()); } else { // Simply `throw;` also works and is better, but using `throw ex;` // here to cover that situation (as observed in the wild). throw ex; // Invokes the copy ctor. } } }); // Test repr that cannot be displayed m.def("simple_bool_passthrough", [](bool x) { return x; }); m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); }); m.def("raise_from", []() { PyErr_SetString(PyExc_ValueError, "inner"); py::raise_from(PyExc_ValueError, "outer"); throw py::error_already_set(); }); m.def("raise_from_already_set", []() { try { PyErr_SetString(PyExc_ValueError, "inner"); throw py::error_already_set(); } catch (py::error_already_set &e) { py::raise_from(e, PyExc_ValueError, "outer"); throw py::error_already_set(); } }); m.def("throw_nested_exception", []() { try { throw std::runtime_error("Inner Exception"); } catch (const std::runtime_error &) { std::throw_with_nested(std::runtime_error("Outer Exception")); } }); m.def("error_already_set_what", [](const py::object &exc_type, const py::object &exc_value) { PyErr_SetObject(exc_type.ptr(), exc_value.ptr()); std::string what = py::error_already_set().what(); bool py_err_set_after_what = (PyErr_Occurred() != nullptr); PyErr_Clear(); return py::make_tuple(std::move(what), py_err_set_after_what); }); m.def("test_cross_module_interleaved_error_already_set", []() { auto cm = py::module_::import("cross_module_interleaved_error_already_set"); auto interleaved_error_already_set = reinterpret_cast(PyLong_AsVoidPtr(cm.attr("funcaddr").ptr())); interleaved_error_already_set(); }); m.def("test_error_already_set_double_restore", [](bool dry_run) { PyErr_SetString(PyExc_ValueError, "Random error."); py::error_already_set e; e.restore(); PyErr_Clear(); if (!dry_run) { e.restore(); } }); // https://github.com/pybind/pybind11/issues/4075 m.def("test_pypy_oserror_normalization", []() { try { py::module_::import("io").attr("open")("this_filename_must_not_exist", "r"); } catch (const py::error_already_set &e) { return py::str(e.what()); // str must be built before e goes out of scope. } return py::str("UNEXPECTED"); }); m.def("test_fn_cast_int", [](const py::function &fn) { // function returns None instead of int, should give a useful error message fn().cast(); }); } aoflagger-v3.4.0/external/pybind11/tests/test_gil_scoped.cpp0000644000175000017500000001227714507760431022627 0ustar olesoles/* tests/test_gil_scoped.cpp -- acquire and release gil Copyright (c) 2017 Borja Zarco (Google LLC) All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "pybind11_tests.h" #include #include #define CROSS_MODULE(Function) \ auto cm = py::module_::import("cross_module_gil_utils"); \ auto target = reinterpret_cast(PyLong_AsVoidPtr(cm.attr(Function).ptr())); class VirtClass { public: virtual ~VirtClass() = default; VirtClass() = default; VirtClass(const VirtClass &) = delete; virtual void virtual_func() {} virtual void pure_virtual_func() = 0; }; class PyVirtClass : public VirtClass { void virtual_func() override { PYBIND11_OVERRIDE(void, VirtClass, virtual_func, ); } void pure_virtual_func() override { PYBIND11_OVERRIDE_PURE(void, VirtClass, pure_virtual_func, ); } }; TEST_SUBMODULE(gil_scoped, m) { m.attr("defined_THREAD_SANITIZER") = #if defined(THREAD_SANITIZER) true; #else false; #endif m.def("intentional_deadlock", []() { std::thread([]() { py::gil_scoped_acquire gil_acquired; }).join(); }); py::class_(m, "VirtClass") .def(py::init<>()) .def("virtual_func", &VirtClass::virtual_func) .def("pure_virtual_func", &VirtClass::pure_virtual_func); m.def("test_callback_py_obj", [](py::object &func) { func(); }); m.def("test_callback_std_func", [](const std::function &func) { func(); }); m.def("test_callback_virtual_func", [](VirtClass &virt) { virt.virtual_func(); }); m.def("test_callback_pure_virtual_func", [](VirtClass &virt) { virt.pure_virtual_func(); }); m.def("test_cross_module_gil_released", []() { CROSS_MODULE("gil_acquire_funcaddr") py::gil_scoped_release gil_release; target(); }); m.def("test_cross_module_gil_acquired", []() { CROSS_MODULE("gil_acquire_funcaddr") py::gil_scoped_acquire gil_acquire; target(); }); m.def("test_cross_module_gil_inner_custom_released", []() { CROSS_MODULE("gil_acquire_inner_custom_funcaddr") py::gil_scoped_release gil_release; target(); }); m.def("test_cross_module_gil_inner_custom_acquired", []() { CROSS_MODULE("gil_acquire_inner_custom_funcaddr") py::gil_scoped_acquire gil_acquire; target(); }); m.def("test_cross_module_gil_inner_pybind11_released", []() { CROSS_MODULE("gil_acquire_inner_pybind11_funcaddr") py::gil_scoped_release gil_release; target(); }); m.def("test_cross_module_gil_inner_pybind11_acquired", []() { CROSS_MODULE("gil_acquire_inner_pybind11_funcaddr") py::gil_scoped_acquire gil_acquire; target(); }); m.def("test_cross_module_gil_nested_custom_released", []() { CROSS_MODULE("gil_acquire_nested_custom_funcaddr") py::gil_scoped_release gil_release; target(); }); m.def("test_cross_module_gil_nested_custom_acquired", []() { CROSS_MODULE("gil_acquire_nested_custom_funcaddr") py::gil_scoped_acquire gil_acquire; target(); }); m.def("test_cross_module_gil_nested_pybind11_released", []() { CROSS_MODULE("gil_acquire_nested_pybind11_funcaddr") py::gil_scoped_release gil_release; target(); }); m.def("test_cross_module_gil_nested_pybind11_acquired", []() { CROSS_MODULE("gil_acquire_nested_pybind11_funcaddr") py::gil_scoped_acquire gil_acquire; target(); }); m.def("test_release_acquire", [](const py::object &obj) { py::gil_scoped_release gil_released; py::gil_scoped_acquire gil_acquired; return py::str(obj); }); m.def("test_nested_acquire", [](const py::object &obj) { py::gil_scoped_release gil_released; py::gil_scoped_acquire gil_acquired_outer; py::gil_scoped_acquire gil_acquired_inner; return py::str(obj); }); m.def("test_multi_acquire_release_cross_module", [](unsigned bits) { py::set internals_ids; internals_ids.add(PYBIND11_INTERNALS_ID); { py::gil_scoped_release gil_released; auto thread_f = [bits, &internals_ids]() { py::gil_scoped_acquire gil_acquired; auto cm = py::module_::import("cross_module_gil_utils"); auto target = reinterpret_cast( PyLong_AsVoidPtr(cm.attr("gil_multi_acquire_release_funcaddr").ptr())); std::string cm_internals_id = target(bits >> 3); internals_ids.add(cm_internals_id); }; if ((bits & 0x1u) != 0u) { thread_f(); } if ((bits & 0x2u) != 0u) { std::thread non_python_thread(thread_f); non_python_thread.join(); } if ((bits & 0x4u) != 0u) { thread_f(); } } return internals_ids; }); } aoflagger-v3.4.0/external/pybind11/tests/test_eigen_matrix.cpp0000644000175000017500000004562614507760431023176 0ustar olesoles/* tests/eigen.cpp -- automatic conversion of Eigen types Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include "constructor_stats.h" #include "pybind11_tests.h" PYBIND11_WARNING_DISABLE_MSVC(4996) #include using MatrixXdR = Eigen::Matrix; // Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the // (1-based) row/column number. template void reset_ref(M &x) { for (int i = 0; i < x.rows(); i++) { for (int j = 0; j < x.cols(); j++) { x(i, j) = 11 + 10 * i + j; } } } // Returns a static, column-major matrix Eigen::MatrixXd &get_cm() { static Eigen::MatrixXd *x; if (!x) { x = new Eigen::MatrixXd(3, 3); reset_ref(*x); } return *x; } // Likewise, but row-major MatrixXdR &get_rm() { static MatrixXdR *x; if (!x) { x = new MatrixXdR(3, 3); reset_ref(*x); } return *x; } // Resets the values of the static matrices returned by get_cm()/get_rm() void reset_refs() { reset_ref(get_cm()); reset_ref(get_rm()); } // Returns element 2,1 from a matrix (used to test copy/nocopy) double get_elem(const Eigen::Ref &m) { return m(2, 1); }; // Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix // reference is referencing rows/columns correctly). template Eigen::MatrixXd adjust_matrix(MatrixArgType m) { Eigen::MatrixXd ret(m); for (int c = 0; c < m.cols(); c++) { for (int r = 0; r < m.rows(); r++) { ret(r, c) += 10 * r + 100 * c; // NOLINT(clang-analyzer-core.uninitialized.Assign) } } return ret; } struct CustomOperatorNew { CustomOperatorNew() = default; Eigen::Matrix4d a = Eigen::Matrix4d::Zero(); Eigen::Matrix4d b = Eigen::Matrix4d::Identity(); EIGEN_MAKE_ALIGNED_OPERATOR_NEW; }; TEST_SUBMODULE(eigen_matrix, m) { using FixedMatrixR = Eigen::Matrix; using FixedMatrixC = Eigen::Matrix; using DenseMatrixR = Eigen::Matrix; using DenseMatrixC = Eigen::Matrix; using FourRowMatrixC = Eigen::Matrix; using FourColMatrixC = Eigen::Matrix; using FourRowMatrixR = Eigen::Matrix; using FourColMatrixR = Eigen::Matrix; using SparseMatrixR = Eigen::SparseMatrix; using SparseMatrixC = Eigen::SparseMatrix; // various tests m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; }); m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; }); m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; }); m.def("double_threec", [](py::EigenDRef x) { x *= 2; }); m.def("double_threer", [](py::EigenDRef x) { x *= 2; }); m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; }); m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; }); // test_eigen_ref_to_python // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended m.def("cholesky1", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky2", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky3", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky4", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); // test_eigen_ref_mutators // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping // into the numpy array data and so the result should show up there. There are three versions: // one that works on a contiguous-row matrix (numpy's default), one for a contiguous-column // matrix, and one for any matrix. auto add_rm = [](Eigen::Ref x, int r, int c, double v) { x(r, c) += v; }; auto add_cm = [](Eigen::Ref x, int r, int c, double v) { x(r, c) += v; }; // Mutators (Eigen maps into numpy variables): m.def("add_rm", add_rm); // Only takes row-contiguous m.def("add_cm", add_cm); // Only takes column-contiguous // Overloaded versions that will accept either row or column contiguous: m.def("add1", add_rm); m.def("add1", add_cm); m.def("add2", add_cm); m.def("add2", add_rm); // This one accepts a matrix of any stride: m.def("add_any", [](py::EigenDRef x, int r, int c, double v) { x(r, c) += v; }); // Return mutable references (numpy maps into eigen variables) m.def("get_cm_ref", []() { return Eigen::Ref(get_cm()); }); m.def("get_rm_ref", []() { return Eigen::Ref(get_rm()); }); // The same references, but non-mutable (numpy maps into eigen variables, but is !writeable) m.def("get_cm_const_ref", []() { return Eigen::Ref(get_cm()); }); m.def("get_rm_const_ref", []() { return Eigen::Ref(get_rm()); }); m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values // Increments and returns ref to (same) matrix m.def( "incr_matrix", [](Eigen::Ref m, double v) { m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); return m; }, py::return_value_policy::reference); // Same, but accepts a matrix of any strides m.def( "incr_matrix_any", [](py::EigenDRef m, double v) { m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); return m; }, py::return_value_policy::reference); // Returns an eigen slice of even rows m.def( "even_rows", [](py::EigenDRef m) { return py::EigenDMap( m.data(), (m.rows() + 1) / 2, m.cols(), py::EigenDStride(m.outerStride(), 2 * m.innerStride())); }, py::return_value_policy::reference); // Returns an eigen slice of even columns m.def( "even_cols", [](py::EigenDRef m) { return py::EigenDMap( m.data(), m.rows(), (m.cols() + 1) / 2, py::EigenDStride(2 * m.outerStride(), m.innerStride())); }, py::return_value_policy::reference); // Returns diagonals: a vector-like object with an inner stride != 1 m.def("diagonal", [](const Eigen::Ref &x) { return x.diagonal(); }); m.def("diagonal_1", [](const Eigen::Ref &x) { return x.diagonal<1>(); }); m.def("diagonal_n", [](const Eigen::Ref &x, int index) { return x.diagonal(index); }); // Return a block of a matrix (gives non-standard strides) m.def("block", [m](const py::object &x_obj, int start_row, int start_col, int block_rows, int block_cols) { return m.attr("_block")(x_obj, x_obj, start_row, start_col, block_rows, block_cols); }); m.def( "_block", [](const py::object &x_obj, const Eigen::Ref &x, int start_row, int start_col, int block_rows, int block_cols) { // See PR #4217 for background. This test is a bit over the top, but might be useful // as a concrete example to point to when explaining the dangling reference trap. auto i0 = py::make_tuple(0, 0); auto x0_orig = x_obj[*i0].cast(); if (x(0, 0) != x0_orig) { throw std::runtime_error( "Something in the type_caster for Eigen::Ref is terribly wrong."); } double x0_mod = x0_orig + 1; x_obj[*i0] = x0_mod; auto copy_detected = (x(0, 0) != x0_mod); x_obj[*i0] = x0_orig; if (copy_detected) { throw std::runtime_error("type_caster for Eigen::Ref made a copy."); } return x.block(start_row, start_col, block_rows, block_cols); }, py::keep_alive<0, 1>()); // test_eigen_return_references, test_eigen_keepalive // return value referencing/copying tests: class ReturnTester { Eigen::MatrixXd mat = create(); public: ReturnTester() { print_created(this); } ~ReturnTester() { print_destroyed(this); } static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); } // NOLINTNEXTLINE(readability-const-return-type) static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); } Eigen::MatrixXd &get() { return mat; } Eigen::MatrixXd *getPtr() { return &mat; } const Eigen::MatrixXd &view() { return mat; } const Eigen::MatrixXd *viewPtr() { return &mat; } Eigen::Ref ref() { return mat; } Eigen::Ref refConst() { return mat; } Eigen::Block block(int r, int c, int nrow, int ncol) { return mat.block(r, c, nrow, ncol); } Eigen::Block blockConst(int r, int c, int nrow, int ncol) const { return mat.block(r, c, nrow, ncol); } py::EigenDMap corners() { return py::EigenDMap( mat.data(), py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1), mat.innerStride() * (mat.innerSize() - 1))); } py::EigenDMap cornersConst() const { return py::EigenDMap( mat.data(), py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1), mat.innerStride() * (mat.innerSize() - 1))); } }; using rvp = py::return_value_policy; py::class_(m, "ReturnTester") .def(py::init<>()) .def_static("create", &ReturnTester::create) .def_static("create_const", &ReturnTester::createConst) .def("get", &ReturnTester::get, rvp::reference_internal) .def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal) .def("view", &ReturnTester::view, rvp::reference_internal) .def("view_ptr", &ReturnTester::view, rvp::reference_internal) .def("copy_get", &ReturnTester::get) // Default rvp: copy .def("copy_view", &ReturnTester::view) // " .def("ref", &ReturnTester::ref) // Default for Ref is to reference .def("ref_const", &ReturnTester::refConst) // Likewise, but const .def("ref_safe", &ReturnTester::ref, rvp::reference_internal) .def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal) .def("copy_ref", &ReturnTester::ref, rvp::copy) .def("copy_ref_const", &ReturnTester::refConst, rvp::copy) .def("block", &ReturnTester::block) .def("block_safe", &ReturnTester::block, rvp::reference_internal) .def("block_const", &ReturnTester::blockConst, rvp::reference_internal) .def("copy_block", &ReturnTester::block, rvp::copy) .def("corners", &ReturnTester::corners, rvp::reference_internal) .def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal); // test_special_matrix_objects // Returns a DiagonalMatrix with diagonal (1,2,3,...) m.def("incr_diag", [](int k) { Eigen::DiagonalMatrix m(k); for (int i = 0; i < k; i++) { m.diagonal()[i] = i + 1; } return m; }); // Returns a SelfAdjointView referencing the lower triangle of m m.def("symmetric_lower", [](const Eigen::MatrixXi &m) { return m.selfadjointView(); }); // Returns a SelfAdjointView referencing the lower triangle of m m.def("symmetric_upper", [](const Eigen::MatrixXi &m) { return m.selfadjointView(); }); // Test matrix for various functions below. Eigen::MatrixXf mat(5, 6); mat << 0, 3, 0, 0, 0, 11, 22, 0, 0, 0, 17, 11, 7, 5, 0, 1, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 14, 0, 8, 11; // test_fixed, and various other tests m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); }); // Our Eigen does a hack which respects constness through the numpy writeable flag. // Therefore, the const return actually affects this type despite being an rvalue. // NOLINTNEXTLINE(readability-const-return-type) m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); }); m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); }); m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; }); m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; }); // test_mutator_descriptors m.def("fixed_mutator_r", [](const Eigen::Ref &) {}); m.def("fixed_mutator_c", [](const Eigen::Ref &) {}); m.def("fixed_mutator_a", [](const py::EigenDRef &) {}); // test_dense m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); }); m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); }); m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; }); m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; }); // test_sparse, test_sparse_signature m.def("sparse_r", [mat]() -> SparseMatrixR { // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) return Eigen::SparseView(mat); }); m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView(mat); }); m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; }); m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; }); // test_partially_fixed m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; }); m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; }); m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; }); m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; }); // test_cpp_casting // Test that we can cast a numpy object to a Eigen::MatrixXd explicitly m.def("cpp_copy", [](py::handle m) { return m.cast()(1, 0); }); m.def("cpp_ref_c", [](py::handle m) { return m.cast>()(1, 0); }); m.def("cpp_ref_r", [](py::handle m) { return m.cast>()(1, 0); }); m.def("cpp_ref_any", [](py::handle m) { return m.cast>()(1, 0); }); // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // test_nocopy_wrapper // Test that we can prevent copying into an argument that would normally copy: First a version // that would allow copying (if types or strides don't match) for comparison: m.def("get_elem", &get_elem); // Now this alternative that calls the tells pybind to fail rather than copy: m.def( "get_elem_nocopy", [](const Eigen::Ref &m) -> double { return get_elem(m); }, py::arg{}.noconvert()); // Also test a row-major-only no-copy const ref: m.def( "get_elem_rm_nocopy", [](Eigen::Ref> &m) -> long { return m(2, 1); }, py::arg{}.noconvert()); // test_issue738, test_zero_length // Issue #738: 1×N or N×1 2D matrices were neither accepted nor properly copied with an // incompatible stride value on the length-1 dimension--but that should be allowed (without // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension. // Similarly, 0×N or N×0 matrices were not accepted--again, these should be allowed since // they contain no data. This particularly affects numpy ≥ 1.23, which sets the strides to // 0 if any dimension size is 0. m.def("iss738_f1", &adjust_matrix &>, py::arg{}.noconvert()); m.def("iss738_f2", &adjust_matrix> &>, py::arg{}.noconvert()); // test_issue1105 // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense // eigen Vector or RowVector, the argument would fail to load because the numpy copy would // fail: numpy won't broadcast a Nx1 into a 1-dimensional vector. m.def("iss1105_col", [](const Eigen::VectorXd &) { return true; }); m.def("iss1105_row", [](const Eigen::RowVectorXd &) { return true; }); // test_named_arguments // Make sure named arguments are working properly: m.def( "matrix_multiply", [](const py::EigenDRef &A, const py::EigenDRef &B) -> Eigen::MatrixXd { if (A.cols() != B.rows()) { throw std::domain_error("Nonconformable matrices!"); } return A * B; }, py::arg("A"), py::arg("B")); // test_custom_operator_new py::class_(m, "CustomOperatorNew") .def(py::init<>()) .def_readonly("a", &CustomOperatorNew::a) .def_readonly("b", &CustomOperatorNew::b); // test_eigen_ref_life_support // In case of a failure (the caster's temp array does not live long enough), creating // a new array (np.ones(10)) increases the chances that the temp array will be garbage // collected and/or that its memory will be overridden with different values. m.def("get_elem_direct", [](const Eigen::Ref &v) { py::module_::import("numpy").attr("ones")(10); return v(5); }); m.def("get_elem_indirect", [](std::vector> v) { py::module_::import("numpy").attr("ones")(10); return v[0](5); }); } aoflagger-v3.4.0/external/pybind11/tests/test_virtual_functions.py0000644000175000017500000003116114507760431024134 0ustar olesolesimport pytest import env # noqa: F401 m = pytest.importorskip("pybind11_tests.virtual_functions") from pybind11_tests import ConstructorStats # noqa: E402 def test_override(capture, msg): class ExtendedExampleVirt(m.ExampleVirt): def __init__(self, state): super().__init__(state + 1) self.data = "Hello world" def run(self, value): print(f"ExtendedExampleVirt::run({value}), calling parent..") return super().run(value + 1) def run_bool(self): print("ExtendedExampleVirt::run_bool()") return False def get_string1(self): return "override1" def pure_virtual(self): print(f"ExtendedExampleVirt::pure_virtual(): {self.data}") class ExtendedExampleVirt2(ExtendedExampleVirt): def __init__(self, state): super().__init__(state + 1) def get_string2(self): return "override2" ex12 = m.ExampleVirt(10) with capture: assert m.runExampleVirt(ex12, 20) == 30 assert ( capture == """ Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2) """ ) with pytest.raises(RuntimeError) as excinfo: m.runExampleVirtVirtual(ex12) assert ( msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' ) ex12p = ExtendedExampleVirt(10) with capture: assert m.runExampleVirt(ex12p, 20) == 32 assert ( capture == """ ExtendedExampleVirt::run(20), calling parent.. Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2) """ ) with capture: assert m.runExampleVirtBool(ex12p) is False assert capture == "ExtendedExampleVirt::run_bool()" with capture: m.runExampleVirtVirtual(ex12p) assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world" ex12p2 = ExtendedExampleVirt2(15) with capture: assert m.runExampleVirt(ex12p2, 50) == 68 assert ( capture == """ ExtendedExampleVirt::run(50), calling parent.. Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2) """ ) cstats = ConstructorStats.get(m.ExampleVirt) assert cstats.alive() == 3 del ex12, ex12p, ex12p2 assert cstats.alive() == 0 assert cstats.values() == ["10", "11", "17"] assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 0 def test_alias_delay_initialization1(capture): """`A` only initializes its trampoline class when we inherit from it If we just create and use an A instance directly, the trampoline initialization is bypassed and we only initialize an A() instead (for performance reasons). """ class B(m.A): def __init__(self): super().__init__() def f(self): print("In python f()") # C++ version with capture: a = m.A() m.call_f(a) del a pytest.gc_collect() assert capture == "A.f()" # Python version with capture: b = B() m.call_f(b) del b pytest.gc_collect() assert ( capture == """ PyA.PyA() PyA.f() In python f() PyA.~PyA() """ ) def test_alias_delay_initialization2(capture): """`A2`, unlike the above, is configured to always initialize the alias While the extra initialization and extra class layer has small virtual dispatch performance penalty, it also allows us to do more things with the trampoline class such as defining local variables and performing construction/destruction. """ class B2(m.A2): def __init__(self): super().__init__() def f(self): print("In python B2.f()") # No python subclass version with capture: a2 = m.A2() m.call_f(a2) del a2 pytest.gc_collect() a3 = m.A2(1) m.call_f(a3) del a3 pytest.gc_collect() assert ( capture == """ PyA2.PyA2() PyA2.f() A2.f() PyA2.~PyA2() PyA2.PyA2() PyA2.f() A2.f() PyA2.~PyA2() """ ) # Python subclass version with capture: b2 = B2() m.call_f(b2) del b2 pytest.gc_collect() assert ( capture == """ PyA2.PyA2() PyA2.f() In python B2.f() PyA2.~PyA2() """ ) # PyPy: Reference count > 1 causes call with noncopyable instance # to fail in ncv1.print_nc() @pytest.mark.xfail("env.PYPY") @pytest.mark.skipif( not hasattr(m, "NCVirt"), reason="NCVirt does not work on Intel/PGI/NVCC compilers" ) def test_move_support(): class NCVirtExt(m.NCVirt): def get_noncopyable(self, a, b): # Constructs and returns a new instance: return m.NonCopyable(a * a, b * b) def get_movable(self, a, b): # Return a referenced copy self.movable = m.Movable(a, b) return self.movable class NCVirtExt2(m.NCVirt): def get_noncopyable(self, a, b): # Keep a reference: this is going to throw an exception self.nc = m.NonCopyable(a, b) return self.nc def get_movable(self, a, b): # Return a new instance without storing it return m.Movable(a, b) ncv1 = NCVirtExt() assert ncv1.print_nc(2, 3) == "36" assert ncv1.print_movable(4, 5) == "9" ncv2 = NCVirtExt2() assert ncv2.print_movable(7, 7) == "14" # Don't check the exception message here because it differs under debug/non-debug mode with pytest.raises(RuntimeError): ncv2.print_nc(9, 9) nc_stats = ConstructorStats.get(m.NonCopyable) mv_stats = ConstructorStats.get(m.Movable) assert nc_stats.alive() == 1 assert mv_stats.alive() == 1 del ncv1, ncv2 assert nc_stats.alive() == 0 assert mv_stats.alive() == 0 assert nc_stats.values() == ["4", "9", "9", "9"] assert mv_stats.values() == ["4", "5", "7", "7"] assert nc_stats.copy_constructions == 0 assert mv_stats.copy_constructions == 1 assert nc_stats.move_constructions >= 0 assert mv_stats.move_constructions >= 0 def test_dispatch_issue(msg): """#159: virtual function dispatch has problems with similar-named functions""" class PyClass1(m.DispatchIssue): def dispatch(self): return "Yay.." class PyClass2(m.DispatchIssue): def dispatch(self): with pytest.raises(RuntimeError) as excinfo: super().dispatch() assert ( msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"' ) return m.dispatch_issue_go(PyClass1()) b = PyClass2() assert m.dispatch_issue_go(b) == "Yay.." def test_recursive_dispatch_issue(): """#3357: Recursive dispatch fails to find python function override""" class Data(m.Data): def __init__(self, value): super().__init__() self.value = value class Adder(m.Adder): def __call__(self, first, second, visitor): # lambda is a workaround, which adds extra frame to the # current CPython thread. Removing lambda reveals the bug # [https://github.com/pybind/pybind11/issues/3357] (lambda: visitor(Data(first.value + second.value)))() # noqa: PLC3002 class StoreResultVisitor: def __init__(self): self.result = None def __call__(self, data): self.result = data.value store = StoreResultVisitor() m.add2(Data(1), Data(2), Adder(), store) assert store.result == 3 # without lambda in Adder class, this function fails with # RuntimeError: Tried to call pure virtual function "AdderBase::__call__" m.add3(Data(1), Data(2), Data(3), Adder(), store) assert store.result == 6 def test_override_ref(): """#392/397: overriding reference-returning functions""" o = m.OverrideTest("asdf") # Not allowed (see associated .cpp comment) # i = o.str_ref() # assert o.str_ref() == "asdf" assert o.str_value() == "asdf" assert o.A_value().value == "hi" a = o.A_ref() assert a.value == "hi" a.value = "bye" assert a.value == "bye" def test_inherited_virtuals(): class AR(m.A_Repeat): def unlucky_number(self): return 99 class AT(m.A_Tpl): def unlucky_number(self): return 999 obj = AR() assert obj.say_something(3) == "hihihi" assert obj.unlucky_number() == 99 assert obj.say_everything() == "hi 99" obj = AT() assert obj.say_something(3) == "hihihi" assert obj.unlucky_number() == 999 assert obj.say_everything() == "hi 999" for obj in [m.B_Repeat(), m.B_Tpl()]: assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 13 assert obj.lucky_number() == 7.0 assert obj.say_everything() == "B says hi 1 times 13" for obj in [m.C_Repeat(), m.C_Tpl()]: assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888.0 assert obj.say_everything() == "B says hi 1 times 4444" class CR(m.C_Repeat): def lucky_number(self): return m.C_Repeat.lucky_number(self) + 1.25 obj = CR() assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 889.25 assert obj.say_everything() == "B says hi 1 times 4444" class CT(m.C_Tpl): pass obj = CT() assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888.0 assert obj.say_everything() == "B says hi 1 times 4444" class CCR(CR): def lucky_number(self): return CR.lucky_number(self) * 10 obj = CCR() assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 8892.5 assert obj.say_everything() == "B says hi 1 times 4444" class CCT(CT): def lucky_number(self): return CT.lucky_number(self) * 1000 obj = CCT() assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888000.0 assert obj.say_everything() == "B says hi 1 times 4444" class DR(m.D_Repeat): def unlucky_number(self): return 123 def lucky_number(self): return 42.0 for obj in [m.D_Repeat(), m.D_Tpl()]: assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888.0 assert obj.say_everything() == "B says hi 1 times 4444" obj = DR() assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 123 assert obj.lucky_number() == 42.0 assert obj.say_everything() == "B says hi 1 times 123" class DT(m.D_Tpl): def say_something(self, times): return "DT says:" + (" quack" * times) def unlucky_number(self): return 1234 def lucky_number(self): return -4.25 obj = DT() assert obj.say_something(3) == "DT says: quack quack quack" assert obj.unlucky_number() == 1234 assert obj.lucky_number() == -4.25 assert obj.say_everything() == "DT says: quack 1234" class DT2(DT): def say_something(self, times): return "DT2: " + ("QUACK" * times) def unlucky_number(self): return -3 class BT(m.B_Tpl): def say_something(self, times): return "BT" * times def unlucky_number(self): return -7 def lucky_number(self): return -1.375 obj = BT() assert obj.say_something(3) == "BTBTBT" assert obj.unlucky_number() == -7 assert obj.lucky_number() == -1.375 assert obj.say_everything() == "BT -7" def test_issue_1454(): # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) m.test_gil() m.test_gil_from_thread() def test_python_override(): def func(): class Test(m.test_override_cache_helper): def func(self): return 42 return Test() def func2(): class Test(m.test_override_cache_helper): pass return Test() for _ in range(1500): assert m.test_override_cache(func()) == 42 assert m.test_override_cache(func2()) == 0 aoflagger-v3.4.0/external/pybind11/tests/test_tagbased_polymorphic.py0000644000175000017500000000134514507760431024556 0ustar olesolesfrom pybind11_tests import tagbased_polymorphic as m def test_downcast(): zoo = m.create_zoo() assert [type(animal) for animal in zoo] == [ m.Labrador, m.Dog, m.Chihuahua, m.Cat, m.Panther, ] assert [animal.name for animal in zoo] == [ "Fido", "Ginger", "Hertzl", "Tiger", "Leo", ] zoo[1].sound = "woooooo" assert [dog.bark() for dog in zoo[:3]] == [ "Labrador Fido goes WOOF!", "Dog Ginger goes woooooo", "Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles", ] assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"] zoo[0].excitement -= 1000 assert zoo[0].excitement == 14000 aoflagger-v3.4.0/external/pybind11/tests/test_factory_constructors.py0000644000175000017500000004015314507760431024656 0ustar olesolesimport re import pytest from pybind11_tests import ConstructorStats from pybind11_tests import factory_constructors as m from pybind11_tests.factory_constructors import tag def test_init_factory_basic(): """Tests py::init_factory() wrapper around various ways of returning the object""" cstats = [ ConstructorStats.get(c) for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3] ] cstats[0].alive() # force gc n_inst = ConstructorStats.detail_reg_inst() x1 = m.TestFactory1(tag.unique_ptr, 3) assert x1.value == "3" y1 = m.TestFactory1(tag.pointer) assert y1.value == "(empty)" z1 = m.TestFactory1("hi!") assert z1.value == "hi!" assert ConstructorStats.detail_reg_inst() == n_inst + 3 x2 = m.TestFactory2(tag.move) assert x2.value == "(empty2)" y2 = m.TestFactory2(tag.pointer, 7) assert y2.value == "7" z2 = m.TestFactory2(tag.unique_ptr, "hi again") assert z2.value == "hi again" assert ConstructorStats.detail_reg_inst() == n_inst + 6 x3 = m.TestFactory3(tag.shared_ptr) assert x3.value == "(empty3)" y3 = m.TestFactory3(tag.pointer, 42) assert y3.value == "42" z3 = m.TestFactory3("bye") assert z3.value == "bye" for null_ptr_kind in [tag.null_ptr, tag.null_unique_ptr, tag.null_shared_ptr]: with pytest.raises(TypeError) as excinfo: m.TestFactory3(null_ptr_kind) assert ( str(excinfo.value) == "pybind11::init(): factory function returned nullptr" ) assert [i.alive() for i in cstats] == [3, 3, 3] assert ConstructorStats.detail_reg_inst() == n_inst + 9 del x1, y2, y3, z3 assert [i.alive() for i in cstats] == [2, 2, 1] assert ConstructorStats.detail_reg_inst() == n_inst + 5 del x2, x3, y1, z1, z2 assert [i.alive() for i in cstats] == [0, 0, 0] assert ConstructorStats.detail_reg_inst() == n_inst assert [i.values() for i in cstats] == [ ["3", "hi!"], ["7", "hi again"], ["42", "bye"], ] assert [i.default_constructions for i in cstats] == [1, 1, 1] def test_init_factory_signature(msg): with pytest.raises(TypeError) as excinfo: m.TestFactory1("invalid", "constructor", "arguments") assert ( msg(excinfo.value) == """ __init__(): incompatible constructor arguments. The following argument types are supported: 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) 2. m.factory_constructors.TestFactory1(arg0: str) 3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag) 4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle) Invoked with: 'invalid', 'constructor', 'arguments' """ ) assert ( msg(m.TestFactory1.__init__.__doc__) == """ __init__(*args, **kwargs) Overloaded function. 1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None 2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None """ ) def test_init_factory_casting(): """Tests py::init_factory() wrapper with various upcasting and downcasting returns""" cstats = [ ConstructorStats.get(c) for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5] ] cstats[0].alive() # force gc n_inst = ConstructorStats.detail_reg_inst() # Construction from derived references: a = m.TestFactory3(tag.pointer, tag.TF4, 4) assert a.value == "4" b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5) assert b.value == "5" c = m.TestFactory3(tag.pointer, tag.TF5, 6) assert c.value == "6" d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7) assert d.value == "7" assert ConstructorStats.detail_reg_inst() == n_inst + 4 # Shared a lambda with TF3: e = m.TestFactory4(tag.pointer, tag.TF4, 8) assert e.value == "8" assert ConstructorStats.detail_reg_inst() == n_inst + 5 assert [i.alive() for i in cstats] == [5, 3, 2] del a assert [i.alive() for i in cstats] == [4, 2, 2] assert ConstructorStats.detail_reg_inst() == n_inst + 4 del b, c, e assert [i.alive() for i in cstats] == [1, 0, 1] assert ConstructorStats.detail_reg_inst() == n_inst + 1 del d assert [i.alive() for i in cstats] == [0, 0, 0] assert ConstructorStats.detail_reg_inst() == n_inst assert [i.values() for i in cstats] == [ ["4", "5", "6", "7", "8"], ["4", "5", "8"], ["6", "7"], ] def test_init_factory_alias(): """Tests py::init_factory() wrapper with value conversions and alias types""" cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()] cstats[0].alive() # force gc n_inst = ConstructorStats.detail_reg_inst() a = m.TestFactory6(tag.base, 1) assert a.get() == 1 assert not a.has_alias() b = m.TestFactory6(tag.alias, "hi there") assert b.get() == 8 assert b.has_alias() c = m.TestFactory6(tag.alias, 3) assert c.get() == 3 assert c.has_alias() d = m.TestFactory6(tag.alias, tag.pointer, 4) assert d.get() == 4 assert d.has_alias() e = m.TestFactory6(tag.base, tag.pointer, 5) assert e.get() == 5 assert not e.has_alias() f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6) assert f.get() == 6 assert f.has_alias() assert ConstructorStats.detail_reg_inst() == n_inst + 6 assert [i.alive() for i in cstats] == [6, 4] del a, b, e assert [i.alive() for i in cstats] == [3, 3] assert ConstructorStats.detail_reg_inst() == n_inst + 3 del f, c, d assert [i.alive() for i in cstats] == [0, 0] assert ConstructorStats.detail_reg_inst() == n_inst class MyTest(m.TestFactory6): def __init__(self, *args): m.TestFactory6.__init__(self, *args) def get(self): return -5 + m.TestFactory6.get(self) # Return Class by value, moved into new alias: z = MyTest(tag.base, 123) assert z.get() == 118 assert z.has_alias() # Return alias by value, moved into new alias: y = MyTest(tag.alias, "why hello!") assert y.get() == 5 assert y.has_alias() # Return Class by pointer, moved into new alias then original destroyed: x = MyTest(tag.base, tag.pointer, 47) assert x.get() == 42 assert x.has_alias() assert ConstructorStats.detail_reg_inst() == n_inst + 3 assert [i.alive() for i in cstats] == [3, 3] del x, y, z assert [i.alive() for i in cstats] == [0, 0] assert ConstructorStats.detail_reg_inst() == n_inst assert [i.values() for i in cstats] == [ ["1", "8", "3", "4", "5", "6", "123", "10", "47"], ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"], ] def test_init_factory_dual(): """Tests init factory functions with dual main/alias factory functions""" from pybind11_tests.factory_constructors import TestFactory7 cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()] cstats[0].alive() # force gc n_inst = ConstructorStats.detail_reg_inst() class PythFactory7(TestFactory7): def get(self): return 100 + TestFactory7.get(self) a1 = TestFactory7(1) a2 = PythFactory7(2) assert a1.get() == 1 assert a2.get() == 102 assert not a1.has_alias() assert a2.has_alias() b1 = TestFactory7(tag.pointer, 3) b2 = PythFactory7(tag.pointer, 4) assert b1.get() == 3 assert b2.get() == 104 assert not b1.has_alias() assert b2.has_alias() c1 = TestFactory7(tag.mixed, 5) c2 = PythFactory7(tag.mixed, 6) assert c1.get() == 5 assert c2.get() == 106 assert not c1.has_alias() assert c2.has_alias() d1 = TestFactory7(tag.base, tag.pointer, 7) d2 = PythFactory7(tag.base, tag.pointer, 8) assert d1.get() == 7 assert d2.get() == 108 assert not d1.has_alias() assert d2.has_alias() # Both return an alias; the second multiplies the value by 10: e1 = TestFactory7(tag.alias, tag.pointer, 9) e2 = PythFactory7(tag.alias, tag.pointer, 10) assert e1.get() == 9 assert e2.get() == 200 assert e1.has_alias() assert e2.has_alias() f1 = TestFactory7(tag.shared_ptr, tag.base, 11) f2 = PythFactory7(tag.shared_ptr, tag.base, 12) assert f1.get() == 11 assert f2.get() == 112 assert not f1.has_alias() assert f2.has_alias() g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13) assert g1.get() == 13 assert not g1.has_alias() with pytest.raises(TypeError) as excinfo: PythFactory7(tag.shared_ptr, tag.invalid_base, 14) assert ( str(excinfo.value) == "pybind11::init(): construction failed: returned holder-wrapped instance is not an " "alias instance" ) assert [i.alive() for i in cstats] == [13, 7] assert ConstructorStats.detail_reg_inst() == n_inst + 13 del a1, a2, b1, d1, e1, e2 assert [i.alive() for i in cstats] == [7, 4] assert ConstructorStats.detail_reg_inst() == n_inst + 7 del b2, c1, c2, d2, f1, f2, g1 assert [i.alive() for i in cstats] == [0, 0] assert ConstructorStats.detail_reg_inst() == n_inst assert [i.values() for i in cstats] == [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"], ["2", "4", "6", "8", "9", "100", "12"], ] def test_no_placement_new(capture): """Prior to 2.2, `py::init<...>` relied on the type supporting placement new; this tests a class without placement new support.""" with capture: a = m.NoPlacementNew(123) found = re.search(r"^operator new called, returning (\d+)\n$", str(capture)) assert found assert a.i == 123 with capture: del a pytest.gc_collect() assert capture == "operator delete called on " + found.group(1) with capture: b = m.NoPlacementNew() found = re.search(r"^operator new called, returning (\d+)\n$", str(capture)) assert found assert b.i == 100 with capture: del b pytest.gc_collect() assert capture == "operator delete called on " + found.group(1) def test_multiple_inheritance(): class MITest(m.TestFactory1, m.TestFactory2): def __init__(self): m.TestFactory1.__init__(self, tag.unique_ptr, 33) m.TestFactory2.__init__(self, tag.move) a = MITest() assert m.TestFactory1.value.fget(a) == "33" assert m.TestFactory2.value.fget(a) == "(empty2)" def create_and_destroy(*args): a = m.NoisyAlloc(*args) print("---") del a pytest.gc_collect() def strip_comments(s): return re.sub(r"\s+#.*", "", s) def test_reallocation_a(capture, msg): """When the constructor is overloaded, previous overloads can require a preallocated value. This test makes sure that such preallocated values only happen when they might be necessary, and that they are deallocated properly.""" pytest.gc_collect() with capture: create_and_destroy(1) assert ( msg(capture) == """ noisy new noisy placement new NoisyAlloc(int 1) --- ~NoisyAlloc() noisy delete """ ) def test_reallocation_b(capture, msg): with capture: create_and_destroy(1.5) assert msg(capture) == strip_comments( """ noisy new # allocation required to attempt first overload noisy delete # have to dealloc before considering factory init overload noisy new # pointer factory calling "new", part 1: allocation NoisyAlloc(double 1.5) # ... part two, invoking constructor --- ~NoisyAlloc() # Destructor noisy delete # operator delete """ ) def test_reallocation_c(capture, msg): with capture: create_and_destroy(2, 3) assert msg(capture) == strip_comments( """ noisy new # pointer factory calling "new", allocation NoisyAlloc(int 2) # constructor --- ~NoisyAlloc() # Destructor noisy delete # operator delete """ ) def test_reallocation_d(capture, msg): with capture: create_and_destroy(2.5, 3) assert msg(capture) == strip_comments( """ NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called) noisy new # return-by-value "new" part 1: allocation ~NoisyAlloc() # moved-away local func variable destruction --- ~NoisyAlloc() # Destructor noisy delete # operator delete """ ) def test_reallocation_e(capture, msg): with capture: create_and_destroy(3.5, 4.5) assert msg(capture) == strip_comments( """ noisy new # preallocation needed before invoking placement-new overload noisy placement new # Placement new NoisyAlloc(double 3.5) # construction --- ~NoisyAlloc() # Destructor noisy delete # operator delete """ ) def test_reallocation_f(capture, msg): with capture: create_and_destroy(4, 0.5) assert msg(capture) == strip_comments( """ noisy new # preallocation needed before invoking placement-new overload noisy delete # deallocation of preallocated storage noisy new # Factory pointer allocation NoisyAlloc(int 4) # factory pointer construction --- ~NoisyAlloc() # Destructor noisy delete # operator delete """ ) def test_reallocation_g(capture, msg): with capture: create_and_destroy(5, "hi") assert msg(capture) == strip_comments( """ noisy new # preallocation needed before invoking first placement new noisy delete # delete before considering new-style constructor noisy new # preallocation for second placement new noisy placement new # Placement new in the second placement new overload NoisyAlloc(int 5) # construction --- ~NoisyAlloc() # Destructor noisy delete # operator delete """ ) def test_invalid_self(): """Tests invocation of the pybind-registered base class with an invalid `self` argument.""" class NotPybindDerived: pass # Attempts to initialize with an invalid type passed as `self`: class BrokenTF1(m.TestFactory1): def __init__(self, bad): if bad == 1: a = m.TestFactory2(tag.pointer, 1) m.TestFactory1.__init__(a, tag.pointer) elif bad == 2: a = NotPybindDerived() m.TestFactory1.__init__(a, tag.pointer) # Same as above, but for a class with an alias: class BrokenTF6(m.TestFactory6): def __init__(self, bad): if bad == 0: m.TestFactory6.__init__() elif bad == 1: a = m.TestFactory2(tag.pointer, 1) m.TestFactory6.__init__(a, tag.base, 1) elif bad == 2: a = m.TestFactory2(tag.pointer, 1) m.TestFactory6.__init__(a, tag.alias, 1) elif bad == 3: m.TestFactory6.__init__( NotPybindDerived.__new__(NotPybindDerived), tag.base, 1 ) elif bad == 4: m.TestFactory6.__init__( NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1 ) for arg in (1, 2): with pytest.raises(TypeError) as excinfo: BrokenTF1(arg) assert ( str(excinfo.value) == "__init__(self, ...) called with invalid or missing `self` argument" ) for arg in (0, 1, 2, 3, 4): with pytest.raises(TypeError) as excinfo: BrokenTF6(arg) assert ( str(excinfo.value) == "__init__(self, ...) called with invalid or missing `self` argument" ) aoflagger-v3.4.0/external/pybind11/tests/test_buffers.py0000644000175000017500000001136014507760431022011 0ustar olesolesimport ctypes import io import struct import pytest import env from pybind11_tests import ConstructorStats from pybind11_tests import buffers as m np = pytest.importorskip("numpy") def test_from_python(): with pytest.raises(RuntimeError) as excinfo: m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array assert str(excinfo.value) == "Incompatible buffer format!" m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) m4 = m.Matrix(m3) for i in range(m4.rows()): for j in range(m4.cols()): assert m3[i, j] == m4[i, j] cstats = ConstructorStats.get(m.Matrix) assert cstats.alive() == 1 del m3, m4 assert cstats.alive() == 0 assert cstats.values() == ["2x3 matrix"] assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Don't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 # https://foss.heptapod.net/pypy/pypy/-/issues/2444 # TODO: fix on recent PyPy @pytest.mark.xfail( env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", strict=False ) def test_to_python(): mat = m.Matrix(5, 4) assert memoryview(mat).shape == (5, 4) assert mat[2, 3] == 0 mat[2, 3] = 4.0 mat[3, 2] = 7.0 assert mat[2, 3] == 4 assert mat[3, 2] == 7 assert struct.unpack_from("f", mat, (3 * 4 + 2) * 4) == (7,) assert struct.unpack_from("f", mat, (2 * 4 + 3) * 4) == (4,) mat2 = np.array(mat, copy=False) assert mat2.shape == (5, 4) assert abs(mat2).sum() == 11 assert mat2[2, 3] == 4 assert mat2[3, 2] == 7 mat2[2, 3] = 5 assert mat2[2, 3] == 5 cstats = ConstructorStats.get(m.Matrix) assert cstats.alive() == 1 del mat pytest.gc_collect() assert cstats.alive() == 1 del mat2 # holds a mat reference pytest.gc_collect() assert cstats.alive() == 0 assert cstats.values() == ["5x4 matrix"] assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Don't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 def test_inherited_protocol(): """SquareMatrix is derived from Matrix and inherits the buffer protocol""" matrix = m.SquareMatrix(5) assert memoryview(matrix).shape == (5, 5) assert np.asarray(matrix).shape == (5, 5) def test_pointer_to_member_fn(): for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]: buf = cls() buf.value = 0x12345678 value = struct.unpack("i", bytearray(buf))[0] assert value == 0x12345678 def test_readonly_buffer(): buf = m.BufferReadOnly(0x64) view = memoryview(buf) assert view[0] == 0x64 assert view.readonly with pytest.raises(TypeError): view[0] = 0 def test_selective_readonly_buffer(): buf = m.BufferReadOnlySelect() memoryview(buf)[0] = 0x64 assert buf.value == 0x64 io.BytesIO(b"A").readinto(buf) assert buf.value == ord(b"A") buf.readonly = True with pytest.raises(TypeError): memoryview(buf)[0] = 0 with pytest.raises(TypeError): io.BytesIO(b"1").readinto(buf) def test_ctypes_array_1d(): char1d = (ctypes.c_char * 10)() int1d = (ctypes.c_int * 15)() long1d = (ctypes.c_long * 7)() for carray in (char1d, int1d, long1d): info = m.get_buffer_info(carray) assert info.itemsize == ctypes.sizeof(carray._type_) assert info.size == len(carray) assert info.ndim == 1 assert info.shape == [info.size] assert info.strides == [info.itemsize] assert not info.readonly def test_ctypes_array_2d(): char2d = ((ctypes.c_char * 10) * 4)() int2d = ((ctypes.c_int * 15) * 3)() long2d = ((ctypes.c_long * 7) * 2)() for carray in (char2d, int2d, long2d): info = m.get_buffer_info(carray) assert info.itemsize == ctypes.sizeof(carray[0]._type_) assert info.size == len(carray) * len(carray[0]) assert info.ndim == 2 assert info.shape == [len(carray), len(carray[0])] assert info.strides == [info.itemsize * len(carray[0]), info.itemsize] assert not info.readonly def test_ctypes_from_buffer(): test_pystr = b"0123456789" for pyarray in (test_pystr, bytearray(test_pystr)): pyinfo = m.get_buffer_info(pyarray) if pyinfo.readonly: cbytes = (ctypes.c_char * len(pyarray)).from_buffer_copy(pyarray) cinfo = m.get_buffer_info(cbytes) else: cbytes = (ctypes.c_char * len(pyarray)).from_buffer(pyarray) cinfo = m.get_buffer_info(cbytes) assert cinfo.size == pyinfo.size assert cinfo.ndim == pyinfo.ndim assert cinfo.shape == pyinfo.shape assert cinfo.strides == pyinfo.strides assert not cinfo.readonly aoflagger-v3.4.0/external/pybind11/tests/test_buffers.cpp0000644000175000017500000002056714507760431022154 0ustar olesoles/* tests/test_buffers.cpp -- supporting Pythons' buffer protocol Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "constructor_stats.h" #include "pybind11_tests.h" TEST_SUBMODULE(buffers, m) { // test_from_python / test_to_python: class Matrix { public: Matrix(py::ssize_t rows, py::ssize_t cols) : m_rows(rows), m_cols(cols) { print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) m_data = new float[(size_t) (rows * cols)]; memset(m_data, 0, sizeof(float) * (size_t) (rows * cols)); } Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) { print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) m_data = new float[(size_t) (m_rows * m_cols)]; memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); } Matrix(Matrix &&s) noexcept : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { print_move_created(this); s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr; } ~Matrix() { print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); delete[] m_data; } Matrix &operator=(const Matrix &s) { if (this == &s) { return *this; } print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); delete[] m_data; m_rows = s.m_rows; m_cols = s.m_cols; m_data = new float[(size_t) (m_rows * m_cols)]; memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); return *this; } Matrix &operator=(Matrix &&s) noexcept { print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); if (&s != this) { delete[] m_data; m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data; s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr; } return *this; } float operator()(py::ssize_t i, py::ssize_t j) const { return m_data[(size_t) (i * m_cols + j)]; } float &operator()(py::ssize_t i, py::ssize_t j) { return m_data[(size_t) (i * m_cols + j)]; } float *data() { return m_data; } py::ssize_t rows() const { return m_rows; } py::ssize_t cols() const { return m_cols; } private: py::ssize_t m_rows; py::ssize_t m_cols; float *m_data; }; py::class_(m, "Matrix", py::buffer_protocol()) .def(py::init()) /// Construct from a buffer .def(py::init([](const py::buffer &b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 2) { throw std::runtime_error("Incompatible buffer format!"); } auto *v = new Matrix(info.shape[0], info.shape[1]); memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols())); return v; })) .def("rows", &Matrix::rows) .def("cols", &Matrix::cols) /// Bare bones interface .def("__getitem__", [](const Matrix &m, std::pair i) { if (i.first >= m.rows() || i.second >= m.cols()) { throw py::index_error(); } return m(i.first, i.second); }) .def("__setitem__", [](Matrix &m, std::pair i, float v) { if (i.first >= m.rows() || i.second >= m.cols()) { throw py::index_error(); } m(i.first, i.second) = v; }) /// Provide buffer access .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( m.data(), /* Pointer to buffer */ {m.rows(), m.cols()}, /* Buffer dimensions */ {sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */ sizeof(float)}); }); // test_inherited_protocol class SquareMatrix : public Matrix { public: explicit SquareMatrix(py::ssize_t n) : Matrix(n, n) {} }; // Derived classes inherit the buffer protocol and the buffer access function py::class_(m, "SquareMatrix").def(py::init()); // test_pointer_to_member_fn // Tests that passing a pointer to member to the base class works in // the derived class. struct Buffer { int32_t value = 0; py::buffer_info get_buffer_info() { return py::buffer_info( &value, sizeof(value), py::format_descriptor::format(), 1); } }; py::class_(m, "Buffer", py::buffer_protocol()) .def(py::init<>()) .def_readwrite("value", &Buffer::value) .def_buffer(&Buffer::get_buffer_info); class ConstBuffer { std::unique_ptr value; public: int32_t get_value() const { return *value; } void set_value(int32_t v) { *value = v; } py::buffer_info get_buffer_info() const { return py::buffer_info( value.get(), sizeof(*value), py::format_descriptor::format(), 1); } ConstBuffer() : value(new int32_t{0}) {} }; py::class_(m, "ConstBuffer", py::buffer_protocol()) .def(py::init<>()) .def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value) .def_buffer(&ConstBuffer::get_buffer_info); struct DerivedBuffer : public Buffer {}; py::class_(m, "DerivedBuffer", py::buffer_protocol()) .def(py::init<>()) .def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value) .def_buffer(&DerivedBuffer::get_buffer_info); struct BufferReadOnly { const uint8_t value = 0; explicit BufferReadOnly(uint8_t value) : value(value) {} py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1); } }; py::class_(m, "BufferReadOnly", py::buffer_protocol()) .def(py::init()) .def_buffer(&BufferReadOnly::get_buffer_info); struct BufferReadOnlySelect { uint8_t value = 0; bool readonly = false; py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1, readonly); } }; py::class_(m, "BufferReadOnlySelect", py::buffer_protocol()) .def(py::init<>()) .def_readwrite("value", &BufferReadOnlySelect::value) .def_readwrite("readonly", &BufferReadOnlySelect::readonly) .def_buffer(&BufferReadOnlySelect::get_buffer_info); // Expose buffer_info for testing. py::class_(m, "buffer_info") .def(py::init<>()) .def_readonly("itemsize", &py::buffer_info::itemsize) .def_readonly("size", &py::buffer_info::size) .def_readonly("format", &py::buffer_info::format) .def_readonly("ndim", &py::buffer_info::ndim) .def_readonly("shape", &py::buffer_info::shape) .def_readonly("strides", &py::buffer_info::strides) .def_readonly("readonly", &py::buffer_info::readonly) .def("__repr__", [](py::handle self) { return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, " "ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, " "readonly={0.readonly!r}") .format(self); }); m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); }); } aoflagger-v3.4.0/external/pybind11/tests/test_stl_binders.cpp0000644000175000017500000001101614507760431023015 0ustar olesoles/* tests/test_stl_binders.cpp -- Usage of stl_binders functions Copyright (c) 2016 Sergey Lyskov All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include "pybind11_tests.h" #include #include #include class El { public: El() = delete; explicit El(int v) : a(v) {} int a; }; std::ostream &operator<<(std::ostream &s, El const &v) { s << "El{" << v.a << '}'; return s; } /// Issue #487: binding std::vector with E non-copyable class E_nc { public: explicit E_nc(int i) : value{i} {} E_nc(const E_nc &) = delete; E_nc &operator=(const E_nc &) = delete; E_nc(E_nc &&) = default; E_nc &operator=(E_nc &&) = default; int value; }; template Container *one_to_n(int n) { auto *v = new Container(); for (int i = 1; i <= n; i++) { v->emplace_back(i); } return v; } template Map *times_ten(int n) { auto *m = new Map(); for (int i = 1; i <= n; i++) { m->emplace(int(i), E_nc(10 * i)); } return m; } template NestMap *times_hundred(int n) { auto *m = new NestMap(); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { (*m)[i].emplace(int(j * 10), E_nc(100 * j)); } } return m; } TEST_SUBMODULE(stl_binders, m) { // test_vector_int py::bind_vector>(m, "VectorInt", py::buffer_protocol()); // test_vector_custom py::class_(m, "El").def(py::init()); py::bind_vector>(m, "VectorEl"); py::bind_vector>>(m, "VectorVectorEl"); // test_map_string_double py::bind_map>(m, "MapStringDouble"); py::bind_map>(m, "UnorderedMapStringDouble"); // test_map_string_double_const py::bind_map>(m, "MapStringDoubleConst"); py::bind_map>(m, "UnorderedMapStringDoubleConst"); py::class_(m, "ENC").def(py::init()).def_readwrite("value", &E_nc::value); // test_noncopyable_containers py::bind_vector>(m, "VectorENC"); m.def("get_vnc", &one_to_n>); py::bind_vector>(m, "DequeENC"); m.def("get_dnc", &one_to_n>); py::bind_map>(m, "MapENC"); m.def("get_mnc", ×_ten>); py::bind_map>(m, "UmapENC"); m.def("get_umnc", ×_ten>); // Issue #1885: binding nested std::map> with E non-copyable py::bind_map>>(m, "MapVecENC"); m.def("get_nvnc", [](int n) { auto *m = new std::map>(); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { (*m)[i].emplace_back(j); } } return m; }); py::bind_map>>(m, "MapMapENC"); m.def("get_nmnc", ×_hundred>>); py::bind_map>>(m, "UmapUmapENC"); m.def("get_numnc", ×_hundred>>); // test_vector_buffer py::bind_vector>(m, "VectorUChar", py::buffer_protocol()); // no dtype declared for this version: struct VUndeclStruct { bool w; uint32_t x; double y; bool z; }; m.def("create_undeclstruct", [m]() mutable { py::bind_vector>( m, "VectorUndeclStruct", py::buffer_protocol()); }); // The rest depends on numpy: try { py::module_::import("numpy"); } catch (...) { return; } // test_vector_buffer_numpy struct VStruct { bool w; uint32_t x; double y; bool z; }; PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z); py::class_(m, "VStruct").def_readwrite("x", &VStruct::x); py::bind_vector>(m, "VectorStruct", py::buffer_protocol()); m.def("get_vectorstruct", [] { return std::vector{{false, 5, 3.0, true}, {true, 30, -1e4, false}}; }); } aoflagger-v3.4.0/external/pybind11/tests/test_eval.py0000644000175000017500000000216714507760431021311 0ustar olesolesimport os import pytest import env # noqa: F401 from pybind11_tests import eval_ as m def test_evals(capture): with capture: assert m.test_eval_statements() assert capture == "Hello World!" assert m.test_eval() assert m.test_eval_single_statement() assert m.test_eval_failure() @pytest.mark.xfail("env.PYPY", raises=RuntimeError) def test_eval_file(): filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py") assert m.test_eval_file(filename) assert m.test_eval_file_failure() def test_eval_empty_globals(): assert "__builtins__" in m.eval_empty_globals(None) g = {} assert "__builtins__" in m.eval_empty_globals(g) assert "__builtins__" in g def test_eval_closure(): global_, local = m.test_eval_closure() assert global_["closure_value"] == 42 assert local["closure_value"] == 0 assert "local_value" not in global_ assert local["local_value"] == 0 assert "func_global" not in global_ assert local["func_global"]() == 42 assert "func_local" not in global_ with pytest.raises(NameError): local["func_local"]() aoflagger-v3.4.0/external/pybind11/tests/test_chrono.cpp0000644000175000017500000000645214507760431022005 0ustar olesoles/* tests/test_chrono.cpp -- test conversions to/from std::chrono types Copyright (c) 2016 Trent Houliston and Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "pybind11_tests.h" #include struct different_resolutions { using time_point_h = std::chrono::time_point; using time_point_m = std::chrono::time_point; using time_point_s = std::chrono::time_point; using time_point_ms = std::chrono::time_point; using time_point_us = std::chrono::time_point; time_point_h timestamp_h; time_point_m timestamp_m; time_point_s timestamp_s; time_point_ms timestamp_ms; time_point_us timestamp_us; }; TEST_SUBMODULE(chrono, m) { using system_time = std::chrono::system_clock::time_point; using steady_time = std::chrono::steady_clock::time_point; using timespan = std::chrono::duration; using timestamp = std::chrono::time_point; // test_chrono_system_clock // Return the current time off the wall clock m.def("test_chrono1", []() { return std::chrono::system_clock::now(); }); // test_chrono_system_clock_roundtrip // Round trip the passed in system clock time m.def("test_chrono2", [](system_time t) { return t; }); // test_chrono_duration_roundtrip // Round trip the passed in duration m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; }); // test_chrono_duration_subtraction_equivalence // Difference between two passed in time_points m.def("test_chrono4", [](system_time a, system_time b) { return a - b; }); // test_chrono_steady_clock // Return the current time off the steady_clock m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); }); // test_chrono_steady_clock_roundtrip // Round trip a steady clock timepoint m.def("test_chrono6", [](steady_time t) { return t; }); // test_floating_point_duration // Roundtrip a duration in microseconds from a float argument m.def("test_chrono7", [](std::chrono::microseconds t) { return t; }); // Float durations (issue #719) m.def("test_chrono_float_diff", [](std::chrono::duration a, std::chrono::duration b) { return a - b; }); m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp { return start + delta; }); // Test different resolutions py::class_(m, "different_resolutions") .def(py::init<>()) .def_readwrite("timestamp_h", &different_resolutions::timestamp_h) .def_readwrite("timestamp_m", &different_resolutions::timestamp_m) .def_readwrite("timestamp_s", &different_resolutions::timestamp_s) .def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms) .def_readwrite("timestamp_us", &different_resolutions::timestamp_us); } aoflagger-v3.4.0/external/pybind11/tests/test_pytypes.cpp0000644000175000017500000007403614507760431022235 0ustar olesoles/* tests/test_pytypes.cpp -- Python type casters Copyright (c) 2017 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "pybind11_tests.h" #include namespace external { namespace detail { bool check(PyObject *o) { return PyFloat_Check(o) != 0; } PyObject *conv(PyObject *o) { PyObject *ret = nullptr; if (PyLong_Check(o)) { double v = PyLong_AsDouble(o); if (!(v == -1.0 && PyErr_Occurred())) { ret = PyFloat_FromDouble(v); } } else { PyErr_SetString(PyExc_TypeError, "Unexpected type"); } return ret; } PyObject *default_constructed() { return PyFloat_FromDouble(0.0); } } // namespace detail class float_ : public py::object { PYBIND11_OBJECT_CVT(float_, py::object, external::detail::check, external::detail::conv) float_() : py::object(external::detail::default_constructed(), stolen_t{}) {} double get_value() const { return PyFloat_AsDouble(this->ptr()); } }; } // namespace external namespace implicit_conversion_from_0_to_handle { // Uncomment to trigger compiler error. Note: Before PR #4008 this used to compile successfully. // void expected_to_trigger_compiler_error() { py::handle(0); } } // namespace implicit_conversion_from_0_to_handle // Used to validate systematically that PR #4008 does/did NOT change the behavior. void pure_compile_tests_for_handle_from_PyObject_pointers() { { PyObject *ptr = Py_None; py::handle{ptr}; } { PyObject *const ptr = Py_None; py::handle{ptr}; } // Uncomment to trigger compiler errors. // PyObject const * ptr = Py_None; py::handle{ptr}; // PyObject const *const ptr = Py_None; py::handle{ptr}; // PyObject volatile * ptr = Py_None; py::handle{ptr}; // PyObject volatile *const ptr = Py_None; py::handle{ptr}; // PyObject const volatile * ptr = Py_None; py::handle{ptr}; // PyObject const volatile *const ptr = Py_None; py::handle{ptr}; } namespace handle_from_move_only_type_with_operator_PyObject { // Reduced from // https://github.com/pytorch/pytorch/blob/279634f384662b7c3a9f8bf7ccc3a6afd2f05657/torch/csrc/utils/object_ptr.h struct operator_ncnst { operator_ncnst() = default; operator_ncnst(operator_ncnst &&) = default; operator PyObject *() /* */ { return Py_None; } // NOLINT(google-explicit-constructor) }; struct operator_const { operator_const() = default; operator_const(operator_const &&) = default; operator PyObject *() const { return Py_None; } // NOLINT(google-explicit-constructor) }; bool from_ncnst() { operator_ncnst obj; auto h = py::handle(obj); // Critical part of test: does this compile? return h.ptr() == Py_None; // Just something. } bool from_const() { operator_const obj; auto h = py::handle(obj); // Critical part of test: does this compile? return h.ptr() == Py_None; // Just something. } void m_defs(py::module_ &m) { m.def("handle_from_move_only_type_with_operator_PyObject_ncnst", from_ncnst); m.def("handle_from_move_only_type_with_operator_PyObject_const", from_const); } } // namespace handle_from_move_only_type_with_operator_PyObject TEST_SUBMODULE(pytypes, m) { m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); }); handle_from_move_only_type_with_operator_PyObject::m_defs(m); // test_bool m.def("get_bool", [] { return py::bool_(false); }); // test_int m.def("get_int", [] { return py::int_(0); }); // test_iterator m.def("get_iterator", [] { return py::iterator(); }); // test_iterable m.def("get_iterable", [] { return py::iterable(); }); m.def("get_frozenset_from_iterable", [](const py::iterable &iter) { return py::frozenset(iter); }); m.def("get_list_from_iterable", [](const py::iterable &iter) { return py::list(iter); }); m.def("get_set_from_iterable", [](const py::iterable &iter) { return py::set(iter); }); m.def("get_tuple_from_iterable", [](const py::iterable &iter) { return py::tuple(iter); }); // test_float m.def("get_float", [] { return py::float_(0.0f); }); // test_list m.def("list_no_args", []() { return py::list{}; }); m.def("list_ssize_t", []() { return py::list{(py::ssize_t) 0}; }); m.def("list_size_t", []() { return py::list{(py::size_t) 0}; }); m.def("list_insert_ssize_t", [](py::list *l) { return l->insert((py::ssize_t) 1, 83); }); m.def("list_insert_size_t", [](py::list *l) { return l->insert((py::size_t) 3, 57); }); m.def("get_list", []() { py::list list; list.append("value"); py::print("Entry at position 0:", list[0]); list[0] = py::str("overwritten"); list.insert(0, "inserted-0"); list.insert(2, "inserted-2"); return list; }); m.def("print_list", [](const py::list &list) { int index = 0; for (auto item : list) { py::print("list item {}: {}"_s.format(index++, item)); } }); // test_none m.def("get_none", [] { return py::none(); }); m.def("print_none", [](const py::none &none) { py::print("none: {}"_s.format(none)); }); // test_set, test_frozenset m.def("get_set", []() { py::set set; set.add(py::str("key1")); set.add("key2"); set.add(std::string("key3")); return set; }); m.def("get_frozenset", []() { py::set set; set.add(py::str("key1")); set.add("key2"); set.add(std::string("key3")); return py::frozenset(set); }); m.def("print_anyset", [](const py::anyset &set) { for (auto item : set) { py::print("key:", item); } }); m.def("anyset_size", [](const py::anyset &set) { return set.size(); }); m.def("anyset_empty", [](const py::anyset &set) { return set.empty(); }); m.def("anyset_contains", [](const py::anyset &set, const py::object &key) { return set.contains(key); }); m.def("anyset_contains", [](const py::anyset &set, const char *key) { return set.contains(key); }); m.def("set_add", [](py::set &set, const py::object &key) { set.add(key); }); m.def("set_clear", [](py::set &set) { set.clear(); }); // test_dict m.def("get_dict", []() { return py::dict("key"_a = "value"); }); m.def("print_dict", [](const py::dict &dict) { for (auto item : dict) { py::print("key: {}, value={}"_s.format(item.first, item.second)); } }); m.def("dict_keyword_constructor", []() { auto d1 = py::dict("x"_a = 1, "y"_a = 2); auto d2 = py::dict("z"_a = 3, **d1); return d2; }); m.def("dict_contains", [](const py::dict &dict, const py::object &val) { return dict.contains(val); }); m.def("dict_contains", [](const py::dict &dict, const char *val) { return dict.contains(val); }); // test_tuple m.def("tuple_no_args", []() { return py::tuple{}; }); m.def("tuple_ssize_t", []() { return py::tuple{(py::ssize_t) 0}; }); m.def("tuple_size_t", []() { return py::tuple{(py::size_t) 0}; }); m.def("get_tuple", []() { return py::make_tuple(42, py::none(), "spam"); }); // test_simple_namespace m.def("get_simple_namespace", []() { auto ns = py::module_::import("types").attr("SimpleNamespace")( "attr"_a = 42, "x"_a = "foo", "wrong"_a = 1); py::delattr(ns, "wrong"); py::setattr(ns, "right", py::int_(2)); return ns; }); // test_str m.def("str_from_char_ssize_t", []() { return py::str{"red", (py::ssize_t) 3}; }); m.def("str_from_char_size_t", []() { return py::str{"blue", (py::size_t) 4}; }); m.def("str_from_string", []() { return py::str(std::string("baz")); }); m.def("str_from_std_string_input", [](const std::string &stri) { return py::str(stri); }); m.def("str_from_cstr_input", [](const char *c_str) { return py::str(c_str); }); m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); }); m.def("str_from_bytes_input", [](const py::bytes &encoded_str) { return py::str(encoded_str); }); m.def("str_from_object", [](const py::object &obj) { return py::str(obj); }); m.def("repr_from_object", [](const py::object &obj) { return py::repr(obj); }); m.def("str_from_handle", [](py::handle h) { return py::str(h); }); m.def("str_from_string_from_str", [](const py::str &obj) { return py::str(static_cast(obj)); }); m.def("str_format", []() { auto s1 = "{} + {} = {}"_s.format(1, 2, 3); auto s2 = "{a} + {b} = {c}"_s.format("a"_a = 1, "b"_a = 2, "c"_a = 3); return py::make_tuple(s1, s2); }); // test_bytes m.def("bytes_from_char_ssize_t", []() { return py::bytes{"green", (py::ssize_t) 5}; }); m.def("bytes_from_char_size_t", []() { return py::bytes{"purple", (py::size_t) 6}; }); m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); }); m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); }); // test bytearray m.def("bytearray_from_char_ssize_t", []() { return py::bytearray{"$%", (py::ssize_t) 2}; }); m.def("bytearray_from_char_size_t", []() { return py::bytearray{"@$!", (py::size_t) 3}; }); m.def("bytearray_from_string", []() { return py::bytearray(std::string("foo")); }); m.def("bytearray_size", []() { return py::bytearray("foo").size(); }); // test_capsule m.def("return_capsule_with_destructor", []() { py::print("creating capsule"); return py::capsule([]() { py::print("destructing capsule"); }); }); m.def("return_renamed_capsule_with_destructor", []() { py::print("creating capsule"); auto cap = py::capsule([]() { py::print("destructing capsule"); }); static const char *capsule_name = "test_name1"; py::print("renaming capsule"); cap.set_name(capsule_name); return cap; }); m.def("return_capsule_with_destructor_2", []() { py::print("creating capsule"); return py::capsule((void *) 1234, [](void *ptr) { py::print("destructing capsule: {}"_s.format((size_t) ptr)); }); }); m.def("return_renamed_capsule_with_destructor_2", []() { py::print("creating capsule"); auto cap = py::capsule((void *) 1234, [](void *ptr) { py::print("destructing capsule: {}"_s.format((size_t) ptr)); }); static const char *capsule_name = "test_name2"; py::print("renaming capsule"); cap.set_name(capsule_name); return cap; }); m.def("return_capsule_with_name_and_destructor", []() { auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) { if (ptr) { const auto *name = PyCapsule_GetName(ptr); py::print("destructing capsule ({}, '{}')"_s.format( (size_t) PyCapsule_GetPointer(ptr, name), name)); } }); capsule.set_pointer((void *) 1234); // Using get_pointer() void *contents1 = static_cast(capsule); void *contents2 = capsule.get_pointer(); void *contents3 = capsule.get_pointer(); auto result1 = reinterpret_cast(contents1); auto result2 = reinterpret_cast(contents2); auto result3 = reinterpret_cast(contents3); py::print( "created capsule ({}, '{}')"_s.format(result1 & result2 & result3, capsule.name())); return capsule; }); m.def("return_capsule_with_explicit_nullptr_dtor", []() { py::print("creating capsule with explicit nullptr dtor"); return py::capsule(reinterpret_cast(1234), static_cast(nullptr)); // PR #4221 }); // test_accessors m.def("accessor_api", [](const py::object &o) { auto d = py::dict(); d["basic_attr"] = o.attr("basic_attr"); auto l = py::list(); for (auto item : o.attr("begin_end")) { l.append(item); } d["begin_end"] = l; d["operator[object]"] = o.attr("d")["operator[object]"_s]; d["operator[char *]"] = o.attr("d")["operator[char *]"]; d["attr(object)"] = o.attr("sub").attr("attr_obj"); d["attr(char *)"] = o.attr("sub").attr("attr_char"); try { o.attr("sub").attr("missing").ptr(); } catch (const py::error_already_set &) { d["missing_attr_ptr"] = "raised"_s; } try { o.attr("missing").attr("doesn't matter"); } catch (const py::error_already_set &) { d["missing_attr_chain"] = "raised"_s; } d["is_none"] = o.attr("basic_attr").is_none(); d["operator()"] = o.attr("func")(1); d["operator*"] = o.attr("func")(*o.attr("begin_end")); // Test implicit conversion py::list implicit_list = o.attr("begin_end"); d["implicit_list"] = implicit_list; py::dict implicit_dict = o.attr("__dict__"); d["implicit_dict"] = implicit_dict; return d; }); m.def("tuple_accessor", [](const py::tuple &existing_t) { try { existing_t[0] = 1; } catch (const py::error_already_set &) { // --> Python system error // Only new tuples (refcount == 1) are mutable auto new_t = py::tuple(3); for (size_t i = 0; i < new_t.size(); ++i) { new_t[i] = i; } return new_t; } return py::tuple(); }); m.def("accessor_assignment", []() { auto l = py::list(1); l[0] = 0; auto d = py::dict(); d["get"] = l[0]; auto var = l[0]; d["deferred_get"] = var; l[0] = 1; d["set"] = l[0]; var = 99; // this assignment should not overwrite l[0] d["deferred_set"] = l[0]; d["var"] = var; return d; }); m.def("accessor_moves", []() { // See PR #3970 py::list return_list; #ifdef PYBIND11_HANDLE_REF_DEBUG py::int_ py_int_0(0); py::int_ py_int_42(42); py::str py_str_count("count"); auto tup = py::make_tuple(0); py::sequence seq(tup); py::list lst; lst.append(0); # define PYBIND11_LOCAL_DEF(...) \ { \ std::size_t inc_refs = py::handle::inc_ref_counter(); \ __VA_ARGS__; \ inc_refs = py::handle::inc_ref_counter() - inc_refs; \ return_list.append(inc_refs); \ } PYBIND11_LOCAL_DEF(tup[py_int_0]) // l-value (to have a control) PYBIND11_LOCAL_DEF(tup[py::int_(0)]) // r-value PYBIND11_LOCAL_DEF(tup.attr(py_str_count)) // l-value PYBIND11_LOCAL_DEF(tup.attr(py::str("count"))) // r-value PYBIND11_LOCAL_DEF(seq[py_int_0]) // l-value PYBIND11_LOCAL_DEF(seq[py::int_(0)]) // r-value PYBIND11_LOCAL_DEF(seq.attr(py_str_count)) // l-value PYBIND11_LOCAL_DEF(seq.attr(py::str("count"))) // r-value PYBIND11_LOCAL_DEF(lst[py_int_0]) // l-value PYBIND11_LOCAL_DEF(lst[py::int_(0)]) // r-value PYBIND11_LOCAL_DEF(lst.attr(py_str_count)) // l-value PYBIND11_LOCAL_DEF(lst.attr(py::str("count"))) // r-value auto lst_acc = lst[py::int_(0)]; lst_acc = py::int_(42); // Detaches lst_acc from lst. PYBIND11_LOCAL_DEF(lst_acc = py_int_42) // l-value PYBIND11_LOCAL_DEF(lst_acc = py::int_(42)) // r-value # undef PYBIND11_LOCAL_DEF #endif return return_list; }); // test_constructors m.def("default_constructors", []() { return py::dict("bytes"_a = py::bytes(), "bytearray"_a = py::bytearray(), "str"_a = py::str(), "bool"_a = py::bool_(), "int"_a = py::int_(), "float"_a = py::float_(), "tuple"_a = py::tuple(), "list"_a = py::list(), "dict"_a = py::dict(), "set"_a = py::set()); }); m.def("converting_constructors", [](const py::dict &d) { return py::dict("bytes"_a = py::bytes(d["bytes"]), "bytearray"_a = py::bytearray(d["bytearray"]), "str"_a = py::str(d["str"]), "bool"_a = py::bool_(d["bool"]), "int"_a = py::int_(d["int"]), "float"_a = py::float_(d["float"]), "tuple"_a = py::tuple(d["tuple"]), "list"_a = py::list(d["list"]), "dict"_a = py::dict(d["dict"]), "set"_a = py::set(d["set"]), "frozenset"_a = py::frozenset(d["frozenset"]), "memoryview"_a = py::memoryview(d["memoryview"])); }); m.def("cast_functions", [](const py::dict &d) { // When converting between Python types, obj.cast() should be the same as T(obj) return py::dict("bytes"_a = d["bytes"].cast(), "bytearray"_a = d["bytearray"].cast(), "str"_a = d["str"].cast(), "bool"_a = d["bool"].cast(), "int"_a = d["int"].cast(), "float"_a = d["float"].cast(), "tuple"_a = d["tuple"].cast(), "list"_a = d["list"].cast(), "dict"_a = d["dict"].cast(), "set"_a = d["set"].cast(), "frozenset"_a = d["frozenset"].cast(), "memoryview"_a = d["memoryview"].cast()); }); m.def("convert_to_pybind11_str", [](const py::object &o) { return py::str(o); }); m.def("nonconverting_constructor", [](const std::string &type, py::object value, bool move) -> py::object { if (type == "bytes") { return move ? py::bytes(std::move(value)) : py::bytes(value); } if (type == "none") { return move ? py::none(std::move(value)) : py::none(value); } if (type == "ellipsis") { return move ? py::ellipsis(std::move(value)) : py::ellipsis(value); } if (type == "type") { return move ? py::type(std::move(value)) : py::type(value); } throw std::runtime_error("Invalid type"); }); m.def("get_implicit_casting", []() { py::dict d; d["char*_i1"] = "abc"; const char *c2 = "abc"; d["char*_i2"] = c2; d["char*_e"] = py::cast(c2); d["char*_p"] = py::str(c2); d["int_i1"] = 42; int i = 42; d["int_i2"] = i; i++; d["int_e"] = py::cast(i); i++; d["int_p"] = py::int_(i); d["str_i1"] = std::string("str"); std::string s2("str1"); d["str_i2"] = s2; s2[3] = '2'; d["str_e"] = py::cast(s2); s2[3] = '3'; d["str_p"] = py::str(s2); py::list l(2); l[0] = 3; l[1] = py::cast(6); l.append(9); l.append(py::cast(12)); l.append(py::int_(15)); return py::dict("d"_a = d, "l"_a = l); }); // test_print m.def("print_function", []() { py::print("Hello, World!"); py::print(1, 2.0, "three", true, std::string("-- multiple args")); auto args = py::make_tuple("and", "a", "custom", "separator"); py::print("*args", *args, "sep"_a = "-"); py::print("no new line here", "end"_a = " -- "); py::print("next print"); auto py_stderr = py::module_::import("sys").attr("stderr"); py::print("this goes to stderr", "file"_a = py_stderr); py::print("flush", "flush"_a = true); py::print( "{a} + {b} = {c}"_s.format("a"_a = "py::print", "b"_a = "str.format", "c"_a = "this")); }); m.def("print_failure", []() { py::print(42, UnregisteredType()); }); m.def("hash_function", [](py::object obj) { return py::hash(std::move(obj)); }); m.def("obj_contains", [](py::object &obj, const py::object &key) { return obj.contains(key); }); m.def("test_number_protocol", [](const py::object &a, const py::object &b) { py::list l; l.append(a.equal(b)); l.append(a.not_equal(b)); l.append(a < b); l.append(a <= b); l.append(a > b); l.append(a >= b); l.append(a + b); l.append(a - b); l.append(a * b); l.append(a / b); l.append(a | b); l.append(a & b); l.append(a ^ b); l.append(a >> b); l.append(a << b); return l; }); m.def("test_list_slicing", [](const py::list &a) { return a[py::slice(0, -1, 2)]; }); // See #2361 m.def("issue2361_str_implicit_copy_none", []() { py::str is_this_none = py::none(); return is_this_none; }); m.def("issue2361_dict_implicit_copy_none", []() { py::dict is_this_none = py::none(); return is_this_none; }); m.def("test_memoryview_object", [](const py::buffer &b) { return py::memoryview(b); }); m.def("test_memoryview_buffer_info", [](const py::buffer &b) { return py::memoryview(b.request()); }); m.def("test_memoryview_from_buffer", [](bool is_unsigned) { static const int16_t si16[] = {3, 1, 4, 1, 5}; static const uint16_t ui16[] = {2, 7, 1, 8}; if (is_unsigned) { return py::memoryview::from_buffer(ui16, {4}, {sizeof(uint16_t)}); } return py::memoryview::from_buffer(si16, {5}, {sizeof(int16_t)}); }); m.def("test_memoryview_from_buffer_nativeformat", []() { static const char *format = "@i"; static const int32_t arr[] = {4, 7, 5}; return py::memoryview::from_buffer(arr, sizeof(int32_t), format, {3}, {sizeof(int32_t)}); }); m.def("test_memoryview_from_buffer_empty_shape", []() { static const char *buf = ""; return py::memoryview::from_buffer(buf, 1, "B", {}, {}); }); m.def("test_memoryview_from_buffer_invalid_strides", []() { static const char *buf = "\x02\x03\x04"; return py::memoryview::from_buffer(buf, 1, "B", {3}, {}); }); m.def("test_memoryview_from_buffer_nullptr", []() { return py::memoryview::from_buffer(static_cast(nullptr), 1, "B", {}, {}); }); m.def("test_memoryview_from_memory", []() { const char *buf = "\xff\xe1\xab\x37"; return py::memoryview::from_memory(buf, static_cast(strlen(buf))); }); // test_builtin_functions m.def("get_len", [](py::handle h) { return py::len(h); }); #ifdef PYBIND11_STR_LEGACY_PERMISSIVE m.attr("PYBIND11_STR_LEGACY_PERMISSIVE") = true; #endif m.def("isinstance_pybind11_bytes", [](py::object o) { return py::isinstance(std::move(o)); }); m.def("isinstance_pybind11_str", [](py::object o) { return py::isinstance(std::move(o)); }); m.def("pass_to_pybind11_bytes", [](py::bytes b) { return py::len(std::move(b)); }); m.def("pass_to_pybind11_str", [](py::str s) { return py::len(std::move(s)); }); m.def("pass_to_std_string", [](const std::string &s) { return s.size(); }); // test_weakref m.def("weakref_from_handle", [](py::handle h) { return py::weakref(h); }); m.def("weakref_from_handle_and_function", [](py::handle h, py::function f) { return py::weakref(h, std::move(f)); }); m.def("weakref_from_object", [](const py::object &o) { return py::weakref(o); }); m.def("weakref_from_object_and_function", [](py::object o, py::function f) { return py::weakref(std::move(o), std::move(f)); }); // See PR #3263 for background (https://github.com/pybind/pybind11/pull/3263): // pytypes.h could be changed to enforce the "most correct" user code below, by removing // `const` from iterator `reference` using type aliases, but that will break existing // user code. #if (defined(__APPLE__) && defined(__clang__)) || defined(PYPY_VERSION) // This is "most correct" and enforced on these platforms. # define PYBIND11_AUTO_IT auto it #else // This works on many platforms and is (unfortunately) reflective of existing user code. // NOLINTNEXTLINE(bugprone-macro-parentheses) # define PYBIND11_AUTO_IT auto &it #endif m.def("tuple_iterator", []() { auto tup = py::make_tuple(5, 7); int tup_sum = 0; for (PYBIND11_AUTO_IT : tup) { tup_sum += it.cast(); } return tup_sum; }); m.def("dict_iterator", []() { py::dict dct; dct[py::int_(3)] = 5; dct[py::int_(7)] = 11; int kv_sum = 0; for (PYBIND11_AUTO_IT : dct) { kv_sum += it.first.cast() * 100 + it.second.cast(); } return kv_sum; }); m.def("passed_iterator", [](const py::iterator &py_it) { int elem_sum = 0; for (PYBIND11_AUTO_IT : py_it) { elem_sum += it.cast(); } return elem_sum; }); #undef PYBIND11_AUTO_IT // Tests below this line are for pybind11 IMPLEMENTATION DETAILS: m.def("sequence_item_get_ssize_t", [](const py::object &o) { return py::detail::accessor_policies::sequence_item::get(o, (py::ssize_t) 1); }); m.def("sequence_item_set_ssize_t", [](const py::object &o) { auto s = py::str{"peppa", 5}; py::detail::accessor_policies::sequence_item::set(o, (py::ssize_t) 1, s); }); m.def("sequence_item_get_size_t", [](const py::object &o) { return py::detail::accessor_policies::sequence_item::get(o, (py::size_t) 2); }); m.def("sequence_item_set_size_t", [](const py::object &o) { auto s = py::str{"george", 6}; py::detail::accessor_policies::sequence_item::set(o, (py::size_t) 2, s); }); m.def("list_item_get_ssize_t", [](const py::object &o) { return py::detail::accessor_policies::list_item::get(o, (py::ssize_t) 3); }); m.def("list_item_set_ssize_t", [](const py::object &o) { auto s = py::str{"rebecca", 7}; py::detail::accessor_policies::list_item::set(o, (py::ssize_t) 3, s); }); m.def("list_item_get_size_t", [](const py::object &o) { return py::detail::accessor_policies::list_item::get(o, (py::size_t) 4); }); m.def("list_item_set_size_t", [](const py::object &o) { auto s = py::str{"richard", 7}; py::detail::accessor_policies::list_item::set(o, (py::size_t) 4, s); }); m.def("tuple_item_get_ssize_t", [](const py::object &o) { return py::detail::accessor_policies::tuple_item::get(o, (py::ssize_t) 5); }); m.def("tuple_item_set_ssize_t", []() { auto s0 = py::str{"emely", 5}; auto s1 = py::str{"edmond", 6}; auto o = py::tuple{2}; py::detail::accessor_policies::tuple_item::set(o, (py::ssize_t) 0, s0); py::detail::accessor_policies::tuple_item::set(o, (py::ssize_t) 1, s1); return o; }); m.def("tuple_item_get_size_t", [](const py::object &o) { return py::detail::accessor_policies::tuple_item::get(o, (py::size_t) 6); }); m.def("tuple_item_set_size_t", []() { auto s0 = py::str{"candy", 5}; auto s1 = py::str{"cat", 3}; auto o = py::tuple{2}; py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 1, s1); py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 0, s0); return o; }); m.def("square_float_", [](const external::float_ &x) -> double { double v = x.get_value(); return v * v; }); m.def("tuple_rvalue_getter", [](const py::tuple &tup) { // tests accessing tuple object with rvalue int for (size_t i = 0; i < tup.size(); i++) { auto o = py::handle(tup[py::int_(i)]); if (!o) { throw py::value_error("tuple is malformed"); } } return tup; }); m.def("list_rvalue_getter", [](const py::list &l) { // tests accessing list with rvalue int for (size_t i = 0; i < l.size(); i++) { auto o = py::handle(l[py::int_(i)]); if (!o) { throw py::value_error("list is malformed"); } } return l; }); m.def("populate_dict_rvalue", [](int population) { auto d = py::dict(); for (int i = 0; i < population; i++) { d[py::int_(i)] = py::int_(i); } return d; }); m.def("populate_obj_str_attrs", [](py::object &o, int population) { for (int i = 0; i < population; i++) { o.attr(py::str(py::int_(i))) = py::str(py::int_(i)); } return o; }); // testing immutable object augmented assignment: #issue 3812 m.def("inplace_append", [](py::object &a, const py::object &b) { a += b; return a; }); m.def("inplace_subtract", [](py::object &a, const py::object &b) { a -= b; return a; }); m.def("inplace_multiply", [](py::object &a, const py::object &b) { a *= b; return a; }); m.def("inplace_divide", [](py::object &a, const py::object &b) { a /= b; return a; }); m.def("inplace_or", [](py::object &a, const py::object &b) { a |= b; return a; }); m.def("inplace_and", [](py::object &a, const py::object &b) { a &= b; return a; }); m.def("inplace_lshift", [](py::object &a, const py::object &b) { a <<= b; return a; }); m.def("inplace_rshift", [](py::object &a, const py::object &b) { a >>= b; return a; }); } aoflagger-v3.4.0/external/pybind11/tests/test_sequences_and_iterators.py0000644000175000017500000001754714507760431025303 0ustar olesolesimport pytest from pytest import approx # noqa: PT013 from pybind11_tests import ConstructorStats from pybind11_tests import sequences_and_iterators as m def test_slice_constructors(): assert m.make_forward_slice_size_t() == slice(0, -1, 1) assert m.make_reversed_slice_object() == slice(None, None, -1) @pytest.mark.skipif(not m.has_optional, reason="no ") def test_slice_constructors_explicit_optional(): assert m.make_reversed_slice_size_t_optional() == slice(None, None, -1) assert m.make_reversed_slice_size_t_optional_verbose() == slice(None, None, -1) def test_generalized_iterators(): assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)] assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)] assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == [] assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3] assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1] assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == [] assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_values()) == [2, 4] assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_values()) == [2] assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_values()) == [] # __next__ must continue to raise StopIteration it = m.IntPairs([(0, 0)]).nonzero() for _ in range(3): with pytest.raises(StopIteration): next(it) it = m.IntPairs([(0, 0)]).nonzero_keys() for _ in range(3): with pytest.raises(StopIteration): next(it) def test_nonref_iterators(): pairs = m.IntPairs([(1, 2), (3, 4), (0, 5)]) assert list(pairs.nonref()) == [(1, 2), (3, 4), (0, 5)] assert list(pairs.nonref_keys()) == [1, 3, 0] assert list(pairs.nonref_values()) == [2, 4, 5] def test_generalized_iterators_simple(): assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_iterator()) == [ (1, 2), (3, 4), (0, 5), ] assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_keys()) == [1, 3, 0] assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_values()) == [2, 4, 5] def test_iterator_referencing(): """Test that iterators reference rather than copy their referents.""" vec = m.VectorNonCopyableInt() vec.append(3) vec.append(5) assert [int(x) for x in vec] == [3, 5] # Increment everything to make sure the referents can be mutated for x in vec: x.set(int(x) + 1) assert [int(x) for x in vec] == [4, 6] vec = m.VectorNonCopyableIntPair() vec.append([3, 4]) vec.append([5, 7]) assert [int(x) for x in vec.keys()] == [3, 5] assert [int(x) for x in vec.values()] == [4, 7] for x in vec.keys(): x.set(int(x) + 1) for x in vec.values(): x.set(int(x) + 10) assert [int(x) for x in vec.keys()] == [4, 6] assert [int(x) for x in vec.values()] == [14, 17] def test_sliceable(): sliceable = m.Sliceable(100) assert sliceable[::] == (0, 100, 1) assert sliceable[10::] == (10, 100, 1) assert sliceable[:10:] == (0, 10, 1) assert sliceable[::10] == (0, 100, 10) assert sliceable[-10::] == (90, 100, 1) assert sliceable[:-10:] == (0, 90, 1) assert sliceable[::-10] == (99, -1, -10) assert sliceable[50:60:1] == (50, 60, 1) assert sliceable[50:60:-1] == (50, 60, -1) def test_sequence(): cstats = ConstructorStats.get(m.Sequence) s = m.Sequence(5) assert cstats.values() == ["of size", "5"] assert "Sequence" in repr(s) assert len(s) == 5 assert s[0] == 0 assert s[3] == 0 assert 12.34 not in s s[0], s[3] = 12.34, 56.78 assert 12.34 in s assert s[0] == approx(12.34, rel=1e-05) assert s[3] == approx(56.78, rel=1e-05) rev = reversed(s) assert cstats.values() == ["of size", "5"] rev2 = s[::-1] assert cstats.values() == ["of size", "5"] it = iter(m.Sequence(0)) for _ in range(3): # __next__ must continue to raise StopIteration with pytest.raises(StopIteration): next(it) assert cstats.values() == ["of size", "0"] expected = [0, 56.78, 0, 0, 12.34] assert rev == approx(expected, rel=1e-05) assert rev2 == approx(expected, rel=1e-05) assert rev == rev2 rev[0::2] = m.Sequence([2.0, 2.0, 2.0]) assert cstats.values() == ["of size", "3", "from std::vector"] assert rev == approx([2, 56.78, 2, 0, 2], rel=1e-05) assert cstats.alive() == 4 del it assert cstats.alive() == 3 del s assert cstats.alive() == 2 del rev assert cstats.alive() == 1 del rev2 assert cstats.alive() == 0 assert cstats.values() == [] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 1 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 def test_sequence_length(): """#2076: Exception raised by len(arg) should be propagated""" class BadLen(RuntimeError): pass class SequenceLike: def __getitem__(self, i): return None def __len__(self): raise BadLen() with pytest.raises(BadLen): m.sequence_length(SequenceLike()) assert m.sequence_length([1, 2, 3]) == 3 assert m.sequence_length("hello") == 5 def test_map_iterator(): sm = m.StringMap({"hi": "bye", "black": "white"}) assert sm["hi"] == "bye" assert len(sm) == 2 assert sm["black"] == "white" with pytest.raises(KeyError): assert sm["orange"] sm["orange"] = "banana" assert sm["orange"] == "banana" expected = {"hi": "bye", "black": "white", "orange": "banana"} for k in sm: assert sm[k] == expected[k] for k, v in sm.items(): assert v == expected[k] assert list(sm.values()) == [expected[k] for k in sm] it = iter(m.StringMap({})) for _ in range(3): # __next__ must continue to raise StopIteration with pytest.raises(StopIteration): next(it) def test_python_iterator_in_cpp(): t = (1, 2, 3) assert m.object_to_list(t) == [1, 2, 3] assert m.object_to_list(iter(t)) == [1, 2, 3] assert m.iterator_to_list(iter(t)) == [1, 2, 3] with pytest.raises(TypeError) as excinfo: m.object_to_list(1) assert "object is not iterable" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.iterator_to_list(1) assert "incompatible function arguments" in str(excinfo.value) def bad_next_call(): raise RuntimeError("py::iterator::advance() should propagate errors") with pytest.raises(RuntimeError) as excinfo: m.iterator_to_list(iter(bad_next_call, None)) assert str(excinfo.value) == "py::iterator::advance() should propagate errors" lst = [1, None, 0, None] assert m.count_none(lst) == 2 assert m.find_none(lst) is True assert m.count_nonzeros({"a": 0, "b": 1, "c": 2}) == 2 r = range(5) assert all(m.tuple_iterator(tuple(r))) assert all(m.list_iterator(list(r))) assert all(m.sequence_iterator(r)) def test_iterator_passthrough(): """#181: iterator passthrough did not compile""" from pybind11_tests.sequences_and_iterators import iterator_passthrough values = [3, 5, 7, 9, 11, 13, 15] assert list(iterator_passthrough(iter(values))) == values def test_iterator_rvp(): """#388: Can't make iterators via make_iterator() with different r/v policies""" import pybind11_tests.sequences_and_iterators as m assert list(m.make_iterator_1()) == [1, 2, 3] assert list(m.make_iterator_2()) == [1, 2, 3] assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2())) def test_carray_iterator(): """#4100: Check for proper iterator overload with C-Arrays""" args_gt = [float(i) for i in range(3)] arr_h = m.CArrayHolder(*args_gt) args = list(arr_h) assert args_gt == args aoflagger-v3.4.0/external/pybind11/tests/test_custom_type_casters.py0000644000175000017500000000763014507760431024461 0ustar olesolesimport pytest from pybind11_tests import custom_type_casters as m def test_noconvert_args(msg): a = m.ArgInspector() assert ( msg(a.f("hi")) == """ loading ArgInspector1 argument WITH conversion allowed. Argument value = hi """ ) assert ( msg(a.g("this is a", "this is b")) == """ loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 13 loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) """ ) assert ( msg(a.g("this is a", "this is b", 42)) == """ loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 42 loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) """ ) assert ( msg(a.g("this is a", "this is b", 42, "this is d")) == """ loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 42 loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d """ ) assert ( a.h("arg 1") == "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1" ) assert ( msg(m.arg_inspect_func("A1", "A2")) == """ loading ArgInspector2 argument WITH conversion allowed. Argument value = A1 loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2 """ ) assert m.floats_preferred(4) == 2.0 assert m.floats_only(4.0) == 2.0 with pytest.raises(TypeError) as excinfo: m.floats_only(4) assert ( msg(excinfo.value) == """ floats_only(): incompatible function arguments. The following argument types are supported: 1. (f: float) -> float Invoked with: 4 """ ) assert m.ints_preferred(4) == 2 assert m.ints_preferred(True) == 0 with pytest.raises(TypeError) as excinfo: m.ints_preferred(4.0) assert ( msg(excinfo.value) == """ ints_preferred(): incompatible function arguments. The following argument types are supported: 1. (i: int) -> int Invoked with: 4.0 """ ) assert m.ints_only(4) == 2 with pytest.raises(TypeError) as excinfo: m.ints_only(4.0) assert ( msg(excinfo.value) == """ ints_only(): incompatible function arguments. The following argument types are supported: 1. (i: int) -> int Invoked with: 4.0 """ ) def test_custom_caster_destruction(): """Tests that returning a pointer to a type that gets converted with a custom type caster gets destroyed when the function has py::return_value_policy::take_ownership policy applied. """ cstats = m.destruction_tester_cstats() # This one *doesn't* have take_ownership: the pointer should be used but not destroyed: z = m.custom_caster_no_destroy() assert cstats.alive() == 1 assert cstats.default_constructions == 1 assert z # take_ownership applied: this constructs a new object, casts it, then destroys it: z = m.custom_caster_destroy() assert z assert cstats.default_constructions == 2 # Same, but with a const pointer return (which should *not* inhibit destruction): z = m.custom_caster_destroy_const() assert z assert cstats.default_constructions == 3 # Make sure we still only have the original object (from ..._no_destroy()) alive: assert cstats.alive() == 1 def test_custom_caster_other_lib(): assert m.other_lib_type(True) aoflagger-v3.4.0/external/pybind11/tests/test_numpy_vectorize.py0000644000175000017500000002267214507760431023627 0ustar olesolesimport pytest from pybind11_tests import numpy_vectorize as m np = pytest.importorskip("numpy") def test_vectorize(capture): assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j]) for f in [m.vectorized_func, m.vectorized_func2]: with capture: assert np.isclose(f(1, 2, 3), 6) assert capture == "my_func(x:int=1, y:float=2, z:float=3)" with capture: assert np.isclose(f(np.array(1), np.array(2), 3), 6) assert capture == "my_func(x:int=1, y:float=2, z:float=3)" with capture: assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36]) assert ( capture == """ my_func(x:int=1, y:float=2, z:float=3) my_func(x:int=3, y:float=4, z:float=3) """ ) with capture: a = np.array([[1, 2], [3, 4]], order="F") b = np.array([[10, 20], [30, 40]], order="F") c = 3 result = f(a, b, c) assert np.allclose(result, a * b * c) assert result.flags.f_contiguous # All inputs are F order and full or singletons, so we the result is in col-major order: assert ( capture == """ my_func(x:int=1, y:float=10, z:float=3) my_func(x:int=3, y:float=30, z:float=3) my_func(x:int=2, y:float=20, z:float=3) my_func(x:int=4, y:float=40, z:float=3) """ ) with capture: a, b, c = ( np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3, ) assert np.allclose(f(a, b, c), a * b * c) assert ( capture == """ my_func(x:int=1, y:float=2, z:float=3) my_func(x:int=3, y:float=4, z:float=3) my_func(x:int=5, y:float=6, z:float=3) my_func(x:int=7, y:float=8, z:float=3) my_func(x:int=9, y:float=10, z:float=3) my_func(x:int=11, y:float=12, z:float=3) """ ) with capture: a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2 assert np.allclose(f(a, b, c), a * b * c) assert ( capture == """ my_func(x:int=1, y:float=2, z:float=2) my_func(x:int=2, y:float=3, z:float=2) my_func(x:int=3, y:float=4, z:float=2) my_func(x:int=4, y:float=2, z:float=2) my_func(x:int=5, y:float=3, z:float=2) my_func(x:int=6, y:float=4, z:float=2) """ ) with capture: a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2 assert np.allclose(f(a, b, c), a * b * c) assert ( capture == """ my_func(x:int=1, y:float=2, z:float=2) my_func(x:int=2, y:float=2, z:float=2) my_func(x:int=3, y:float=2, z:float=2) my_func(x:int=4, y:float=3, z:float=2) my_func(x:int=5, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2) """ ) with capture: a, b, c = ( np.array([[1, 2, 3], [4, 5, 6]], order="F"), np.array([[2], [3]]), 2, ) assert np.allclose(f(a, b, c), a * b * c) assert ( capture == """ my_func(x:int=1, y:float=2, z:float=2) my_func(x:int=2, y:float=2, z:float=2) my_func(x:int=3, y:float=2, z:float=2) my_func(x:int=4, y:float=3, z:float=2) my_func(x:int=5, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2) """ ) with capture: a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], np.array([[2], [3]]), 2 assert np.allclose(f(a, b, c), a * b * c) assert ( capture == """ my_func(x:int=1, y:float=2, z:float=2) my_func(x:int=3, y:float=2, z:float=2) my_func(x:int=4, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2) """ ) with capture: a, b, c = ( np.array([[1, 2, 3], [4, 5, 6]], order="F")[::, ::2], np.array([[2], [3]]), 2, ) assert np.allclose(f(a, b, c), a * b * c) assert ( capture == """ my_func(x:int=1, y:float=2, z:float=2) my_func(x:int=3, y:float=2, z:float=2) my_func(x:int=4, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2) """ ) def test_type_selection(): assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken." assert ( m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken." ) def test_docs(doc): assert ( doc(m.vectorized_func) == """ vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object """ ) def test_trivial_broadcasting(): trivial, vectorized_is_trivial = m.trivial, m.vectorized_is_trivial assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial assert ( vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3) == trivial.c_trivial ) assert trivial.c_trivial == vectorized_is_trivial( np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3 ) assert ( vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2) == trivial.non_trivial ) assert ( vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) == trivial.non_trivial ) z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype="int32") z2 = np.array(z1, dtype="float32") z3 = np.array(z1, dtype="float64") assert vectorized_is_trivial(z1, z2, z3) == trivial.c_trivial assert vectorized_is_trivial(1, z2, z3) == trivial.c_trivial assert vectorized_is_trivial(z1, 1, z3) == trivial.c_trivial assert vectorized_is_trivial(z1, z2, 1) == trivial.c_trivial assert vectorized_is_trivial(z1[::2, ::2], 1, 1) == trivial.non_trivial assert vectorized_is_trivial(1, 1, z1[::2, ::2]) == trivial.c_trivial assert vectorized_is_trivial(1, 1, z3[::2, ::2]) == trivial.non_trivial assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_trivial y1 = np.array(z1, order="F") y2 = np.array(y1) y3 = np.array(y1) assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial assert vectorized_is_trivial(y1, 1, 1) == trivial.f_trivial assert vectorized_is_trivial(1, y2, 1) == trivial.f_trivial assert vectorized_is_trivial(1, 1, y3) == trivial.f_trivial assert vectorized_is_trivial(y1, z2, 1) == trivial.non_trivial assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial assert m.vectorized_func(z1, z2, z3).flags.c_contiguous assert m.vectorized_func(y1, y2, y3).flags.f_contiguous assert m.vectorized_func(z1, 1, 1).flags.c_contiguous assert m.vectorized_func(1, y2, 1).flags.f_contiguous assert m.vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous assert m.vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous def test_passthrough_arguments(doc): assert doc(m.vec_passthrough) == ( "vec_passthrough(" + ", ".join( [ "arg0: float", "arg1: numpy.ndarray[numpy.float64]", "arg2: numpy.ndarray[numpy.float64]", "arg3: numpy.ndarray[numpy.int32]", "arg4: int", "arg5: m.numpy_vectorize.NonPODClass", "arg6: numpy.ndarray[numpy.float64]", ] ) + ") -> object" ) b = np.array([[10, 20, 30]], dtype="float64") c = np.array([100, 200]) # NOT a vectorized argument d = np.array([[1000], [2000], [3000]], dtype="int") g = np.array([[1000000, 2000000, 3000000]], dtype="int") # requires casting assert np.all( m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) == np.array( [ [1111111, 2111121, 3111131], [1112111, 2112121, 3112131], [1113111, 2113121, 3113131], ] ) ) def test_method_vectorization(): o = m.VectorizeTestClass(3) x = np.array([1, 2], dtype="int") y = np.array([[10], [20]], dtype="float32") assert np.all(o.method(x, y) == [[14, 15], [24, 25]]) def test_array_collapse(): assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray) assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray) z = m.vectorized_func([1], 2, 3) assert isinstance(z, np.ndarray) assert z.shape == (1,) z = m.vectorized_func(1, [[[2]]], 3) assert isinstance(z, np.ndarray) assert z.shape == (1, 1, 1) def test_vectorized_noreturn(): x = m.NonPODClass(0) assert x.value == 0 m.add_to(x, [1, 2, 3, 4]) assert x.value == 10 m.add_to(x, 1) assert x.value == 11 m.add_to(x, [[1, 1], [2, 3]]) assert x.value == 18 aoflagger-v3.4.0/external/pybind11/tests/test_const_name.cpp0000644000175000017500000000736714507760431022651 0ustar olesoles// Copyright (c) 2021 The Pybind Development Team. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "pybind11_tests.h" // IUT = Implementation Under Test #define CONST_NAME_TESTS(TEST_FUNC, IUT) \ std::string TEST_FUNC(int selector) { \ switch (selector) { \ case 0: \ return IUT("").text; \ case 1: \ return IUT("A").text; \ case 2: \ return IUT("Bd").text; \ case 3: \ return IUT("Cef").text; \ case 4: \ return IUT().text; /*NOLINT(bugprone-macro-parentheses)*/ \ case 5: \ return IUT().text; /*NOLINT(bugprone-macro-parentheses)*/ \ case 6: \ return IUT("T1", "T2").text; /*NOLINT(bugprone-macro-parentheses)*/ \ case 7: \ return IUT("U1", "U2").text; /*NOLINT(bugprone-macro-parentheses)*/ \ case 8: \ /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \ return IUT(IUT("D1"), IUT("D2")).text; \ case 9: \ /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \ return IUT(IUT("E1"), IUT("E2")).text; \ case 10: \ return IUT("KeepAtEnd").text; \ default: \ break; \ } \ throw std::runtime_error("Invalid selector value."); \ } CONST_NAME_TESTS(const_name_tests, py::detail::const_name) #ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY CONST_NAME_TESTS(underscore_tests, py::detail::_) #endif TEST_SUBMODULE(const_name, m) { m.def("const_name_tests", const_name_tests); #if defined(PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY) m.def("underscore_tests", underscore_tests); #else m.attr("underscore_tests") = "PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY not defined."; #endif } aoflagger-v3.4.0/external/pybind11/tests/test_pickling.cpp0000644000175000017500000001507714507760431022320 0ustar olesoles/* tests/test_pickling.cpp -- pickle support Copyright (c) 2016 Wenzel Jakob Copyright (c) 2021 The Pybind Development Team. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "pybind11_tests.h" #include #include #include namespace exercise_trampoline { struct SimpleBase { int num = 0; virtual ~SimpleBase() = default; // For compatibility with old clang versions: SimpleBase() = default; SimpleBase(const SimpleBase &) = default; }; struct SimpleBaseTrampoline : SimpleBase {}; struct SimpleCppDerived : SimpleBase {}; void wrap(py::module m) { py::class_(m, "SimpleBase") .def(py::init<>()) .def_readwrite("num", &SimpleBase::num) .def(py::pickle( [](const py::object &self) { py::dict d; if (py::hasattr(self, "__dict__")) { d = self.attr("__dict__"); } return py::make_tuple(self.attr("num"), d); }, [](const py::tuple &t) { if (t.size() != 2) { throw std::runtime_error("Invalid state!"); } auto cpp_state = std::unique_ptr(new SimpleBaseTrampoline); cpp_state->num = t[0].cast(); auto py_state = t[1].cast(); return std::make_pair(std::move(cpp_state), py_state); })); m.def("make_SimpleCppDerivedAsBase", []() { return std::unique_ptr(new SimpleCppDerived); }); m.def("check_dynamic_cast_SimpleCppDerived", [](const SimpleBase *base_ptr) { return dynamic_cast(base_ptr) != nullptr; }); } } // namespace exercise_trampoline TEST_SUBMODULE(pickling, m) { m.def("simple_callable", []() { return 20220426; }); // test_roundtrip class Pickleable { public: explicit Pickleable(const std::string &value) : m_value(value) {} const std::string &value() const { return m_value; } void setExtra1(int extra1) { m_extra1 = extra1; } void setExtra2(int extra2) { m_extra2 = extra2; } int extra1() const { return m_extra1; } int extra2() const { return m_extra2; } private: std::string m_value; int m_extra1 = 0; int m_extra2 = 0; }; class PickleableNew : public Pickleable { public: using Pickleable::Pickleable; }; py::class_ pyPickleable(m, "Pickleable"); pyPickleable.def(py::init()) .def("value", &Pickleable::value) .def("extra1", &Pickleable::extra1) .def("extra2", &Pickleable::extra2) .def("setExtra1", &Pickleable::setExtra1) .def("setExtra2", &Pickleable::setExtra2) // For details on the methods below, refer to // http://docs.python.org/3/library/pickle.html#pickling-class-instances .def("__getstate__", [](const Pickleable &p) { /* Return a tuple that fully encodes the state of the object */ return py::make_tuple(p.value(), p.extra1(), p.extra2()); }); ignoreOldStyleInitWarnings([&pyPickleable]() { pyPickleable.def("__setstate__", [](Pickleable &p, const py::tuple &t) { if (t.size() != 3) { throw std::runtime_error("Invalid state!"); } /* Invoke the constructor (need to use in-place version) */ new (&p) Pickleable(t[0].cast()); /* Assign any additional state */ p.setExtra1(t[1].cast()); p.setExtra2(t[2].cast()); }); }); py::class_(m, "PickleableNew") .def(py::init()) .def(py::pickle( [](const PickleableNew &p) { return py::make_tuple(p.value(), p.extra1(), p.extra2()); }, [](const py::tuple &t) { if (t.size() != 3) { throw std::runtime_error("Invalid state!"); } auto p = PickleableNew(t[0].cast()); p.setExtra1(t[1].cast()); p.setExtra2(t[2].cast()); return p; })); #if !defined(PYPY_VERSION) // test_roundtrip_with_dict class PickleableWithDict { public: explicit PickleableWithDict(const std::string &value) : value(value) {} std::string value; int extra; }; class PickleableWithDictNew : public PickleableWithDict { public: using PickleableWithDict::PickleableWithDict; }; py::class_ pyPickleableWithDict( m, "PickleableWithDict", py::dynamic_attr()); pyPickleableWithDict.def(py::init()) .def_readwrite("value", &PickleableWithDict::value) .def_readwrite("extra", &PickleableWithDict::extra) .def("__getstate__", [](const py::object &self) { /* Also include __dict__ in state */ return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__")); }); ignoreOldStyleInitWarnings([&pyPickleableWithDict]() { pyPickleableWithDict.def("__setstate__", [](const py::object &self, const py::tuple &t) { if (t.size() != 3) { throw std::runtime_error("Invalid state!"); } /* Cast and construct */ auto &p = self.cast(); new (&p) PickleableWithDict(t[0].cast()); /* Assign C++ state */ p.extra = t[1].cast(); /* Assign Python state */ self.attr("__dict__") = t[2]; }); }); py::class_(m, "PickleableWithDictNew") .def(py::init()) .def(py::pickle( [](const py::object &self) { return py::make_tuple( self.attr("value"), self.attr("extra"), self.attr("__dict__")); }, [](const py::tuple &t) { if (t.size() != 3) { throw std::runtime_error("Invalid state!"); } auto cpp_state = PickleableWithDictNew(t[0].cast()); cpp_state.extra = t[1].cast(); auto py_state = t[2].cast(); return std::make_pair(cpp_state, py_state); })); #endif exercise_trampoline::wrap(m); } aoflagger-v3.4.0/external/pybind11/tests/test_gil_scoped.py0000644000175000017500000002047314507760431022472 0ustar olesolesimport multiprocessing import sys import threading import time import pytest import env from pybind11_tests import gil_scoped as m class ExtendedVirtClass(m.VirtClass): def virtual_func(self): pass def pure_virtual_func(self): pass def test_callback_py_obj(): m.test_callback_py_obj(lambda: None) def test_callback_std_func(): m.test_callback_std_func(lambda: None) def test_callback_virtual_func(): extended = ExtendedVirtClass() m.test_callback_virtual_func(extended) def test_callback_pure_virtual_func(): extended = ExtendedVirtClass() m.test_callback_pure_virtual_func(extended) def test_cross_module_gil_released(): """Makes sure that the GIL can be acquired by another module from a GIL-released state.""" m.test_cross_module_gil_released() # Should not raise a SIGSEGV def test_cross_module_gil_acquired(): """Makes sure that the GIL can be acquired by another module from a GIL-acquired state.""" m.test_cross_module_gil_acquired() # Should not raise a SIGSEGV def test_cross_module_gil_inner_custom_released(): """Makes sure that the GIL can be acquired/released by another module from a GIL-released state using custom locking logic.""" m.test_cross_module_gil_inner_custom_released() def test_cross_module_gil_inner_custom_acquired(): """Makes sure that the GIL can be acquired/acquired by another module from a GIL-acquired state using custom locking logic.""" m.test_cross_module_gil_inner_custom_acquired() def test_cross_module_gil_inner_pybind11_released(): """Makes sure that the GIL can be acquired/released by another module from a GIL-released state using pybind11 locking logic.""" m.test_cross_module_gil_inner_pybind11_released() def test_cross_module_gil_inner_pybind11_acquired(): """Makes sure that the GIL can be acquired/acquired by another module from a GIL-acquired state using pybind11 locking logic.""" m.test_cross_module_gil_inner_pybind11_acquired() def test_cross_module_gil_nested_custom_released(): """Makes sure that the GIL can be nested acquired/released by another module from a GIL-released state using custom locking logic.""" m.test_cross_module_gil_nested_custom_released() def test_cross_module_gil_nested_custom_acquired(): """Makes sure that the GIL can be nested acquired/acquired by another module from a GIL-acquired state using custom locking logic.""" m.test_cross_module_gil_nested_custom_acquired() def test_cross_module_gil_nested_pybind11_released(): """Makes sure that the GIL can be nested acquired/released by another module from a GIL-released state using pybind11 locking logic.""" m.test_cross_module_gil_nested_pybind11_released() def test_cross_module_gil_nested_pybind11_acquired(): """Makes sure that the GIL can be nested acquired/acquired by another module from a GIL-acquired state using pybind11 locking logic.""" m.test_cross_module_gil_nested_pybind11_acquired() def test_release_acquire(): assert m.test_release_acquire(0xAB) == "171" def test_nested_acquire(): assert m.test_nested_acquire(0xAB) == "171" def test_multi_acquire_release_cross_module(): for bits in range(16 * 8): internals_ids = m.test_multi_acquire_release_cross_module(bits) assert len(internals_ids) == 2 if bits % 8 else 1 # Intentionally putting human review in the loop here, to guard against accidents. VARS_BEFORE_ALL_BASIC_TESTS = dict(vars()) # Make a copy of the dict (critical). ALL_BASIC_TESTS = ( test_callback_py_obj, test_callback_std_func, test_callback_virtual_func, test_callback_pure_virtual_func, test_cross_module_gil_released, test_cross_module_gil_acquired, test_cross_module_gil_inner_custom_released, test_cross_module_gil_inner_custom_acquired, test_cross_module_gil_inner_pybind11_released, test_cross_module_gil_inner_pybind11_acquired, test_cross_module_gil_nested_custom_released, test_cross_module_gil_nested_custom_acquired, test_cross_module_gil_nested_pybind11_released, test_cross_module_gil_nested_pybind11_acquired, test_release_acquire, test_nested_acquire, test_multi_acquire_release_cross_module, ) def test_all_basic_tests_completeness(): num_found = 0 for key, value in VARS_BEFORE_ALL_BASIC_TESTS.items(): if not key.startswith("test_"): continue assert value in ALL_BASIC_TESTS num_found += 1 assert len(ALL_BASIC_TESTS) == num_found def _intentional_deadlock(): m.intentional_deadlock() ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK = ALL_BASIC_TESTS + (_intentional_deadlock,) def _run_in_process(target, *args, **kwargs): test_fn = target if len(args) == 0 else args[0] # Do not need to wait much, 10s should be more than enough. timeout = 0.1 if test_fn is _intentional_deadlock else 10 process = multiprocessing.Process(target=target, args=args, kwargs=kwargs) process.daemon = True try: t_start = time.time() process.start() if timeout >= 100: # For debugging. print( "\nprocess.pid STARTED", process.pid, (sys.argv, target, args, kwargs) ) print(f"COPY-PASTE-THIS: gdb {sys.argv[0]} -p {process.pid}", flush=True) process.join(timeout=timeout) if timeout >= 100: print("\nprocess.pid JOINED", process.pid, flush=True) t_delta = time.time() - t_start if process.exitcode == 66 and m.defined_THREAD_SANITIZER: # Issue #2754 # WOULD-BE-NICE-TO-HAVE: Check that the message below is actually in the output. # Maybe this could work: # https://gist.github.com/alexeygrigorev/01ce847f2e721b513b42ea4a6c96905e pytest.skip( "ThreadSanitizer: starting new threads after multi-threaded fork is not supported." ) elif test_fn is _intentional_deadlock: assert process.exitcode is None return 0 if process.exitcode is None: assert t_delta > 0.9 * timeout msg = "DEADLOCK, most likely, exactly what this test is meant to detect." if env.PYPY and env.WIN: pytest.skip(msg) raise RuntimeError(msg) return process.exitcode finally: if process.is_alive(): process.terminate() def _run_in_threads(test_fn, num_threads, parallel): threads = [] for _ in range(num_threads): thread = threading.Thread(target=test_fn) thread.daemon = True thread.start() if parallel: threads.append(thread) else: thread.join() for thread in threads: thread.join() # TODO: FIXME, sometimes returns -11 (segfault) instead of 0 on macOS Python 3.9 @pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK) def test_run_in_process_one_thread(test_fn): """Makes sure there is no GIL deadlock when running in a thread. It runs in a separate process to be able to stop and assert if it deadlocks. """ assert _run_in_process(_run_in_threads, test_fn, num_threads=1, parallel=False) == 0 # TODO: FIXME on macOS Python 3.9 @pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK) def test_run_in_process_multiple_threads_parallel(test_fn): """Makes sure there is no GIL deadlock when running in a thread multiple times in parallel. It runs in a separate process to be able to stop and assert if it deadlocks. """ assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=True) == 0 # TODO: FIXME on macOS Python 3.9 @pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK) def test_run_in_process_multiple_threads_sequential(test_fn): """Makes sure there is no GIL deadlock when running in a thread multiple times sequentially. It runs in a separate process to be able to stop and assert if it deadlocks. """ assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=False) == 0 # TODO: FIXME on macOS Python 3.9 @pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK) def test_run_in_process_direct(test_fn): """Makes sure there is no GIL deadlock when using processes. This test is for completion, but it was never an issue. """ assert _run_in_process(test_fn) == 0 aoflagger-v3.4.0/external/pybind11/tests/test_eigen_matrix.py0000644000175000017500000007054414507760431023041 0ustar olesolesimport pytest from pybind11_tests import ConstructorStats np = pytest.importorskip("numpy") m = pytest.importorskip("pybind11_tests.eigen_matrix") ref = np.array( [ [0.0, 3, 0, 0, 0, 11], [22, 0, 0, 0, 17, 11], [7, 5, 0, 1, 0, 11], [0, 0, 0, 0, 0, 11], [0, 0, 14, 0, 8, 11], ] ) def assert_equal_ref(mat): np.testing.assert_array_equal(mat, ref) def assert_sparse_equal_ref(sparse_mat): assert_equal_ref(sparse_mat.toarray()) def test_fixed(): assert_equal_ref(m.fixed_c()) assert_equal_ref(m.fixed_r()) assert_equal_ref(m.fixed_copy_r(m.fixed_r())) assert_equal_ref(m.fixed_copy_c(m.fixed_c())) assert_equal_ref(m.fixed_copy_r(m.fixed_c())) assert_equal_ref(m.fixed_copy_c(m.fixed_r())) def test_dense(): assert_equal_ref(m.dense_r()) assert_equal_ref(m.dense_c()) assert_equal_ref(m.dense_copy_r(m.dense_r())) assert_equal_ref(m.dense_copy_c(m.dense_c())) assert_equal_ref(m.dense_copy_r(m.dense_c())) assert_equal_ref(m.dense_copy_c(m.dense_r())) def test_partially_fixed(): ref2 = np.array([[0.0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2) np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2) np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]]) np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :]) np.testing.assert_array_equal( m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)] ) np.testing.assert_array_equal( m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :] ) np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2) np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2) np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]]) np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :]) np.testing.assert_array_equal( m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)] ) np.testing.assert_array_equal( m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :] ) # TypeError should be raise for a shape mismatch functions = [ m.partial_copy_four_rm_r, m.partial_copy_four_rm_c, m.partial_copy_four_cm_r, m.partial_copy_four_cm_c, ] matrix_with_wrong_shape = [[1, 2], [3, 4]] for f in functions: with pytest.raises(TypeError) as excinfo: f(matrix_with_wrong_shape) assert "incompatible function arguments" in str(excinfo.value) def test_mutator_descriptors(): zr = np.arange(30, dtype="float32").reshape(5, 6) # row-major zc = zr.reshape(6, 5).transpose() # column-major m.fixed_mutator_r(zr) m.fixed_mutator_c(zc) m.fixed_mutator_a(zr) m.fixed_mutator_a(zc) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_r(zc) assert ( "(arg0: numpy.ndarray[numpy.float32[5, 6]," " flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value) ) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_c(zr) assert ( "(arg0: numpy.ndarray[numpy.float32[5, 6]," " flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value) ) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32")) assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str( excinfo.value ) zr.flags.writeable = False with pytest.raises(TypeError): m.fixed_mutator_r(zr) with pytest.raises(TypeError): m.fixed_mutator_a(zr) def test_cpp_casting(): assert m.cpp_copy(m.fixed_r()) == 22.0 assert m.cpp_copy(m.fixed_c()) == 22.0 z = np.array([[5.0, 6], [7, 8]]) assert m.cpp_copy(z) == 7.0 assert m.cpp_copy(m.get_cm_ref()) == 21.0 assert m.cpp_copy(m.get_rm_ref()) == 21.0 assert m.cpp_ref_c(m.get_cm_ref()) == 21.0 assert m.cpp_ref_r(m.get_rm_ref()) == 21.0 with pytest.raises(RuntimeError) as excinfo: # Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles m.cpp_ref_any(m.fixed_c()) assert "Unable to cast Python instance" in str(excinfo.value) with pytest.raises(RuntimeError) as excinfo: # Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles m.cpp_ref_any(m.fixed_r()) assert "Unable to cast Python instance" in str(excinfo.value) assert m.cpp_ref_any(m.ReturnTester.create()) == 1.0 assert m.cpp_ref_any(m.get_cm_ref()) == 21.0 assert m.cpp_ref_any(m.get_cm_ref()) == 21.0 def test_pass_readonly_array(): z = np.full((5, 6), 42.0) z.flags.writeable = False np.testing.assert_array_equal(z, m.fixed_copy_r(z)) np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r()) assert not m.fixed_r_const().flags.writeable np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const()) def test_nonunit_stride_from_python(): counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) second_row = counting_mat[1, :] second_col = counting_mat[:, 1] np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row) np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row) np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row) np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col) np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col) np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col) counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] for ref_mat in slices: np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat) np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat) # Mutator: m.double_threer(second_row) m.double_threec(second_col) np.testing.assert_array_equal(counting_mat, [[0.0, 2, 2], [6, 16, 10], [6, 14, 8]]) def test_negative_stride_from_python(msg): """Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an exception will be thrown as Eigen will not be able to map the numpy array.""" counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) counting_mat = counting_mat[::-1, ::-1] second_row = counting_mat[1, :] second_col = counting_mat[:, 1] np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row) np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row) np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row) np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col) np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col) np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col) counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) counting_3d = counting_3d[::-1, ::-1, ::-1] slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] for ref_mat in slices: np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat) np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat) # Mutator: with pytest.raises(TypeError) as excinfo: m.double_threer(second_row) assert ( msg(excinfo.value) == """ double_threer(): incompatible function arguments. The following argument types are supported: 1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None Invoked with: """ + repr(np.array([5.0, 4.0, 3.0], dtype="float32")) ) with pytest.raises(TypeError) as excinfo: m.double_threec(second_col) assert ( msg(excinfo.value) == """ double_threec(): incompatible function arguments. The following argument types are supported: 1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None Invoked with: """ + repr(np.array([7.0, 4.0, 1.0], dtype="float32")) ) def test_block_runtime_error_type_caster_eigen_ref_made_a_copy(): with pytest.raises(RuntimeError) as excinfo: m.block(ref, 0, 0, 0, 0) assert str(excinfo.value) == "type_caster for Eigen::Ref made a copy." def test_nonunit_stride_to_python(): assert np.all(m.diagonal(ref) == ref.diagonal()) assert np.all(m.diagonal_1(ref) == ref.diagonal(1)) for i in range(-5, 7): assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({i})" # Must be order="F", otherwise the type_caster will make a copy and # m.block() will return a dangling reference (heap-use-after-free). rof = np.asarray(ref, order="F") assert np.all(m.block(rof, 2, 1, 3, 3) == rof[2:5, 1:4]) assert np.all(m.block(rof, 1, 4, 4, 2) == rof[1:, 4:]) assert np.all(m.block(rof, 1, 4, 3, 2) == rof[1:4, 4:]) def test_eigen_ref_to_python(): chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4] for i, chol in enumerate(chols, start=1): mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]])) assert np.all( mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]]) ), f"cholesky{i}" def assign_both(a1, a2, r, c, v): a1[r, c] = v a2[r, c] = v def array_copy_but_one(a, r, c, v): z = np.array(a, copy=True) z[r, c] = v return z def test_eigen_return_references(): """Tests various ways of returning references and non-referencing copies""" primary = np.ones((10, 10)) a = m.ReturnTester() a_get1 = a.get() assert not a_get1.flags.owndata assert a_get1.flags.writeable assign_both(a_get1, primary, 3, 3, 5) a_get2 = a.get_ptr() assert not a_get2.flags.owndata assert a_get2.flags.writeable assign_both(a_get1, primary, 2, 3, 6) a_view1 = a.view() assert not a_view1.flags.owndata assert not a_view1.flags.writeable with pytest.raises(ValueError): a_view1[2, 3] = 4 a_view2 = a.view_ptr() assert not a_view2.flags.owndata assert not a_view2.flags.writeable with pytest.raises(ValueError): a_view2[2, 3] = 4 a_copy1 = a.copy_get() assert a_copy1.flags.owndata assert a_copy1.flags.writeable np.testing.assert_array_equal(a_copy1, primary) a_copy1[7, 7] = -44 # Shouldn't affect anything else c1want = array_copy_but_one(primary, 7, 7, -44) a_copy2 = a.copy_view() assert a_copy2.flags.owndata assert a_copy2.flags.writeable np.testing.assert_array_equal(a_copy2, primary) a_copy2[4, 4] = -22 # Shouldn't affect anything else c2want = array_copy_but_one(primary, 4, 4, -22) a_ref1 = a.ref() assert not a_ref1.flags.owndata assert a_ref1.flags.writeable assign_both(a_ref1, primary, 1, 1, 15) a_ref2 = a.ref_const() assert not a_ref2.flags.owndata assert not a_ref2.flags.writeable with pytest.raises(ValueError): a_ref2[5, 5] = 33 a_ref3 = a.ref_safe() assert not a_ref3.flags.owndata assert a_ref3.flags.writeable assign_both(a_ref3, primary, 0, 7, 99) a_ref4 = a.ref_const_safe() assert not a_ref4.flags.owndata assert not a_ref4.flags.writeable with pytest.raises(ValueError): a_ref4[7, 0] = 987654321 a_copy3 = a.copy_ref() assert a_copy3.flags.owndata assert a_copy3.flags.writeable np.testing.assert_array_equal(a_copy3, primary) a_copy3[8, 1] = 11 c3want = array_copy_but_one(primary, 8, 1, 11) a_copy4 = a.copy_ref_const() assert a_copy4.flags.owndata assert a_copy4.flags.writeable np.testing.assert_array_equal(a_copy4, primary) a_copy4[8, 4] = 88 c4want = array_copy_but_one(primary, 8, 4, 88) a_block1 = a.block(3, 3, 2, 2) assert not a_block1.flags.owndata assert a_block1.flags.writeable a_block1[0, 0] = 55 primary[3, 3] = 55 a_block2 = a.block_safe(2, 2, 3, 2) assert not a_block2.flags.owndata assert a_block2.flags.writeable a_block2[2, 1] = -123 primary[4, 3] = -123 a_block3 = a.block_const(6, 7, 4, 3) assert not a_block3.flags.owndata assert not a_block3.flags.writeable with pytest.raises(ValueError): a_block3[2, 2] = -44444 a_copy5 = a.copy_block(2, 2, 2, 3) assert a_copy5.flags.owndata assert a_copy5.flags.writeable np.testing.assert_array_equal(a_copy5, primary[2:4, 2:5]) a_copy5[1, 1] = 777 c5want = array_copy_but_one(primary[2:4, 2:5], 1, 1, 777) a_corn1 = a.corners() assert not a_corn1.flags.owndata assert a_corn1.flags.writeable a_corn1 *= 50 a_corn1[1, 1] = 999 primary[0, 0] = 50 primary[0, 9] = 50 primary[9, 0] = 50 primary[9, 9] = 999 a_corn2 = a.corners_const() assert not a_corn2.flags.owndata assert not a_corn2.flags.writeable with pytest.raises(ValueError): a_corn2[1, 0] = 51 # All of the changes made all the way along should be visible everywhere # now (except for the copies, of course) np.testing.assert_array_equal(a_get1, primary) np.testing.assert_array_equal(a_get2, primary) np.testing.assert_array_equal(a_view1, primary) np.testing.assert_array_equal(a_view2, primary) np.testing.assert_array_equal(a_ref1, primary) np.testing.assert_array_equal(a_ref2, primary) np.testing.assert_array_equal(a_ref3, primary) np.testing.assert_array_equal(a_ref4, primary) np.testing.assert_array_equal(a_block1, primary[3:5, 3:5]) np.testing.assert_array_equal(a_block2, primary[2:5, 2:4]) np.testing.assert_array_equal(a_block3, primary[6:10, 7:10]) np.testing.assert_array_equal( a_corn1, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1] ) np.testing.assert_array_equal( a_corn2, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1] ) np.testing.assert_array_equal(a_copy1, c1want) np.testing.assert_array_equal(a_copy2, c2want) np.testing.assert_array_equal(a_copy3, c3want) np.testing.assert_array_equal(a_copy4, c4want) np.testing.assert_array_equal(a_copy5, c5want) def assert_keeps_alive(cl, method, *args): cstats = ConstructorStats.get(cl) start_with = cstats.alive() a = cl() assert cstats.alive() == start_with + 1 z = method(a, *args) assert cstats.alive() == start_with + 1 del a # Here's the keep alive in action: assert cstats.alive() == start_with + 1 del z # Keep alive should have expired: assert cstats.alive() == start_with def test_eigen_keepalive(): a = m.ReturnTester() cstats = ConstructorStats.get(m.ReturnTester) assert cstats.alive() == 1 unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)] copies = [ a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(), a.copy_block(4, 3, 2, 1), ] del a assert cstats.alive() == 0 del unsafe del copies for meth in [ m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view, m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe, m.ReturnTester.corners, m.ReturnTester.corners_const, ]: assert_keeps_alive(m.ReturnTester, meth) for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]: assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1) def test_eigen_ref_mutators(): """Tests Eigen's ability to mutate numpy values""" orig = np.array([[1.0, 2, 3], [4, 5, 6], [7, 8, 9]]) zr = np.array(orig) zc = np.array(orig, order="F") m.add_rm(zr, 1, 0, 100) assert np.all(zr == np.array([[1.0, 2, 3], [104, 5, 6], [7, 8, 9]])) m.add_cm(zc, 1, 0, 200) assert np.all(zc == np.array([[1.0, 2, 3], [204, 5, 6], [7, 8, 9]])) m.add_any(zr, 1, 0, 20) assert np.all(zr == np.array([[1.0, 2, 3], [124, 5, 6], [7, 8, 9]])) m.add_any(zc, 1, 0, 10) assert np.all(zc == np.array([[1.0, 2, 3], [214, 5, 6], [7, 8, 9]])) # Can't reference a col-major array with a row-major Ref, and vice versa: with pytest.raises(TypeError): m.add_rm(zc, 1, 0, 1) with pytest.raises(TypeError): m.add_cm(zr, 1, 0, 1) # Overloads: m.add1(zr, 1, 0, -100) m.add2(zr, 1, 0, -20) assert np.all(zr == orig) m.add1(zc, 1, 0, -200) m.add2(zc, 1, 0, -10) assert np.all(zc == orig) # a non-contiguous slice (this won't work on either the row- or # column-contiguous refs, but should work for the any) cornersr = zr[0::2, 0::2] cornersc = zc[0::2, 0::2] assert np.all(cornersr == np.array([[1.0, 3], [7, 9]])) assert np.all(cornersc == np.array([[1.0, 3], [7, 9]])) with pytest.raises(TypeError): m.add_rm(cornersr, 0, 1, 25) with pytest.raises(TypeError): m.add_cm(cornersr, 0, 1, 25) with pytest.raises(TypeError): m.add_rm(cornersc, 0, 1, 25) with pytest.raises(TypeError): m.add_cm(cornersc, 0, 1, 25) m.add_any(cornersr, 0, 1, 25) m.add_any(cornersc, 0, 1, 44) assert np.all(zr == np.array([[1.0, 2, 28], [4, 5, 6], [7, 8, 9]])) assert np.all(zc == np.array([[1.0, 2, 47], [4, 5, 6], [7, 8, 9]])) # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method: zro = zr[0:4, 0:4] zro.flags.writeable = False with pytest.raises(TypeError): m.add_rm(zro, 0, 0, 0) with pytest.raises(TypeError): m.add_any(zro, 0, 0, 0) with pytest.raises(TypeError): m.add1(zro, 0, 0, 0) with pytest.raises(TypeError): m.add2(zro, 0, 0, 0) # integer array shouldn't be passable to a double-matrix-accepting mutating func: zi = np.array([[1, 2], [3, 4]]) with pytest.raises(TypeError): m.add_rm(zi) def test_numpy_ref_mutators(): """Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)""" m.reset_refs() # In case another test already changed it zc = m.get_cm_ref() zcro = m.get_cm_const_ref() zr = m.get_rm_ref() zrro = m.get_rm_const_ref() assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4 assert not zc.flags.owndata assert zc.flags.writeable assert not zr.flags.owndata assert zr.flags.writeable assert not zcro.flags.owndata assert not zcro.flags.writeable assert not zrro.flags.owndata assert not zrro.flags.writeable zc[1, 2] = 99 expect = np.array([[11.0, 12, 13], [21, 22, 99], [31, 32, 33]]) # We should have just changed zc, of course, but also zcro and the original eigen matrix assert np.all(zc == expect) assert np.all(zcro == expect) assert np.all(m.get_cm_ref() == expect) zr[1, 2] = 99 assert np.all(zr == expect) assert np.all(zrro == expect) assert np.all(m.get_rm_ref() == expect) # Make sure the readonly ones are numpy-readonly: with pytest.raises(ValueError): zcro[1, 2] = 6 with pytest.raises(ValueError): zrro[1, 2] = 6 # We should be able to explicitly copy like this (and since we're copying, # the const should drop away) y1 = np.array(m.get_cm_const_ref()) assert y1.flags.owndata assert y1.flags.writeable # We should get copies of the eigen data, which was modified above: assert y1[1, 2] == 99 y1[1, 2] += 12 assert y1[1, 2] == 111 assert zc[1, 2] == 99 # Make sure we aren't referencing the original def test_both_ref_mutators(): """Tests a complex chain of nested eigen/numpy references""" m.reset_refs() # In case another test already changed it z = m.get_cm_ref() # numpy -> eigen z[0, 2] -= 3 z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen z2[1, 1] += 6 z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3 z3[2, 2] += -5 z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4 z4[1, 1] -= 1 z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5 z5[0, 0] = 0 assert np.all(z == z2) assert np.all(z == z3) assert np.all(z == z4) assert np.all(z == z5) expect = np.array([[0.0, 22, 20], [31, 37, 33], [41, 42, 38]]) assert np.all(z == expect) y = np.array(range(100), dtype="float64").reshape(10, 10) y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np y3 = m.incr_matrix_any( y2[0::2, 0::2], -33 ) # np -> eigen -> np slice -> np -> eigen -> np y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3) y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4) y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5) # Apply same mutations using just numpy: yexpect = np.array(range(100), dtype="float64").reshape(10, 10) yexpect += 10 yexpect[0::2, 0::2] -= 33 yexpect[0::4, 0::4] += 1000 assert np.all(y6 == yexpect[0::4, 0::4]) assert np.all(y5 == yexpect[0::4, 0::4]) assert np.all(y4 == yexpect[0::4, 0::2]) assert np.all(y3 == yexpect[0::2, 0::2]) assert np.all(y2 == yexpect) assert np.all(y == yexpect) def test_nocopy_wrapper(): # get_elem requires a column-contiguous matrix reference, but should be # callable with other types of matrix (via copying): int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order="F") dbl_matrix_colmajor = np.array( int_matrix_colmajor, dtype="double", order="F", copy=True ) int_matrix_rowmajor = np.array(int_matrix_colmajor, order="C", copy=True) dbl_matrix_rowmajor = np.array( int_matrix_rowmajor, dtype="double", order="C", copy=True ) # All should be callable via get_elem: assert m.get_elem(int_matrix_colmajor) == 8 assert m.get_elem(dbl_matrix_colmajor) == 8 assert m.get_elem(int_matrix_rowmajor) == 8 assert m.get_elem(dbl_matrix_rowmajor) == 8 # All but the second should fail with m.get_elem_nocopy: with pytest.raises(TypeError) as excinfo: m.get_elem_nocopy(int_matrix_colmajor) assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value) assert ", flags.f_contiguous" in str(excinfo.value) assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8 with pytest.raises(TypeError) as excinfo: m.get_elem_nocopy(int_matrix_rowmajor) assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value) assert ", flags.f_contiguous" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.get_elem_nocopy(dbl_matrix_rowmajor) assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value) assert ", flags.f_contiguous" in str(excinfo.value) # For the row-major test, we take a long matrix in row-major, so only the third is allowed: with pytest.raises(TypeError) as excinfo: m.get_elem_rm_nocopy(int_matrix_colmajor) assert "get_elem_rm_nocopy(): incompatible function arguments." in str( excinfo.value ) assert ", flags.c_contiguous" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.get_elem_rm_nocopy(dbl_matrix_colmajor) assert "get_elem_rm_nocopy(): incompatible function arguments." in str( excinfo.value ) assert ", flags.c_contiguous" in str(excinfo.value) assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8 with pytest.raises(TypeError) as excinfo: m.get_elem_rm_nocopy(dbl_matrix_rowmajor) assert "get_elem_rm_nocopy(): incompatible function arguments." in str( excinfo.value ) assert ", flags.c_contiguous" in str(excinfo.value) def test_eigen_ref_life_support(): """Ensure the lifetime of temporary arrays created by the `Ref` caster The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to happen both for directs casts (just the array) or indirectly (e.g. list of arrays). """ a = np.full(shape=10, fill_value=8, dtype=np.int8) assert m.get_elem_direct(a) == 8 list_of_a = [a] assert m.get_elem_indirect(list_of_a) == 8 def test_special_matrix_objects(): assert np.all(m.incr_diag(7) == np.diag([1.0, 2, 3, 4, 5, 6, 7])) asymm = np.array([[1.0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]) symm_lower = np.array(asymm) symm_upper = np.array(asymm) for i in range(4): for j in range(i + 1, 4): symm_lower[i, j] = symm_lower[j, i] symm_upper[j, i] = symm_upper[i, j] assert np.all(m.symmetric_lower(asymm) == symm_lower) assert np.all(m.symmetric_upper(asymm) == symm_upper) def test_dense_signature(doc): assert ( doc(m.double_col) == """ double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]] """ ) assert ( doc(m.double_row) == """ double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]] """ ) assert doc(m.double_complex) == ( """ double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])""" """ -> numpy.ndarray[numpy.complex64[m, 1]] """ ) assert doc(m.double_mat_rm) == ( """ double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])""" """ -> numpy.ndarray[numpy.float32[m, n]] """ ) def test_named_arguments(): a = np.array([[1.0, 2], [3, 4], [5, 6]]) b = np.ones((2, 1)) assert np.all(m.matrix_multiply(a, b) == np.array([[3.0], [7], [11]])) assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.0], [7], [11]])) assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.0], [7], [11]])) with pytest.raises(ValueError) as excinfo: m.matrix_multiply(b, a) assert str(excinfo.value) == "Nonconformable matrices!" with pytest.raises(ValueError) as excinfo: m.matrix_multiply(A=b, B=a) assert str(excinfo.value) == "Nonconformable matrices!" with pytest.raises(ValueError) as excinfo: m.matrix_multiply(B=a, A=b) assert str(excinfo.value) == "Nonconformable matrices!" def test_sparse(): pytest.importorskip("scipy") assert_sparse_equal_ref(m.sparse_r()) assert_sparse_equal_ref(m.sparse_c()) assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r())) assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c())) assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c())) assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r())) def test_sparse_signature(doc): pytest.importorskip("scipy") assert ( doc(m.sparse_copy_r) == """ sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32] """ ) assert ( doc(m.sparse_copy_c) == """ sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32] """ ) def test_issue738(): """Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)""" assert np.all(m.iss738_f1(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]])) assert np.all( m.iss738_f1(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]]) ) assert np.all(m.iss738_f2(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]])) assert np.all( m.iss738_f2(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]]) ) @pytest.mark.parametrize("func", [m.iss738_f1, m.iss738_f2]) @pytest.mark.parametrize("sizes", [(0, 2), (2, 0)]) def test_zero_length(func, sizes): """Ignore strides on a length-0 dimension (even if they would be incompatible length > 1)""" assert np.all(func(np.zeros(sizes)) == np.zeros(sizes)) def test_issue1105(): """Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen compile-time row vectors or column vector""" assert m.iss1105_row(np.ones((1, 7))) assert m.iss1105_col(np.ones((7, 1))) # These should still fail (incompatible dimensions): with pytest.raises(TypeError) as excinfo: m.iss1105_row(np.ones((7, 1))) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.iss1105_col(np.ones((1, 7))) assert "incompatible function arguments" in str(excinfo.value) def test_custom_operator_new(): """Using Eigen types as member variables requires a class-specific operator new with proper alignment""" o = m.CustomOperatorNew() np.testing.assert_allclose(o.a, 0.0) np.testing.assert_allclose(o.b.diagonal(), 1.0) aoflagger-v3.4.0/external/pybind11/tests/test_enum.cpp0000644000175000017500000001313214507760431021452 0ustar olesoles/* tests/test_enums.cpp -- enumerations Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "pybind11_tests.h" TEST_SUBMODULE(enums, m) { // test_unscoped_enum enum UnscopedEnum { EOne = 1, ETwo, EThree }; py::enum_(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration") .value("EOne", EOne, "Docstring for EOne") .value("ETwo", ETwo, "Docstring for ETwo") .value("EThree", EThree, "Docstring for EThree") .export_values(); // test_scoped_enum enum class ScopedEnum { Two = 2, Three }; py::enum_(m, "ScopedEnum", py::arithmetic()) .value("Two", ScopedEnum::Two) .value("Three", ScopedEnum::Three); m.def("test_scoped_enum", [](ScopedEnum z) { return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three"); }); // test_binary_operators enum Flags { Read = 4, Write = 2, Execute = 1 }; py::enum_(m, "Flags", py::arithmetic()) .value("Read", Flags::Read) .value("Write", Flags::Write) .value("Execute", Flags::Execute) .export_values(); // test_implicit_conversion class ClassWithUnscopedEnum { public: enum EMode { EFirstMode = 1, ESecondMode }; static EMode test_function(EMode mode) { return mode; } }; py::class_ exenum_class(m, "ClassWithUnscopedEnum"); exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function); py::enum_(exenum_class, "EMode") .value("EFirstMode", ClassWithUnscopedEnum::EFirstMode) .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode) .export_values(); // test_enum_to_int m.def("test_enum_to_int", [](int) {}); m.def("test_enum_to_uint", [](uint32_t) {}); m.def("test_enum_to_long_long", [](long long) {}); // test_duplicate_enum_name enum SimpleEnum { ONE, TWO, THREE }; m.def("register_bad_enum", [m]() { py::enum_(m, "SimpleEnum") .value("ONE", SimpleEnum::ONE) // NOTE: all value function calls are called with the // same first parameter value .value("ONE", SimpleEnum::TWO) .value("ONE", SimpleEnum::THREE) .export_values(); }); // test_enum_scalar enum UnscopedUCharEnum : unsigned char {}; enum class ScopedShortEnum : short {}; enum class ScopedLongEnum : long {}; enum UnscopedUInt64Enum : std::uint64_t {}; static_assert( py::detail::all_of< std::is_same::Scalar, unsigned char>, std::is_same::Scalar, short>, std::is_same::Scalar, long>, std::is_same::Scalar, std::uint64_t>>::value, "Error during the deduction of enum's scalar type with normal integer underlying"); // test_enum_scalar_with_char_underlying enum class ScopedCharEnum : char { Zero, Positive }; enum class ScopedWCharEnum : wchar_t { Zero, Positive }; enum class ScopedChar32Enum : char32_t { Zero, Positive }; enum class ScopedChar16Enum : char16_t { Zero, Positive }; // test the scalar of char type enums according to chapter 'Character types' // from https://en.cppreference.com/w/cpp/language/types static_assert( py::detail::any_of< std::is_same::Scalar, signed char>, // e.g. gcc on x86 std::is_same::Scalar, unsigned char> // e.g. arm linux >::value, "char should be cast to either signed char or unsigned char"); static_assert(sizeof(py::enum_::Scalar) == 2 || sizeof(py::enum_::Scalar) == 4, "wchar_t should be either 16 bits (Windows) or 32 (everywhere else)"); static_assert( py::detail::all_of< std::is_same::Scalar, std::uint_least32_t>, std::is_same::Scalar, std::uint_least16_t>>::value, "char32_t, char16_t (and char8_t)'s size, signedness, and alignment is determined"); #if defined(PYBIND11_HAS_U8STRING) enum class ScopedChar8Enum : char8_t { Zero, Positive }; static_assert(std::is_same::Scalar, unsigned char>::value); #endif // test_char_underlying_enum py::enum_(m, "ScopedCharEnum") .value("Zero", ScopedCharEnum::Zero) .value("Positive", ScopedCharEnum::Positive); py::enum_(m, "ScopedWCharEnum") .value("Zero", ScopedWCharEnum::Zero) .value("Positive", ScopedWCharEnum::Positive); py::enum_(m, "ScopedChar32Enum") .value("Zero", ScopedChar32Enum::Zero) .value("Positive", ScopedChar32Enum::Positive); py::enum_(m, "ScopedChar16Enum") .value("Zero", ScopedChar16Enum::Zero) .value("Positive", ScopedChar16Enum::Positive); // test_bool_underlying_enum enum class ScopedBoolEnum : bool { FALSE, TRUE }; // bool is unsigned (std::is_signed returns false) and 1-byte long, so represented with u8 static_assert(std::is_same::Scalar, std::uint8_t>::value, ""); py::enum_(m, "ScopedBoolEnum") .value("FALSE", ScopedBoolEnum::FALSE) .value("TRUE", ScopedBoolEnum::TRUE); } aoflagger-v3.4.0/external/pybind11/tests/test_embed/0000755000175000017500000000000014516225226021054 5ustar olesolesaoflagger-v3.4.0/external/pybind11/tests/test_embed/test_trampoline.py0000644000175000017500000000042314507760431024640 0ustar olesolesimport trampoline_module def func(): class Test(trampoline_module.test_override_cache_helper): def func(self): return 42 return Test() def func2(): class Test(trampoline_module.test_override_cache_helper): pass return Test() aoflagger-v3.4.0/external/pybind11/tests/test_embed/external_module.cpp0000644000175000017500000000103714507760431024752 0ustar olesoles#include namespace py = pybind11; /* Simple test module/test class to check that the referenced internals data of external pybind11 * modules aren't preserved over a finalize/initialize. */ PYBIND11_MODULE(external_module, m) { class A { public: explicit A(int value) : v{value} {}; int v; }; py::class_(m, "A").def(py::init()).def_readwrite("value", &A::v); m.def("internals_at", []() { return reinterpret_cast(&py::detail::get_internals()); }); } aoflagger-v3.4.0/external/pybind11/tests/test_embed/test_interpreter.py0000644000175000017500000000035514507760431025035 0ustar olesolesimport sys from widget_module import Widget class DerivedWidget(Widget): def __init__(self, message): super().__init__(message) def the_answer(self): return 42 def argv0(self): return sys.argv[0] aoflagger-v3.4.0/external/pybind11/tests/test_embed/test_interpreter.cpp0000644000175000017500000004200214507760431025162 0ustar olesoles#include // Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to // catch 2.0.1; this should be fixed in the next catch release after 2.0.1). PYBIND11_WARNING_DISABLE_MSVC(4996) #include #include #include #include #include #include namespace py = pybind11; using namespace py::literals; size_t get_sys_path_size() { auto sys_path = py::module::import("sys").attr("path"); return py::len(sys_path); } class Widget { public: explicit Widget(std::string message) : message(std::move(message)) {} virtual ~Widget() = default; std::string the_message() const { return message; } virtual int the_answer() const = 0; virtual std::string argv0() const = 0; private: std::string message; }; class PyWidget final : public Widget { using Widget::Widget; int the_answer() const override { PYBIND11_OVERRIDE_PURE(int, Widget, the_answer); } std::string argv0() const override { PYBIND11_OVERRIDE_PURE(std::string, Widget, argv0); } }; class test_override_cache_helper { public: virtual int func() { return 0; } test_override_cache_helper() = default; virtual ~test_override_cache_helper() = default; // Non-copyable test_override_cache_helper &operator=(test_override_cache_helper const &Right) = delete; test_override_cache_helper(test_override_cache_helper const &Copy) = delete; }; class test_override_cache_helper_trampoline : public test_override_cache_helper { int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); } }; PYBIND11_EMBEDDED_MODULE(widget_module, m) { py::class_(m, "Widget") .def(py::init()) .def_property_readonly("the_message", &Widget::the_message); m.def("add", [](int i, int j) { return i + j; }); } PYBIND11_EMBEDDED_MODULE(trampoline_module, m) { py::class_>(m, "test_override_cache_helper") .def(py::init_alias<>()) .def("func", &test_override_cache_helper::func); } PYBIND11_EMBEDDED_MODULE(throw_exception, ) { throw std::runtime_error("C++ Error"); } PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) { auto d = py::dict(); d["missing"].cast(); } TEST_CASE("PYTHONPATH is used to update sys.path") { // The setup for this TEST_CASE is in catch.cpp! auto sys_path = py::str(py::module_::import("sys").attr("path")).cast(); REQUIRE_THAT(sys_path, Catch::Matchers::Contains("pybind11_test_embed_PYTHONPATH_2099743835476552")); } TEST_CASE("Pass classes and data between modules defined in C++ and Python") { auto module_ = py::module_::import("test_interpreter"); REQUIRE(py::hasattr(module_, "DerivedWidget")); auto locals = py::dict("hello"_a = "Hello, World!", "x"_a = 5, **module_.attr("__dict__")); py::exec(R"( widget = DerivedWidget("{} - {}".format(hello, x)) message = widget.the_message )", py::globals(), locals); REQUIRE(locals["message"].cast() == "Hello, World! - 5"); auto py_widget = module_.attr("DerivedWidget")("The question"); auto message = py_widget.attr("the_message"); REQUIRE(message.cast() == "The question"); const auto &cpp_widget = py_widget.cast(); REQUIRE(cpp_widget.the_answer() == 42); } TEST_CASE("Override cache") { auto module_ = py::module_::import("test_trampoline"); REQUIRE(py::hasattr(module_, "func")); REQUIRE(py::hasattr(module_, "func2")); auto locals = py::dict(**module_.attr("__dict__")); int i = 0; for (; i < 1500; ++i) { std::shared_ptr p_obj; std::shared_ptr p_obj2; py::object loc_inst = locals["func"](); p_obj = py::cast>(loc_inst); int ret = p_obj->func(); REQUIRE(ret == 42); loc_inst = locals["func2"](); p_obj2 = py::cast>(loc_inst); p_obj2->func(); } } TEST_CASE("Import error handling") { REQUIRE_NOTHROW(py::module_::import("widget_module")); REQUIRE_THROWS_WITH(py::module_::import("throw_exception"), "ImportError: C++ Error"); REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"), Catch::Contains("ImportError: initialization failed")); auto locals = py::dict("is_keyerror"_a = false, "message"_a = "not set"); py::exec(R"( try: import throw_error_already_set except ImportError as e: is_keyerror = type(e.__cause__) == KeyError message = str(e.__cause__) )", py::globals(), locals); REQUIRE(locals["is_keyerror"].cast() == true); REQUIRE(locals["message"].cast() == "'missing'"); } TEST_CASE("There can be only one interpreter") { static_assert(std::is_move_constructible::value, ""); static_assert(!std::is_move_assignable::value, ""); static_assert(!std::is_copy_constructible::value, ""); static_assert(!std::is_copy_assignable::value, ""); REQUIRE_THROWS_WITH(py::initialize_interpreter(), "The interpreter is already running"); REQUIRE_THROWS_WITH(py::scoped_interpreter(), "The interpreter is already running"); py::finalize_interpreter(); REQUIRE_NOTHROW(py::scoped_interpreter()); { auto pyi1 = py::scoped_interpreter(); auto pyi2 = std::move(pyi1); } py::initialize_interpreter(); } #if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX TEST_CASE("Custom PyConfig") { py::finalize_interpreter(); PyConfig config; PyConfig_InitPythonConfig(&config); REQUIRE_NOTHROW(py::scoped_interpreter{&config}); { py::scoped_interpreter p{&config}; REQUIRE(py::module_::import("widget_module").attr("add")(1, 41).cast() == 42); } py::initialize_interpreter(); } TEST_CASE("scoped_interpreter with PyConfig_InitIsolatedConfig and argv") { py::finalize_interpreter(); { PyConfig config; PyConfig_InitIsolatedConfig(&config); char *argv[] = {strdup("a.out")}; py::scoped_interpreter argv_scope{&config, 1, argv}; std::free(argv[0]); auto module = py::module::import("test_interpreter"); auto py_widget = module.attr("DerivedWidget")("The question"); const auto &cpp_widget = py_widget.cast(); REQUIRE(cpp_widget.argv0() == "a.out"); } py::initialize_interpreter(); } TEST_CASE("scoped_interpreter with PyConfig_InitPythonConfig and argv") { py::finalize_interpreter(); { PyConfig config; PyConfig_InitPythonConfig(&config); // `initialize_interpreter() overrides the default value for config.parse_argv (`1`) by // changing it to `0`. This test exercises `scoped_interpreter` with the default config. char *argv[] = {strdup("a.out"), strdup("arg1")}; py::scoped_interpreter argv_scope(&config, 2, argv); std::free(argv[0]); std::free(argv[1]); auto module = py::module::import("test_interpreter"); auto py_widget = module.attr("DerivedWidget")("The question"); const auto &cpp_widget = py_widget.cast(); REQUIRE(cpp_widget.argv0() == "arg1"); } py::initialize_interpreter(); } #endif TEST_CASE("Add program dir to path pre-PyConfig") { py::finalize_interpreter(); size_t path_size_add_program_dir_to_path_false = 0; { py::scoped_interpreter scoped_interp{true, 0, nullptr, false}; path_size_add_program_dir_to_path_false = get_sys_path_size(); } { py::scoped_interpreter scoped_interp{}; REQUIRE(get_sys_path_size() == path_size_add_program_dir_to_path_false + 1); } py::initialize_interpreter(); } #if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX TEST_CASE("Add program dir to path using PyConfig") { py::finalize_interpreter(); size_t path_size_add_program_dir_to_path_false = 0; { PyConfig config; PyConfig_InitPythonConfig(&config); py::scoped_interpreter scoped_interp{&config, 0, nullptr, false}; path_size_add_program_dir_to_path_false = get_sys_path_size(); } { PyConfig config; PyConfig_InitPythonConfig(&config); py::scoped_interpreter scoped_interp{&config}; REQUIRE(get_sys_path_size() == path_size_add_program_dir_to_path_false + 1); } py::initialize_interpreter(); } #endif bool has_pybind11_internals_builtin() { auto builtins = py::handle(PyEval_GetBuiltins()); return builtins.contains(PYBIND11_INTERNALS_ID); }; bool has_pybind11_internals_static() { auto **&ipp = py::detail::get_internals_pp(); return (ipp != nullptr) && (*ipp != nullptr); } TEST_CASE("Restart the interpreter") { // Verify pre-restart state. REQUIRE(py::module_::import("widget_module").attr("add")(1, 2).cast() == 3); REQUIRE(has_pybind11_internals_builtin()); REQUIRE(has_pybind11_internals_static()); REQUIRE(py::module_::import("external_module").attr("A")(123).attr("value").cast() == 123); // local and foreign module internals should point to the same internals: REQUIRE(reinterpret_cast(*py::detail::get_internals_pp()) == py::module_::import("external_module").attr("internals_at")().cast()); // Restart the interpreter. py::finalize_interpreter(); REQUIRE(Py_IsInitialized() == 0); py::initialize_interpreter(); REQUIRE(Py_IsInitialized() == 1); // Internals are deleted after a restart. REQUIRE_FALSE(has_pybind11_internals_builtin()); REQUIRE_FALSE(has_pybind11_internals_static()); pybind11::detail::get_internals(); REQUIRE(has_pybind11_internals_builtin()); REQUIRE(has_pybind11_internals_static()); REQUIRE(reinterpret_cast(*py::detail::get_internals_pp()) == py::module_::import("external_module").attr("internals_at")().cast()); // Make sure that an interpreter with no get_internals() created until finalize still gets the // internals destroyed py::finalize_interpreter(); py::initialize_interpreter(); bool ran = false; py::module_::import("__main__").attr("internals_destroy_test") = py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast(ran) = true; }); REQUIRE_FALSE(has_pybind11_internals_builtin()); REQUIRE_FALSE(has_pybind11_internals_static()); REQUIRE_FALSE(ran); py::finalize_interpreter(); REQUIRE(ran); py::initialize_interpreter(); REQUIRE_FALSE(has_pybind11_internals_builtin()); REQUIRE_FALSE(has_pybind11_internals_static()); // C++ modules can be reloaded. auto cpp_module = py::module_::import("widget_module"); REQUIRE(cpp_module.attr("add")(1, 2).cast() == 3); // C++ type information is reloaded and can be used in python modules. auto py_module = py::module_::import("test_interpreter"); auto py_widget = py_module.attr("DerivedWidget")("Hello after restart"); REQUIRE(py_widget.attr("the_message").cast() == "Hello after restart"); } TEST_CASE("Subinterpreter") { // Add tags to the modules in the main interpreter and test the basics. py::module_::import("__main__").attr("main_tag") = "main interpreter"; { auto m = py::module_::import("widget_module"); m.attr("extension_module_tag") = "added to module in main interpreter"; REQUIRE(m.attr("add")(1, 2).cast() == 3); } REQUIRE(has_pybind11_internals_builtin()); REQUIRE(has_pybind11_internals_static()); /// Create and switch to a subinterpreter. auto *main_tstate = PyThreadState_Get(); auto *sub_tstate = Py_NewInterpreter(); // Subinterpreters get their own copy of builtins. detail::get_internals() still // works by returning from the static variable, i.e. all interpreters share a single // global pybind11::internals; REQUIRE_FALSE(has_pybind11_internals_builtin()); REQUIRE(has_pybind11_internals_static()); // Modules tags should be gone. REQUIRE_FALSE(py::hasattr(py::module_::import("__main__"), "tag")); { auto m = py::module_::import("widget_module"); REQUIRE_FALSE(py::hasattr(m, "extension_module_tag")); // Function bindings should still work. REQUIRE(m.attr("add")(1, 2).cast() == 3); } // Restore main interpreter. Py_EndInterpreter(sub_tstate); PyThreadState_Swap(main_tstate); REQUIRE(py::hasattr(py::module_::import("__main__"), "main_tag")); REQUIRE(py::hasattr(py::module_::import("widget_module"), "extension_module_tag")); } TEST_CASE("Execution frame") { // When the interpreter is embedded, there is no execution frame, but `py::exec` // should still function by using reasonable globals: `__main__.__dict__`. py::exec("var = dict(number=42)"); REQUIRE(py::globals()["var"]["number"].cast() == 42); } TEST_CASE("Threads") { // Restart interpreter to ensure threads are not initialized py::finalize_interpreter(); py::initialize_interpreter(); REQUIRE_FALSE(has_pybind11_internals_static()); constexpr auto num_threads = 10; auto locals = py::dict("count"_a = 0); { py::gil_scoped_release gil_release{}; auto threads = std::vector(); for (auto i = 0; i < num_threads; ++i) { threads.emplace_back([&]() { py::gil_scoped_acquire gil{}; locals["count"] = locals["count"].cast() + 1; }); } for (auto &thread : threads) { thread.join(); } } REQUIRE(locals["count"].cast() == num_threads); } // Scope exit utility https://stackoverflow.com/a/36644501/7255855 struct scope_exit { std::function f_; explicit scope_exit(std::function f) noexcept : f_(std::move(f)) {} ~scope_exit() { if (f_) { f_(); } } }; TEST_CASE("Reload module from file") { // Disable generation of cached bytecode (.pyc files) for this test, otherwise // Python might pick up an old version from the cache instead of the new versions // of the .py files generated below auto sys = py::module_::import("sys"); bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast(); sys.attr("dont_write_bytecode") = true; // Reset the value at scope exit scope_exit reset_dont_write_bytecode( [&]() { sys.attr("dont_write_bytecode") = dont_write_bytecode; }); std::string module_name = "test_module_reload"; std::string module_file = module_name + ".py"; // Create the module .py file std::ofstream test_module(module_file); test_module << "def test():\n"; test_module << " return 1\n"; test_module.close(); // Delete the file at scope exit scope_exit delete_module_file([&]() { std::remove(module_file.c_str()); }); // Import the module from file auto module_ = py::module_::import(module_name.c_str()); int result = module_.attr("test")().cast(); REQUIRE(result == 1); // Update the module .py file with a small change test_module.open(module_file); test_module << "def test():\n"; test_module << " return 2\n"; test_module.close(); // Reload the module module_.reload(); result = module_.attr("test")().cast(); REQUIRE(result == 2); } TEST_CASE("sys.argv gets initialized properly") { py::finalize_interpreter(); { py::scoped_interpreter default_scope; auto module = py::module::import("test_interpreter"); auto py_widget = module.attr("DerivedWidget")("The question"); const auto &cpp_widget = py_widget.cast(); REQUIRE(cpp_widget.argv0().empty()); } { char *argv[] = {strdup("a.out")}; py::scoped_interpreter argv_scope(true, 1, argv); std::free(argv[0]); auto module = py::module::import("test_interpreter"); auto py_widget = module.attr("DerivedWidget")("The question"); const auto &cpp_widget = py_widget.cast(); REQUIRE(cpp_widget.argv0() == "a.out"); } py::initialize_interpreter(); } TEST_CASE("make_iterator can be called before then after finalizing an interpreter") { // Reproduction of issue #2101 (https://github.com/pybind/pybind11/issues/2101) py::finalize_interpreter(); std::vector container; { pybind11::scoped_interpreter g; auto iter = pybind11::make_iterator(container.begin(), container.end()); } REQUIRE_NOTHROW([&]() { pybind11::scoped_interpreter g; auto iter = pybind11::make_iterator(container.begin(), container.end()); }()); py::initialize_interpreter(); } aoflagger-v3.4.0/external/pybind11/tests/test_embed/catch.cpp0000644000175000017500000000244314507760431022647 0ustar olesoles// The Catch implementation is compiled here. This is a standalone // translation unit to avoid recompiling it for every test change. #include // Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to // catch 2.0.1; this should be fixed in the next catch release after 2.0.1). PYBIND11_WARNING_DISABLE_MSVC(4996) // Catch uses _ internally, which breaks gettext style defines #ifdef _ # undef _ #endif #define CATCH_CONFIG_RUNNER #include namespace py = pybind11; int main(int argc, char *argv[]) { // Setup for TEST_CASE in test_interpreter.cpp, tagging on a large random number: std::string updated_pythonpath("pybind11_test_embed_PYTHONPATH_2099743835476552"); const char *preexisting_pythonpath = getenv("PYTHONPATH"); if (preexisting_pythonpath != nullptr) { #if defined(_WIN32) updated_pythonpath += ';'; #else updated_pythonpath += ':'; #endif updated_pythonpath += preexisting_pythonpath; } #if defined(_WIN32) _putenv_s("PYTHONPATH", updated_pythonpath.c_str()); #else setenv("PYTHONPATH", updated_pythonpath.c_str(), /*replace=*/1); #endif py::scoped_interpreter guard{}; auto result = Catch::Session().run(argc, argv); return result < 0xff ? result : 0xff; } aoflagger-v3.4.0/external/pybind11/tests/test_embed/CMakeLists.txt0000644000175000017500000000340614507760431023621 0ustar olesolespossibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID) if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy") message(STATUS "Skipping embed test on PyPy") add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported. set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") return() endif() find_package(Catch 2.13.9) if(CATCH_FOUND) message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}") else() message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers" " manually or use `cmake -DDOWNLOAD_CATCH=ON` to fetch them automatically.") return() endif() find_package(Threads REQUIRED) add_executable(test_embed catch.cpp test_interpreter.cpp) pybind11_enable_warnings(test_embed) target_link_libraries(test_embed PRIVATE pybind11::embed Catch2::Catch2 Threads::Threads) if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) file(COPY test_interpreter.py test_trampoline.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") endif() add_custom_target( cpptest COMMAND "$" DEPENDS test_embed WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") pybind11_add_module(external_module THIN_LTO external_module.cpp) set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") foreach(config ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${config} config) set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} "${CMAKE_CURRENT_BINARY_DIR}") endforeach() add_dependencies(cpptest external_module) add_dependencies(check cpptest) aoflagger-v3.4.0/external/pybind11/tests/test_local_bindings.cpp0000644000175000017500000001046114507760431023457 0ustar olesoles/* tests/test_local_bindings.cpp -- tests the py::module_local class feature which makes a class binding local to the module in which it is defined. Copyright (c) 2017 Jason Rhinelander All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include "local_bindings.h" #include "pybind11_tests.h" #include #include TEST_SUBMODULE(local_bindings, m) { // test_load_external m.def("load_external1", [](ExternalType1 &e) { return e.i; }); m.def("load_external2", [](ExternalType2 &e) { return e.i; }); // test_local_bindings // Register a class with py::module_local: bind_local(m, "LocalType", py::module_local()).def("get3", [](LocalType &t) { return t.i + 3; }); m.def("local_value", [](LocalType &l) { return l.i; }); // test_nonlocal_failure // The main pybind11 test module is loaded first, so this registration will succeed (the second // one, in pybind11_cross_module_tests.cpp, is designed to fail): bind_local(m, "NonLocalType") .def(py::init()) .def("get", [](LocalType &i) { return i.i; }); // test_duplicate_local // py::module_local declarations should be visible across compilation units that get linked // together; this tries to register a duplicate local. It depends on a definition in // test_class.cpp and should raise a runtime error from the duplicate definition attempt. If // test_class isn't available it *also* throws a runtime error (with "test_class not enabled" // as value). m.def("register_local_external", [m]() { auto main = py::module_::import("pybind11_tests"); if (py::hasattr(main, "class_")) { bind_local(m, "LocalExternal", py::module_local()); } else { throw std::runtime_error("test_class not enabled"); } }); // test_stl_bind_local // stl_bind.h binders defaults to py::module_local if the types are local or converting: py::bind_vector(m, "LocalVec"); py::bind_map(m, "LocalMap"); // and global if the type (or one of the types, for the map) is global: py::bind_vector(m, "NonLocalVec"); py::bind_map(m, "NonLocalMap"); // test_stl_bind_global // They can, however, be overridden to global using `py::module_local(false)`: bind_local(m, "NonLocal2"); py::bind_vector(m, "LocalVec2", py::module_local()); py::bind_map(m, "NonLocalMap2", py::module_local(false)); // test_mixed_local_global // We try this both with the global type registered first and vice versa (the order shouldn't // matter). m.def("register_mixed_global", [m]() { bind_local(m, "MixedGlobalLocal", py::module_local(false)); }); m.def("register_mixed_local", [m]() { bind_local(m, "MixedLocalGlobal", py::module_local()); }); m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); }); m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); }); // test_internal_locals_differ m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; }); // test_stl_caster_vs_stl_bind m.def("load_vector_via_caster", [](std::vector v) { return std::accumulate(v.begin(), v.end(), 0); }); // test_cross_module_calls m.def("return_self", [](LocalVec *v) { return v; }); m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); class Cat : public pets::Pet { public: explicit Cat(std::string name) : Pet(std::move(name)) {} }; py::class_(m, "Pet", py::module_local()).def("get_name", &pets::Pet::name); // Binding for local extending class: py::class_(m, "Cat").def(py::init()); m.def("pet_name", [](pets::Pet &p) { return p.name(); }); py::class_(m, "MixGL").def(py::init()); m.def("get_gl_value", [](MixGL &o) { return o.i + 10; }); py::class_(m, "MixGL2").def(py::init()); } aoflagger-v3.4.0/external/pybind11/tests/test_callbacks.cpp0000644000175000017500000002515214507760431022432 0ustar olesoles/* tests/test_callbacks.cpp -- callbacks Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "constructor_stats.h" #include "pybind11_tests.h" #include int dummy_function(int i) { return i + 1; } TEST_SUBMODULE(callbacks, m) { // test_callbacks, test_function_signatures m.def("test_callback1", [](const py::object &func) { return func(); }); m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); }); m.def("test_callback3", [](const std::function &func) { return "func(43) = " + std::to_string(func(43)); }); m.def("test_callback4", []() -> std::function { return [](int i) { return i + 1; }; }); m.def("test_callback5", []() { return py::cpp_function([](int i) { return i + 1; }, py::arg("number")); }); // test_keyword_args_and_generalized_unpacking m.def("test_tuple_unpacking", [](const py::function &f) { auto t1 = py::make_tuple(2, 3); auto t2 = py::make_tuple(5, 6); return f("positional", 1, *t1, 4, *t2); }); m.def("test_dict_unpacking", [](const py::function &f) { auto d1 = py::dict("key"_a = "value", "a"_a = 1); auto d2 = py::dict(); auto d3 = py::dict("b"_a = 2); return f("positional", 1, **d1, **d2, **d3); }); m.def("test_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); }); m.def("test_unpacking_and_keywords1", [](const py::function &f) { auto args = py::make_tuple(2); auto kwargs = py::dict("d"_a = 4); return f(1, *args, "c"_a = 3, **kwargs); }); m.def("test_unpacking_and_keywords2", [](const py::function &f) { auto kwargs1 = py::dict("a"_a = 1); auto kwargs2 = py::dict("c"_a = 3, "d"_a = 4); return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, "key"_a = "value", **kwargs1, "b"_a = 2, **kwargs2, "e"_a = 5); }); m.def("test_unpacking_error1", [](const py::function &f) { auto kwargs = py::dict("x"_a = 3); return f("x"_a = 1, "y"_a = 2, **kwargs); // duplicate ** after keyword }); m.def("test_unpacking_error2", [](const py::function &f) { auto kwargs = py::dict("x"_a = 3); return f(**kwargs, "x"_a = 1); // duplicate keyword after ** }); m.def("test_arg_conversion_error1", [](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); }); m.def("test_arg_conversion_error2", [](const py::function &f) { f(234, "expected_name"_a = UnregisteredType(), "kw"_a = 567); }); // test_lambda_closure_cleanup struct Payload { Payload() { print_default_created(this); } ~Payload() { print_destroyed(this); } Payload(const Payload &) { print_copy_created(this); } Payload(Payload &&) noexcept { print_move_created(this); } }; // Export the payload constructor statistics for testing purposes: m.def("payload_cstats", &ConstructorStats::get); m.def("test_lambda_closure_cleanup", []() -> std::function { Payload p; // In this situation, `Func` in the implementation of // `cpp_function::initialize` is NOT trivially destructible. return [p]() { /* p should be cleaned up when the returned function is garbage collected */ (void) p; }; }); class CppCallable { public: CppCallable() { track_default_created(this); } ~CppCallable() { track_destroyed(this); } CppCallable(const CppCallable &) { track_copy_created(this); } CppCallable(CppCallable &&) noexcept { track_move_created(this); } void operator()() {} }; m.def("test_cpp_callable_cleanup", []() { // Related issue: https://github.com/pybind/pybind11/issues/3228 // Related PR: https://github.com/pybind/pybind11/pull/3229 py::list alive_counts; ConstructorStats &stat = ConstructorStats::get(); alive_counts.append(stat.alive()); { CppCallable cpp_callable; alive_counts.append(stat.alive()); { // In this situation, `Func` in the implementation of // `cpp_function::initialize` IS trivially destructible, // only `capture` is not. py::cpp_function py_func(cpp_callable); py::detail::silence_unused_warnings(py_func); alive_counts.append(stat.alive()); } alive_counts.append(stat.alive()); { py::cpp_function py_func(std::move(cpp_callable)); py::detail::silence_unused_warnings(py_func); alive_counts.append(stat.alive()); } alive_counts.append(stat.alive()); } alive_counts.append(stat.alive()); return alive_counts; }); // test_cpp_function_roundtrip /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ m.def("dummy_function", &dummy_function); m.def("dummy_function_overloaded", [](int i, int j) { return i + j; }); m.def("dummy_function_overloaded", &dummy_function); m.def("dummy_function2", [](int i, int j) { return i + j; }); m.def( "roundtrip", [](std::function f, bool expect_none = false) { if (expect_none && f) { throw std::runtime_error("Expected None to be converted to empty std::function"); } return f; }, py::arg("f"), py::arg("expect_none") = false); m.def("test_dummy_function", [](const std::function &f) -> std::string { using fn_type = int (*)(int); const auto *result = f.target(); if (!result) { auto r = f(1); return "can't convert to function pointer: eval(1) = " + std::to_string(r); } if (*result == dummy_function) { auto r = (*result)(1); return "matches dummy_function: eval(1) = " + std::to_string(r); } return "argument does NOT match dummy_function. This should never happen!"; }); class AbstractBase { public: // [workaround(intel)] = default does not work here // Defaulting this destructor results in linking errors with the Intel compiler // (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827) virtual ~AbstractBase() {} // NOLINT(modernize-use-equals-default) virtual unsigned int func() = 0; }; m.def("func_accepting_func_accepting_base", [](const std::function &) {}); struct MovableObject { bool valid = true; MovableObject() = default; MovableObject(const MovableObject &) = default; MovableObject &operator=(const MovableObject &) = default; MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; } MovableObject &operator=(MovableObject &&o) noexcept { valid = o.valid; o.valid = false; return *this; } }; py::class_(m, "MovableObject"); // test_movable_object m.def("callback_with_movable", [](const std::function &f) { auto x = MovableObject(); f(x); // lvalue reference shouldn't move out object return x.valid; // must still return `true` }); // test_bound_method_callback struct CppBoundMethodTest {}; py::class_(m, "CppBoundMethodTest") .def(py::init<>()) .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; }); // This checks that builtin functions can be passed as callbacks // rather than throwing RuntimeError due to trying to extract as capsule m.def("test_sum_builtin", [](const std::function &sum_builtin, const py::iterable &i) { return sum_builtin(i); }); // test async Python callbacks using callback_f = std::function; m.def("test_async_callback", [](const callback_f &f, const py::list &work) { // make detached thread that calls `f` with piece of work after a little delay auto start_f = [f](int j) { auto invoke_f = [f, j] { std::this_thread::sleep_for(std::chrono::milliseconds(50)); f(j); }; auto t = std::thread(std::move(invoke_f)); t.detach(); }; // spawn worker threads for (auto i : work) { start_f(py::cast(i)); } }); m.def("callback_num_times", [](const py::function &f, std::size_t num) { for (std::size_t i = 0; i < num; i++) { f(); } }); auto *custom_def = []() { static PyMethodDef def; def.ml_name = "example_name"; def.ml_doc = "Example doc"; def.ml_meth = [](PyObject *, PyObject *args) -> PyObject * { if (PyTuple_Size(args) != 1) { throw std::runtime_error("Invalid number of arguments for example_name"); } PyObject *first = PyTuple_GetItem(args, 0); if (!PyLong_Check(first)) { throw std::runtime_error("Invalid argument to example_name"); } auto result = py::cast(PyLong_AsLong(first) * 9); return result.release().ptr(); }; def.ml_flags = METH_VARARGS; return &def; }(); // rec_capsule with name that has the same value (but not pointer) as our internal one // This capsule should be detected by our code as foreign and not inspected as the pointers // shouldn't match constexpr const char *rec_capsule_name = pybind11::detail::internals_function_record_capsule_name; py::capsule rec_capsule(std::malloc(1), [](void *data) { std::free(data); }); rec_capsule.set_name(rec_capsule_name); m.add_object("custom_function", PyCFunction_New(custom_def, rec_capsule.ptr())); // This test requires a new ABI version to pass #if PYBIND11_INTERNALS_VERSION > 4 // rec_capsule with nullptr name py::capsule rec_capsule2(std::malloc(1), [](void *data) { std::free(data); }); m.add_object("custom_function2", PyCFunction_New(custom_def, rec_capsule2.ptr())); #else m.add_object("custom_function2", py::none()); #endif } aoflagger-v3.4.0/external/pybind11/tests/test_methods_and_attributes.py0000644000175000017500000004327114507760431025116 0ustar olesolesimport sys import pytest import env # noqa: F401 from pybind11_tests import ConstructorStats from pybind11_tests import methods_and_attributes as m NO_GETTER_MSG = ( "unreadable attribute" if sys.version_info < (3, 11) else "object has no getter" ) NO_SETTER_MSG = ( "can't set attribute" if sys.version_info < (3, 11) else "object has no setter" ) NO_DELETER_MSG = ( "can't delete attribute" if sys.version_info < (3, 11) else "object has no deleter" ) def test_methods_and_attributes(): instance1 = m.ExampleMandA() instance2 = m.ExampleMandA(32) instance1.add1(instance2) instance1.add2(instance2) instance1.add3(instance2) instance1.add4(instance2) instance1.add5(instance2) instance1.add6(32) instance1.add7(32) instance1.add8(32) instance1.add9(32) instance1.add10(32) assert str(instance1) == "ExampleMandA[value=320]" assert str(instance2) == "ExampleMandA[value=32]" assert str(instance1.self1()) == "ExampleMandA[value=320]" assert str(instance1.self2()) == "ExampleMandA[value=320]" assert str(instance1.self3()) == "ExampleMandA[value=320]" assert str(instance1.self4()) == "ExampleMandA[value=320]" assert str(instance1.self5()) == "ExampleMandA[value=320]" assert instance1.internal1() == 320 assert instance1.internal2() == 320 assert instance1.internal3() == 320 assert instance1.internal4() == 320 assert instance1.internal5() == 320 assert instance1.overloaded() == "()" assert instance1.overloaded(0) == "(int)" assert instance1.overloaded(1, 1.0) == "(int, float)" assert instance1.overloaded(2.0, 2) == "(float, int)" assert instance1.overloaded(3, 3) == "(int, int)" assert instance1.overloaded(4.0, 4.0) == "(float, float)" assert instance1.overloaded_const(-3) == "(int) const" assert instance1.overloaded_const(5, 5.0) == "(int, float) const" assert instance1.overloaded_const(6.0, 6) == "(float, int) const" assert instance1.overloaded_const(7, 7) == "(int, int) const" assert instance1.overloaded_const(8.0, 8.0) == "(float, float) const" assert instance1.overloaded_float(1, 1) == "(float, float)" assert instance1.overloaded_float(1, 1.0) == "(float, float)" assert instance1.overloaded_float(1.0, 1) == "(float, float)" assert instance1.overloaded_float(1.0, 1.0) == "(float, float)" assert instance1.value == 320 instance1.value = 100 assert str(instance1) == "ExampleMandA[value=100]" cstats = ConstructorStats.get(m.ExampleMandA) assert cstats.alive() == 2 del instance1, instance2 assert cstats.alive() == 0 assert cstats.values() == ["32"] assert cstats.default_constructions == 1 assert cstats.copy_constructions == 2 assert cstats.move_constructions >= 2 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 def test_copy_method(): """Issue #443: calling copied methods fails in Python 3""" m.ExampleMandA.add2c = m.ExampleMandA.add2 m.ExampleMandA.add2d = m.ExampleMandA.add2b a = m.ExampleMandA(123) assert a.value == 123 a.add2(m.ExampleMandA(-100)) assert a.value == 23 a.add2b(m.ExampleMandA(20)) assert a.value == 43 a.add2c(m.ExampleMandA(6)) assert a.value == 49 a.add2d(m.ExampleMandA(-7)) assert a.value == 42 def test_properties(): instance = m.TestProperties() assert instance.def_readonly == 1 with pytest.raises(AttributeError): instance.def_readonly = 2 instance.def_readwrite = 2 assert instance.def_readwrite == 2 assert instance.def_property_readonly == 2 with pytest.raises(AttributeError): instance.def_property_readonly = 3 instance.def_property = 3 assert instance.def_property == 3 with pytest.raises(AttributeError) as excinfo: dummy = instance.def_property_writeonly # unused var assert NO_GETTER_MSG in str(excinfo.value) instance.def_property_writeonly = 4 assert instance.def_property_readonly == 4 with pytest.raises(AttributeError) as excinfo: dummy = instance.def_property_impossible # noqa: F841 unused var assert NO_GETTER_MSG in str(excinfo.value) with pytest.raises(AttributeError) as excinfo: instance.def_property_impossible = 5 assert NO_SETTER_MSG in str(excinfo.value) def test_static_properties(): assert m.TestProperties.def_readonly_static == 1 with pytest.raises(AttributeError) as excinfo: m.TestProperties.def_readonly_static = 2 assert NO_SETTER_MSG in str(excinfo.value) m.TestProperties.def_readwrite_static = 2 assert m.TestProperties.def_readwrite_static == 2 with pytest.raises(AttributeError) as excinfo: dummy = m.TestProperties.def_writeonly_static # unused var assert NO_GETTER_MSG in str(excinfo.value) m.TestProperties.def_writeonly_static = 3 assert m.TestProperties.def_readonly_static == 3 assert m.TestProperties.def_property_readonly_static == 3 with pytest.raises(AttributeError) as excinfo: m.TestProperties.def_property_readonly_static = 99 assert NO_SETTER_MSG in str(excinfo.value) m.TestProperties.def_property_static = 4 assert m.TestProperties.def_property_static == 4 with pytest.raises(AttributeError) as excinfo: dummy = m.TestProperties.def_property_writeonly_static assert NO_GETTER_MSG in str(excinfo.value) m.TestProperties.def_property_writeonly_static = 5 assert m.TestProperties.def_property_static == 5 # Static property read and write via instance instance = m.TestProperties() m.TestProperties.def_readwrite_static = 0 assert m.TestProperties.def_readwrite_static == 0 assert instance.def_readwrite_static == 0 instance.def_readwrite_static = 2 assert m.TestProperties.def_readwrite_static == 2 assert instance.def_readwrite_static == 2 with pytest.raises(AttributeError) as excinfo: dummy = instance.def_property_writeonly_static # noqa: F841 unused var assert NO_GETTER_MSG in str(excinfo.value) instance.def_property_writeonly_static = 4 assert instance.def_property_static == 4 # It should be possible to override properties in derived classes assert m.TestPropertiesOverride().def_readonly == 99 assert m.TestPropertiesOverride.def_readonly_static == 99 # Only static attributes can be deleted del m.TestPropertiesOverride.def_readonly_static assert hasattr(m.TestPropertiesOverride, "def_readonly_static") assert ( m.TestPropertiesOverride.def_readonly_static is m.TestProperties.def_readonly_static ) assert "def_readonly_static" not in m.TestPropertiesOverride.__dict__ properties_override = m.TestPropertiesOverride() with pytest.raises(AttributeError) as excinfo: del properties_override.def_readonly assert NO_DELETER_MSG in str(excinfo.value) def test_static_cls(): """Static property getter and setters expect the type object as the their only argument""" instance = m.TestProperties() assert m.TestProperties.static_cls is m.TestProperties assert instance.static_cls is m.TestProperties def check_self(self): assert self is m.TestProperties m.TestProperties.static_cls = check_self instance.static_cls = check_self def test_metaclass_override(): """Overriding pybind11's default metaclass changes the behavior of `static_property`""" assert type(m.ExampleMandA).__name__ == "pybind11_type" assert type(m.MetaclassOverride).__name__ == "type" assert m.MetaclassOverride.readonly == 1 assert ( type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property" ) # Regular `type` replaces the property instead of calling `__set__()` m.MetaclassOverride.readonly = 2 assert m.MetaclassOverride.readonly == 2 assert isinstance(m.MetaclassOverride.__dict__["readonly"], int) def test_no_mixed_overloads(): from pybind11_tests import detailed_error_messages_enabled with pytest.raises(RuntimeError) as excinfo: m.ExampleMandA.add_mixed_overloads1() assert str( excinfo.value ) == "overloading a method with both static and instance methods is not supported; " + ( "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details" if not detailed_error_messages_enabled else "error while attempting to bind static method ExampleMandA.overload_mixed1" "(arg0: float) -> str" ) with pytest.raises(RuntimeError) as excinfo: m.ExampleMandA.add_mixed_overloads2() assert str( excinfo.value ) == "overloading a method with both static and instance methods is not supported; " + ( "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details" if not detailed_error_messages_enabled else "error while attempting to bind instance method ExampleMandA.overload_mixed2" "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)" " -> str" ) @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) def test_property_return_value_policies(access): obj = m.TestPropRVP() if not access.startswith("static") else m.TestPropRVP ref = getattr(obj, access + "_ref") assert ref.value == 1 ref.value = 2 assert getattr(obj, access + "_ref").value == 2 ref.value = 1 # restore original value for static properties copy = getattr(obj, access + "_copy") assert copy.value == 1 copy.value = 2 assert getattr(obj, access + "_copy").value == 1 copy = getattr(obj, access + "_func") assert copy.value == 1 copy.value = 2 assert getattr(obj, access + "_func").value == 1 def test_property_rvalue_policy(): """When returning an rvalue, the return value policy is automatically changed from `reference(_internal)` to `move`. The following would not work otherwise.""" instance = m.TestPropRVP() o = instance.rvalue assert o.value == 1 os = m.TestPropRVP.static_rvalue assert os.value == 1 # https://foss.heptapod.net/pypy/pypy/-/issues/2447 @pytest.mark.xfail("env.PYPY") def test_dynamic_attributes(): instance = m.DynamicClass() assert not hasattr(instance, "foo") assert "foo" not in dir(instance) # Dynamically add attribute instance.foo = 42 assert hasattr(instance, "foo") assert instance.foo == 42 assert "foo" in dir(instance) # __dict__ should be accessible and replaceable assert "foo" in instance.__dict__ instance.__dict__ = {"bar": True} assert not hasattr(instance, "foo") assert hasattr(instance, "bar") with pytest.raises(TypeError) as excinfo: instance.__dict__ = [] assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'" cstats = ConstructorStats.get(m.DynamicClass) assert cstats.alive() == 1 del instance assert cstats.alive() == 0 # Derived classes should work as well class PythonDerivedDynamicClass(m.DynamicClass): pass for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass: derived = cls() derived.foobar = 100 assert derived.foobar == 100 assert cstats.alive() == 1 del derived assert cstats.alive() == 0 # https://foss.heptapod.net/pypy/pypy/-/issues/2447 @pytest.mark.xfail("env.PYPY") def test_cyclic_gc(): # One object references itself instance = m.DynamicClass() instance.circular_reference = instance cstats = ConstructorStats.get(m.DynamicClass) assert cstats.alive() == 1 del instance assert cstats.alive() == 0 # Two object reference each other i1 = m.DynamicClass() i2 = m.DynamicClass() i1.cycle = i2 i2.cycle = i1 assert cstats.alive() == 2 del i1, i2 assert cstats.alive() == 0 def test_bad_arg_default(msg): from pybind11_tests import detailed_error_messages_enabled with pytest.raises(RuntimeError) as excinfo: m.bad_arg_def_named() assert msg(excinfo.value) == ( "arg(): could not convert default argument 'a: UnregisteredType' in function " "'should_fail' into a Python object (type not registered yet?)" if detailed_error_messages_enabled else "arg(): could not convert default argument into a Python object (type not registered " "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information." ) with pytest.raises(RuntimeError) as excinfo: m.bad_arg_def_unnamed() assert msg(excinfo.value) == ( "arg(): could not convert default argument 'UnregisteredType' in function " "'should_fail' into a Python object (type not registered yet?)" if detailed_error_messages_enabled else "arg(): could not convert default argument into a Python object (type not registered " "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information." ) def test_accepts_none(msg): a = m.NoneTester() assert m.no_none1(a) == 42 assert m.no_none2(a) == 42 assert m.no_none3(a) == 42 assert m.no_none4(a) == 42 assert m.no_none5(a) == 42 assert m.ok_none1(a) == 42 assert m.ok_none2(a) == 42 assert m.ok_none3(a) == 42 assert m.ok_none4(a) == 42 assert m.ok_none5(a) == 42 with pytest.raises(TypeError) as excinfo: m.no_none1(None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none2(None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none3(None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none4(None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none5(None) assert "incompatible function arguments" in str(excinfo.value) # The first one still raises because you can't pass None as a lvalue reference arg: with pytest.raises(TypeError) as excinfo: assert m.ok_none1(None) == -1 assert ( msg(excinfo.value) == """ ok_none1(): incompatible function arguments. The following argument types are supported: 1. (arg0: m.methods_and_attributes.NoneTester) -> int Invoked with: None """ ) # The rest take the argument as pointer or holder, and accept None: assert m.ok_none2(None) == -1 assert m.ok_none3(None) == -1 assert m.ok_none4(None) == -1 assert m.ok_none5(None) == -1 with pytest.raises(TypeError) as excinfo: m.no_none_kwarg(None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none_kwarg(a=None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none_kwarg_kw_only(None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none_kwarg_kw_only(a=None) assert "incompatible function arguments" in str(excinfo.value) def test_casts_none(): """#2778: implicit casting from None to object (not pointer)""" a = m.NoneCastTester() assert m.ok_obj_or_none(a) == -1 a = m.NoneCastTester(4) assert m.ok_obj_or_none(a) == 4 a = m.NoneCastTester(None) assert m.ok_obj_or_none(a) == -1 assert m.ok_obj_or_none(None) == -1 def test_str_issue(msg): """#283: __str__ called on uninitialized instance when constructor arguments invalid""" assert str(m.StrIssue(3)) == "StrIssue[3]" with pytest.raises(TypeError) as excinfo: str(m.StrIssue("no", "such", "constructor")) assert ( msg(excinfo.value) == """ __init__(): incompatible constructor arguments. The following argument types are supported: 1. m.methods_and_attributes.StrIssue(arg0: int) 2. m.methods_and_attributes.StrIssue() Invoked with: 'no', 'such', 'constructor' """ ) def test_unregistered_base_implementations(): a = m.RegisteredDerived() a.do_nothing() assert a.rw_value == 42 assert a.ro_value == 1.25 a.rw_value += 5 assert a.sum() == 48.25 a.increase_value() assert a.rw_value == 48 assert a.ro_value == 1.5 assert a.sum() == 49.5 assert a.rw_value_prop == 48 a.rw_value_prop += 1 assert a.rw_value_prop == 49 a.increase_value() assert a.ro_value_prop == 1.75 def test_ref_qualified(): """Tests that explicit lvalue ref-qualified methods can be called just like their non ref-qualified counterparts.""" r = m.RefQualified() assert r.value == 0 r.refQualified(17) assert r.value == 17 assert r.constRefQualified(23) == 40 def test_overload_ordering(): "Check to see if the normal overload order (first defined) and prepend overload order works" assert m.overload_order("string") == 1 assert m.overload_order(0) == 4 assert "1. overload_order(arg0: int) -> int" in m.overload_order.__doc__ assert "2. overload_order(arg0: str) -> int" in m.overload_order.__doc__ assert "3. overload_order(arg0: str) -> int" in m.overload_order.__doc__ assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__ with pytest.raises(TypeError) as err: m.overload_order(1.1) assert "1. (arg0: int) -> int" in str(err.value) assert "2. (arg0: str) -> int" in str(err.value) assert "3. (arg0: str) -> int" in str(err.value) assert "4. (arg0: int) -> int" in str(err.value) def test_rvalue_ref_param(): r = m.RValueRefParam() assert r.func1("123") == 3 assert r.func2("1234") == 4 assert r.func3("12345") == 5 assert r.func4("123456") == 6 aoflagger-v3.4.0/external/pybind11/tests/test_custom_type_setup.cpp0000644000175000017500000000235314507760431024304 0ustar olesoles/* tests/test_custom_type_setup.cpp -- Tests `pybind11::custom_type_setup` Copyright (c) Google LLC All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "pybind11_tests.h" namespace py = pybind11; namespace { struct OwnsPythonObjects { py::object value = py::none(); }; } // namespace TEST_SUBMODULE(custom_type_setup, m) { py::class_ cls( m, "OwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) { auto *type = &heap_type->ht_type; type->tp_flags |= Py_TPFLAGS_HAVE_GC; type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) { auto &self = py::cast(py::handle(self_base)); Py_VISIT(self.value.ptr()); return 0; }; type->tp_clear = [](PyObject *self_base) { auto &self = py::cast(py::handle(self_base)); self.value = py::none(); return 0; }; })); cls.def(py::init<>()); cls.def_readwrite("value", &OwnsPythonObjects::value); } aoflagger-v3.4.0/external/pybind11/tests/test_numpy_dtypes.cpp0000644000175000017500000005117214507760431023254 0ustar olesoles/* tests/test_numpy_dtypes.cpp -- Structured and compound NumPy dtypes Copyright (c) 2016 Ivan Smirnov All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "pybind11_tests.h" #ifdef __GNUC__ # define PYBIND11_PACKED(cls) cls __attribute__((__packed__)) #else # define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop)) #endif namespace py = pybind11; struct SimpleStruct { bool bool_; uint32_t uint_; float float_; long double ldbl_; }; std::ostream &operator<<(std::ostream &os, const SimpleStruct &v) { return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; } struct SimpleStructReordered { bool bool_; float float_; uint32_t uint_; long double ldbl_; }; PYBIND11_PACKED(struct PackedStruct { bool bool_; uint32_t uint_; float float_; long double ldbl_; }); std::ostream &operator<<(std::ostream &os, const PackedStruct &v) { return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; } PYBIND11_PACKED(struct NestedStruct { SimpleStruct a; PackedStruct b; }); std::ostream &operator<<(std::ostream &os, const NestedStruct &v) { return os << "n:a=" << v.a << ";b=" << v.b; } struct PartialStruct { bool bool_; uint32_t uint_; float float_; uint64_t dummy2; long double ldbl_; }; struct PartialNestedStruct { uint64_t dummy1; PartialStruct a; uint64_t dummy2; }; struct UnboundStruct {}; struct StringStruct { char a[3]; std::array b; }; struct ComplexStruct { std::complex cflt; std::complex cdbl; }; std::ostream &operator<<(std::ostream &os, const ComplexStruct &v) { return os << "c:" << v.cflt << "," << v.cdbl; } struct ArrayStruct { char a[3][4]; int32_t b[2]; std::array c; std::array d[4]; }; PYBIND11_PACKED(struct StructWithUglyNames { int8_t __x__; uint64_t __y__; }); enum class E1 : int64_t { A = -1, B = 1 }; enum E2 : uint8_t { X = 1, Y = 2 }; PYBIND11_PACKED(struct EnumStruct { E1 e1; E2 e2; }); std::ostream &operator<<(std::ostream &os, const StringStruct &v) { os << "a='"; for (size_t i = 0; i < 3 && (v.a[i] != 0); i++) { os << v.a[i]; } os << "',b='"; for (size_t i = 0; i < 3 && (v.b[i] != 0); i++) { os << v.b[i]; } return os << "'"; } std::ostream &operator<<(std::ostream &os, const ArrayStruct &v) { os << "a={"; for (int i = 0; i < 3; i++) { if (i > 0) { os << ','; } os << '{'; for (int j = 0; j < 3; j++) { os << v.a[i][j] << ','; } os << v.a[i][3] << '}'; } os << "},b={" << v.b[0] << ',' << v.b[1]; os << "},c={" << int(v.c[0]) << ',' << int(v.c[1]) << ',' << int(v.c[2]); os << "},d={"; for (int i = 0; i < 4; i++) { if (i > 0) { os << ','; } os << '{' << v.d[i][0] << ',' << v.d[i][1] << '}'; } return os << '}'; } std::ostream &operator<<(std::ostream &os, const EnumStruct &v) { return os << "e1=" << (v.e1 == E1::A ? "A" : "B") << ",e2=" << (v.e2 == E2::X ? "X" : "Y"); } template py::array mkarray_via_buffer(size_t n) { return py::array(py::buffer_info( nullptr, sizeof(T), py::format_descriptor::format(), 1, {n}, {sizeof(T)})); } #define SET_TEST_VALS(s, i) \ do { \ (s).bool_ = (i) % 2 != 0; \ (s).uint_ = (uint32_t) (i); \ (s).float_ = (float) (i) *1.5f; \ (s).ldbl_ = (long double) (i) * -2.5L; \ } while (0) template py::array_t create_recarray(size_t n) { auto arr = mkarray_via_buffer(n); auto req = arr.request(); auto *ptr = static_cast(req.ptr); for (size_t i = 0; i < n; i++) { SET_TEST_VALS(ptr[i], i); } return arr; } template py::list print_recarray(py::array_t arr) { const auto req = arr.request(); auto *const ptr = static_cast(req.ptr); auto l = py::list(); for (py::ssize_t i = 0; i < req.size; i++) { std::stringstream ss; ss << ptr[i]; l.append(py::str(ss.str())); } return l; } py::array_t test_array_ctors(int i) { using arr_t = py::array_t; std::vector data{1, 2, 3, 4, 5, 6}; std::vector shape{3, 2}; std::vector strides{8, 4}; auto *ptr = data.data(); auto *vptr = (void *) ptr; auto dtype = py::dtype("int32"); py::buffer_info buf_ndim1(vptr, 4, "i", 6); py::buffer_info buf_ndim1_null(nullptr, 4, "i", 6); py::buffer_info buf_ndim2(vptr, 4, "i", 2, shape, strides); py::buffer_info buf_ndim2_null(nullptr, 4, "i", 2, shape, strides); auto fill = [](py::array arr) { auto req = arr.request(); for (int i = 0; i < 6; i++) { ((int32_t *) req.ptr)[i] = i + 1; } return arr; }; switch (i) { // shape: (3, 2) case 10: return arr_t(shape, strides, ptr); case 11: return py::array(shape, strides, ptr); case 12: return py::array(dtype, shape, strides, vptr); case 13: return arr_t(shape, ptr); case 14: return py::array(shape, ptr); case 15: return py::array(dtype, shape, vptr); case 16: return arr_t(buf_ndim2); case 17: return py::array(buf_ndim2); // shape: (3, 2) - post-fill case 20: return fill(arr_t(shape, strides)); case 21: return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor case 22: return fill(py::array(dtype, shape, strides)); case 23: return fill(arr_t(shape)); case 24: return py::array(shape, ptr); // can't have nullptr due to templated ctor case 25: return fill(py::array(dtype, shape)); case 26: return fill(arr_t(buf_ndim2_null)); case 27: return fill(py::array(buf_ndim2_null)); // shape: (6, ) case 30: return arr_t(6, ptr); case 31: return py::array(6, ptr); case 32: return py::array(dtype, 6, vptr); case 33: return arr_t(buf_ndim1); case 34: return py::array(buf_ndim1); // shape: (6, ) case 40: return fill(arr_t(6)); case 41: return py::array(6, ptr); // can't have nullptr due to templated ctor case 42: return fill(py::array(dtype, 6)); case 43: return fill(arr_t(buf_ndim1_null)); case 44: return fill(py::array(buf_ndim1_null)); } return arr_t(); } py::list test_dtype_ctors() { py::list list; list.append(py::dtype("int32")); list.append(py::dtype(std::string("float64"))); list.append(py::dtype::from_args(py::str("bool"))); py::list names, offsets, formats; py::dict dict; names.append(py::str("a")); names.append(py::str("b")); dict["names"] = names; offsets.append(py::int_(1)); offsets.append(py::int_(10)); dict["offsets"] = offsets; formats.append(py::dtype("int32")); formats.append(py::dtype("float64")); dict["formats"] = formats; dict["itemsize"] = py::int_(20); list.append(py::dtype::from_args(dict)); list.append(py::dtype(names, formats, offsets, 20)); list.append(py::dtype(py::buffer_info((void *) nullptr, sizeof(unsigned int), "I", 1))); list.append(py::dtype(py::buffer_info((void *) nullptr, 0, "T{i:a:f:b:}", 1))); list.append(py::dtype(py::detail::npy_api::NPY_DOUBLE_)); return list; } struct A {}; struct B {}; TEST_SUBMODULE(numpy_dtypes, m) { try { py::module_::import("numpy"); } catch (const py::error_already_set &) { return; } // typeinfo may be registered before the dtype descriptor for scalar casts to work... py::class_(m, "SimpleStruct") // Explicit construct to ensure zero-valued initialization. .def(py::init([]() { return SimpleStruct(); })) .def_readwrite("bool_", &SimpleStruct::bool_) .def_readwrite("uint_", &SimpleStruct::uint_) .def_readwrite("float_", &SimpleStruct::float_) .def_readwrite("ldbl_", &SimpleStruct::ldbl_) .def("astuple", [](const SimpleStruct &self) { return py::make_tuple(self.bool_, self.uint_, self.float_, self.ldbl_); }) .def_static("fromtuple", [](const py::tuple &tup) { if (py::len(tup) != 4) { throw py::cast_error("Invalid size"); } return SimpleStruct{tup[0].cast(), tup[1].cast(), tup[2].cast(), tup[3].cast()}; }); PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); PYBIND11_NUMPY_DTYPE(SimpleStructReordered, bool_, uint_, float_, ldbl_); PYBIND11_NUMPY_DTYPE(PackedStruct, bool_, uint_, float_, ldbl_); PYBIND11_NUMPY_DTYPE(NestedStruct, a, b); PYBIND11_NUMPY_DTYPE(PartialStruct, bool_, uint_, float_, ldbl_); PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a); PYBIND11_NUMPY_DTYPE(StringStruct, a, b); PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d); PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2); PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl); // ... or after py::class_(m, "PackedStruct"); PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y"); #ifdef PYBIND11_NEVER_DEFINED_EVER // If enabled, this should produce a static_assert failure telling the user that the struct // is not a POD type struct NotPOD { std::string v; NotPOD() : v("hi"){}; }; PYBIND11_NUMPY_DTYPE(NotPOD, v); #endif // Check that dtypes can be registered programmatically, both from // initializer lists of field descriptors and from other containers. py::detail::npy_format_descriptor::register_dtype({}); py::detail::npy_format_descriptor::register_dtype( std::vector{}); // test_recarray, test_scalar_conversion m.def("create_rec_simple", &create_recarray); m.def("create_rec_packed", &create_recarray); m.def("create_rec_nested", [](size_t n) { // test_signature py::array_t arr = mkarray_via_buffer(n); auto req = arr.request(); auto *ptr = static_cast(req.ptr); for (size_t i = 0; i < n; i++) { SET_TEST_VALS(ptr[i].a, i); SET_TEST_VALS(ptr[i].b, i + 1); } return arr; }); m.def("create_rec_partial", &create_recarray); m.def("create_rec_partial_nested", [](size_t n) { py::array_t arr = mkarray_via_buffer(n); auto req = arr.request(); auto *ptr = static_cast(req.ptr); for (size_t i = 0; i < n; i++) { SET_TEST_VALS(ptr[i].a, i); } return arr; }); m.def("print_rec_simple", &print_recarray); m.def("print_rec_packed", &print_recarray); m.def("print_rec_nested", &print_recarray); // test_format_descriptors m.def("get_format_unbound", []() { return py::format_descriptor::format(); }); m.def("print_format_descriptors", []() { py::list l; for (const auto &fmt : {py::format_descriptor::format(), py::format_descriptor::format(), py::format_descriptor::format(), py::format_descriptor::format(), py::format_descriptor::format(), py::format_descriptor::format(), py::format_descriptor::format(), py::format_descriptor::format(), py::format_descriptor::format()}) { l.append(py::cast(fmt)); } return l; }); // test_dtype std::vector dtype_names{ "byte", "short", "intc", "int_", "longlong", "ubyte", "ushort", "uintc", "uint", "ulonglong", "half", "single", "double", "longdouble", "csingle", "cdouble", "clongdouble", "bool_", "datetime64", "timedelta64", "object_"}; m.def("print_dtypes", []() { py::list l; for (const py::handle &d : {py::dtype::of(), py::dtype::of(), py::dtype::of(), py::dtype::of(), py::dtype::of(), py::dtype::of(), py::dtype::of(), py::dtype::of(), py::dtype::of(), py::dtype::of()}) { l.append(py::str(d)); } return l; }); m.def("test_dtype_ctors", &test_dtype_ctors); m.def("test_dtype_kind", [dtype_names]() { py::list list; for (const auto &dt_name : dtype_names) { list.append(py::dtype(dt_name).kind()); } return list; }); m.def("test_dtype_char_", [dtype_names]() { py::list list; for (const auto &dt_name : dtype_names) { list.append(py::dtype(dt_name).char_()); } return list; }); m.def("test_dtype_num", [dtype_names]() { py::list list; for (const auto &dt_name : dtype_names) { list.append(py::dtype(dt_name).num()); } return list; }); m.def("test_dtype_byteorder", [dtype_names]() { py::list list; for (const auto &dt_name : dtype_names) { list.append(py::dtype(dt_name).byteorder()); } return list; }); m.def("test_dtype_alignment", [dtype_names]() { py::list list; for (const auto &dt_name : dtype_names) { list.append(py::dtype(dt_name).alignment()); } return list; }); m.def("test_dtype_flags", [dtype_names]() { py::list list; for (const auto &dt_name : dtype_names) { list.append(py::dtype(dt_name).flags()); } return list; }); m.def("test_dtype_methods", []() { py::list list; auto dt1 = py::dtype::of(); auto dt2 = py::dtype::of(); list.append(dt1); list.append(dt2); list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields())); list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize())); return list; }); struct TrailingPaddingStruct { int32_t a; char b; }; PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b); m.def("trailing_padding_dtype", []() { return py::dtype::of(); }); // test_string_array m.def("create_string_array", [](bool non_empty) { py::array_t arr = mkarray_via_buffer(non_empty ? 4 : 0); if (non_empty) { auto req = arr.request(); auto *ptr = static_cast(req.ptr); for (py::ssize_t i = 0; i < req.size * req.itemsize; i++) { static_cast(req.ptr)[i] = 0; } ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a'; ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a'; ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a'; ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b'; ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b'; ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c'; } return arr; }); m.def("print_string_array", &print_recarray); // test_array_array m.def("create_array_array", [](size_t n) { py::array_t arr = mkarray_via_buffer(n); auto *ptr = (ArrayStruct *) arr.mutable_data(); for (size_t i = 0; i < n; i++) { for (size_t j = 0; j < 3; j++) { for (size_t k = 0; k < 4; k++) { ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26); } } for (size_t j = 0; j < 2; j++) { ptr[i].b[j] = int32_t(i * 1000 + j); } for (size_t j = 0; j < 3; j++) { ptr[i].c[j] = uint8_t(i * 10 + j); } for (size_t j = 0; j < 4; j++) { for (size_t k = 0; k < 2; k++) { ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k); } } } return arr; }); m.def("print_array_array", &print_recarray); // test_enum_array m.def("create_enum_array", [](size_t n) { py::array_t arr = mkarray_via_buffer(n); auto *ptr = (EnumStruct *) arr.mutable_data(); for (size_t i = 0; i < n; i++) { ptr[i].e1 = static_cast(-1 + ((int) i % 2) * 2); ptr[i].e2 = static_cast(1 + (i % 2)); } return arr; }); m.def("print_enum_array", &print_recarray); // test_complex_array m.def("create_complex_array", [](size_t n) { py::array_t arr = mkarray_via_buffer(n); auto *ptr = (ComplexStruct *) arr.mutable_data(); for (size_t i = 0; i < n; i++) { ptr[i].cflt.real(float(i)); ptr[i].cflt.imag(float(i) + 0.25f); ptr[i].cdbl.real(double(i) + 0.5); ptr[i].cdbl.imag(double(i) + 0.75); } return arr; }); m.def("print_complex_array", &print_recarray); // test_array_constructors m.def("test_array_ctors", &test_array_ctors); // test_compare_buffer_info struct CompareStruct { bool x; uint32_t y; float z; }; PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z); m.def("compare_buffer_info", []() { py::list list; list.append(py::bool_(py::detail::compare_buffer_info::compare( py::buffer_info(nullptr, sizeof(float), "f", 1)))); list.append(py::bool_(py::detail::compare_buffer_info::compare( py::buffer_info(nullptr, sizeof(int), "I", 1)))); list.append(py::bool_(py::detail::compare_buffer_info::compare( py::buffer_info(nullptr, sizeof(long), "l", 1)))); list.append(py::bool_(py::detail::compare_buffer_info::compare( py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1)))); list.append(py::bool_(py::detail::compare_buffer_info::compare( py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1)))); return list; }); m.def("buffer_to_dtype", [](py::buffer &buf) { return py::dtype(buf.request()); }); // test_scalar_conversion auto f_simple = [](SimpleStruct s) { return s.uint_ * 10; }; m.def("f_simple", f_simple); m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; }); m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; }); // test_vectorize m.def("f_simple_vectorized", py::vectorize(f_simple)); auto f_simple_pass_thru = [](SimpleStruct s) { return s; }; m.def("f_simple_pass_thru_vectorized", py::vectorize(f_simple_pass_thru)); // test_register_dtype m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); }); // test_str_leak m.def("dtype_wrapper", [](const py::object &d) { return py::dtype::from_args(d); }); } aoflagger-v3.4.0/external/pybind11/tests/test_builtin_casters.py0000644000175000017500000004153314507760431023554 0ustar olesolesimport sys import pytest import env from pybind11_tests import IncType, UserType from pybind11_tests import builtin_casters as m def test_simple_string(): assert m.string_roundtrip("const char *") == "const char *" def test_unicode_conversion(): """Tests unicode conversion and error reporting.""" assert m.good_utf8_string() == "Say utf8‽ 🎂 ð€" assert m.good_utf16_string() == "b‽🎂ð€z" assert m.good_utf32_string() == "að€ðŸŽ‚‽z" assert m.good_wchar_string() == "a⸘ð€z" if hasattr(m, "has_u8string"): assert m.good_utf8_u8string() == "Say utf8‽ 🎂 ð€" with pytest.raises(UnicodeDecodeError): m.bad_utf8_string() with pytest.raises(UnicodeDecodeError): m.bad_utf16_string() # These are provided only if they actually fail (they don't when 32-bit) if hasattr(m, "bad_utf32_string"): with pytest.raises(UnicodeDecodeError): m.bad_utf32_string() if hasattr(m, "bad_wchar_string"): with pytest.raises(UnicodeDecodeError): m.bad_wchar_string() if hasattr(m, "has_u8string"): with pytest.raises(UnicodeDecodeError): m.bad_utf8_u8string() assert m.u8_Z() == "Z" assert m.u8_eacute() == "é" assert m.u16_ibang() == "‽" assert m.u32_mathbfA() == "ð€" assert m.wchar_heart() == "♥" if hasattr(m, "has_u8string"): assert m.u8_char8_Z() == "Z" def test_single_char_arguments(): """Tests failures for passing invalid inputs to char-accepting functions""" def toobig_message(r): return f"Character code point not in range({r:#x})" toolong_message = "Expected a character, but multi-character string found" assert m.ord_char("a") == 0x61 # simple ASCII assert m.ord_char_lv("b") == 0x62 assert ( m.ord_char("é") == 0xE9 ) # requires 2 bytes in utf-8, but can be stuffed in a char with pytest.raises(ValueError) as excinfo: assert m.ord_char("Ä€") == 0x100 # requires 2 bytes, doesn't fit in a char assert str(excinfo.value) == toobig_message(0x100) with pytest.raises(ValueError) as excinfo: assert m.ord_char("ab") assert str(excinfo.value) == toolong_message assert m.ord_char16("a") == 0x61 assert m.ord_char16("é") == 0xE9 assert m.ord_char16_lv("ê") == 0xEA assert m.ord_char16("Ä€") == 0x100 assert m.ord_char16("‽") == 0x203D assert m.ord_char16("♥") == 0x2665 assert m.ord_char16_lv("♡") == 0x2661 with pytest.raises(ValueError) as excinfo: assert m.ord_char16("🎂") == 0x1F382 # requires surrogate pair assert str(excinfo.value) == toobig_message(0x10000) with pytest.raises(ValueError) as excinfo: assert m.ord_char16("aa") assert str(excinfo.value) == toolong_message assert m.ord_char32("a") == 0x61 assert m.ord_char32("é") == 0xE9 assert m.ord_char32("Ä€") == 0x100 assert m.ord_char32("‽") == 0x203D assert m.ord_char32("♥") == 0x2665 assert m.ord_char32("🎂") == 0x1F382 with pytest.raises(ValueError) as excinfo: assert m.ord_char32("aa") assert str(excinfo.value) == toolong_message assert m.ord_wchar("a") == 0x61 assert m.ord_wchar("é") == 0xE9 assert m.ord_wchar("Ä€") == 0x100 assert m.ord_wchar("‽") == 0x203D assert m.ord_wchar("♥") == 0x2665 if m.wchar_size == 2: with pytest.raises(ValueError) as excinfo: assert m.ord_wchar("🎂") == 0x1F382 # requires surrogate pair assert str(excinfo.value) == toobig_message(0x10000) else: assert m.ord_wchar("🎂") == 0x1F382 with pytest.raises(ValueError) as excinfo: assert m.ord_wchar("aa") assert str(excinfo.value) == toolong_message if hasattr(m, "has_u8string"): assert m.ord_char8("a") == 0x61 # simple ASCII assert m.ord_char8_lv("b") == 0x62 assert ( m.ord_char8("é") == 0xE9 ) # requires 2 bytes in utf-8, but can be stuffed in a char with pytest.raises(ValueError) as excinfo: assert m.ord_char8("Ä€") == 0x100 # requires 2 bytes, doesn't fit in a char assert str(excinfo.value) == toobig_message(0x100) with pytest.raises(ValueError) as excinfo: assert m.ord_char8("ab") assert str(excinfo.value) == toolong_message def test_bytes_to_string(): """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is one-way: the only way to return bytes to Python is via the pybind11::bytes class.""" # Issue #816 assert m.strlen(b"hi") == 2 assert m.string_length(b"world") == 5 assert m.string_length(b"a\x00b") == 3 assert m.strlen(b"a\x00b") == 1 # C-string limitation # passing in a utf8 encoded string should work assert m.string_length("💩".encode()) == 4 def test_bytearray_to_string(): """Tests the ability to pass bytearray to C++ string-accepting functions""" assert m.string_length(bytearray(b"Hi")) == 2 assert m.strlen(bytearray(b"bytearray")) == 9 assert m.string_length(bytearray()) == 0 assert m.string_length(bytearray("🦜", "utf-8", "strict")) == 4 assert m.string_length(bytearray(b"\x80")) == 1 @pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no ") def test_string_view(capture): """Tests support for C++17 string_view arguments and return values""" assert m.string_view_chars("Hi") == [72, 105] assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82] assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82] assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874] if hasattr(m, "has_u8string"): assert m.string_view8_chars("Hi") == [72, 105] assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82] assert m.string_view_return() == "utf8 secret 🎂" assert m.string_view16_return() == "utf16 secret 🎂" assert m.string_view32_return() == "utf32 secret 🎂" if hasattr(m, "has_u8string"): assert m.string_view8_return() == "utf8 secret 🎂" with capture: m.string_view_print("Hi") m.string_view_print("utf8 🎂") m.string_view16_print("utf16 🎂") m.string_view32_print("utf32 🎂") assert ( capture == """ Hi 2 utf8 🎂 9 utf16 🎂 8 utf32 🎂 7 """ ) if hasattr(m, "has_u8string"): with capture: m.string_view8_print("Hi") m.string_view8_print("utf8 🎂") assert ( capture == """ Hi 2 utf8 🎂 9 """ ) with capture: m.string_view_print("Hi, ascii") m.string_view_print("Hi, utf8 🎂") m.string_view16_print("Hi, utf16 🎂") m.string_view32_print("Hi, utf32 🎂") assert ( capture == """ Hi, ascii 9 Hi, utf8 🎂 13 Hi, utf16 🎂 12 Hi, utf32 🎂 11 """ ) if hasattr(m, "has_u8string"): with capture: m.string_view8_print("Hi, ascii") m.string_view8_print("Hi, utf8 🎂") assert ( capture == """ Hi, ascii 9 Hi, utf8 🎂 13 """ ) assert m.string_view_bytes() == b"abc \x80\x80 def" assert m.string_view_str() == "abc ‽ def" assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def" if hasattr(m, "has_u8string"): assert m.string_view8_str() == "abc ‽ def" assert m.string_view_memoryview() == "Have some 🎂".encode() assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success" assert m.str_from_type_with_both_operator_string_and_string_view() == "success" def test_integer_casting(): """Issue #929 - out-of-range integer values shouldn't be accepted""" assert m.i32_str(-1) == "-1" assert m.i64_str(-1) == "-1" assert m.i32_str(2000000000) == "2000000000" assert m.u32_str(2000000000) == "2000000000" assert m.i64_str(-999999999999) == "-999999999999" assert m.u64_str(999999999999) == "999999999999" with pytest.raises(TypeError) as excinfo: m.u32_str(-1) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.u64_str(-1) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.i32_str(-3000000000) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.i32_str(3000000000) assert "incompatible function arguments" in str(excinfo.value) def test_int_convert(): class Int: def __int__(self): return 42 class NotInt: pass class Float: def __float__(self): return 41.99999 class Index: def __index__(self): return 42 class IntAndIndex: def __int__(self): return 42 def __index__(self): return 0 class RaisingTypeErrorOnIndex: def __index__(self): raise TypeError def __int__(self): return 42 class RaisingValueErrorOnIndex: def __index__(self): raise ValueError def __int__(self): return 42 convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert def requires_conversion(v): pytest.raises(TypeError, noconvert, v) def cant_convert(v): pytest.raises(TypeError, convert, v) assert convert(7) == 7 assert noconvert(7) == 7 cant_convert(3.14159) # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON: with env.deprecated_call(): assert convert(Int()) == 42 else: assert convert(Int()) == 42 requires_conversion(Int()) cant_convert(NotInt()) cant_convert(Float()) # Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`, # but pybind11 "backports" this behavior. assert convert(Index()) == 42 assert noconvert(Index()) == 42 assert convert(IntAndIndex()) == 0 # Fishy; `int(DoubleThought)` == 42 assert noconvert(IntAndIndex()) == 0 assert convert(RaisingTypeErrorOnIndex()) == 42 requires_conversion(RaisingTypeErrorOnIndex()) assert convert(RaisingValueErrorOnIndex()) == 42 requires_conversion(RaisingValueErrorOnIndex()) def test_numpy_int_convert(): np = pytest.importorskip("numpy") convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert def require_implicit(v): pytest.raises(TypeError, noconvert, v) # `np.intc` is an alias that corresponds to a C++ `int` assert convert(np.intc(42)) == 42 assert noconvert(np.intc(42)) == 42 # The implicit conversion from np.float32 is undesirable but currently accepted. # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) # https://github.com/pybind/pybind11/issues/3408 if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON: with env.deprecated_call(): assert convert(np.float32(3.14159)) == 3 else: assert convert(np.float32(3.14159)) == 3 require_implicit(np.float32(3.14159)) def test_tuple(doc): """std::pair <-> tuple & std::tuple <-> tuple""" assert m.pair_passthrough((True, "test")) == ("test", True) assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True) # Any sequence can be cast to a std::pair or std::tuple assert m.pair_passthrough([True, "test"]) == ("test", True) assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True) assert m.empty_tuple() == () assert ( doc(m.pair_passthrough) == """ pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool] Return a pair in reversed order """ ) assert ( doc(m.tuple_passthrough) == """ tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] Return a triple in reversed order """ ) assert m.rvalue_pair() == ("rvalue", "rvalue") assert m.lvalue_pair() == ("lvalue", "lvalue") assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue") assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue") assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue"))) assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue"))) assert m.int_string_pair() == (2, "items") def test_builtins_cast_return_none(): """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None""" assert m.return_none_string() is None assert m.return_none_char() is None assert m.return_none_bool() is None assert m.return_none_int() is None assert m.return_none_float() is None assert m.return_none_pair() is None def test_none_deferred(): """None passed as various argument types should defer to other overloads""" assert not m.defer_none_cstring("abc") assert m.defer_none_cstring(None) assert not m.defer_none_custom(UserType()) assert m.defer_none_custom(None) assert m.nodefer_none_void(None) def test_void_caster(): assert m.load_nullptr_t(None) is None assert m.cast_nullptr_t() is None def test_reference_wrapper(): """std::reference_wrapper for builtin and user types""" assert m.refwrap_builtin(42) == 420 assert m.refwrap_usertype(UserType(42)) == 42 assert m.refwrap_usertype_const(UserType(42)) == 42 with pytest.raises(TypeError) as excinfo: m.refwrap_builtin(None) assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.refwrap_usertype(None) assert "incompatible function arguments" in str(excinfo.value) assert m.refwrap_lvalue().value == 1 assert m.refwrap_lvalue_const().value == 1 a1 = m.refwrap_list(copy=True) a2 = m.refwrap_list(copy=True) assert [x.value for x in a1] == [2, 3] assert [x.value for x in a2] == [2, 3] assert a1[0] is not a2[0] assert a1[1] is not a2[1] b1 = m.refwrap_list(copy=False) b2 = m.refwrap_list(copy=False) assert [x.value for x in b1] == [1, 2] assert [x.value for x in b2] == [1, 2] assert b1[0] is b2[0] assert b1[1] is b2[1] assert m.refwrap_iiw(IncType(5)) == 5 assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10] def test_complex_cast(): """std::complex casts""" assert m.complex_cast(1) == "1.0" assert m.complex_cast(2j) == "(0.0, 2.0)" def test_bool_caster(): """Test bool caster implicit conversions.""" convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert def require_implicit(v): pytest.raises(TypeError, noconvert, v) def cant_convert(v): pytest.raises(TypeError, convert, v) # straight up bool assert convert(True) is True assert convert(False) is False assert noconvert(True) is True assert noconvert(False) is False # None requires implicit conversion require_implicit(None) assert convert(None) is False class A: def __init__(self, x): self.x = x def __nonzero__(self): return self.x def __bool__(self): return self.x class B: pass # Arbitrary objects are not accepted cant_convert(object()) cant_convert(B()) # Objects with __nonzero__ / __bool__ defined can be converted require_implicit(A(True)) assert convert(A(True)) is True assert convert(A(False)) is False def test_numpy_bool(): np = pytest.importorskip("numpy") convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert def cant_convert(v): pytest.raises(TypeError, convert, v) # np.bool_ is not considered implicit assert convert(np.bool_(True)) is True assert convert(np.bool_(False)) is False assert noconvert(np.bool_(True)) is True assert noconvert(np.bool_(False)) is False cant_convert(np.zeros(2, dtype="int")) def test_int_long(): assert isinstance(m.int_cast(), int) assert isinstance(m.long_cast(), int) assert isinstance(m.longlong_cast(), int) def test_void_caster_2(): assert m.test_void_caster() def test_const_ref_caster(): """Verifies that const-ref is propagated through type_caster cast_op. The returned ConstRefCasted type is a minimal type that is constructed to reference the casting mode used. """ x = False assert m.takes(x) == 1 assert m.takes_move(x) == 1 assert m.takes_ptr(x) == 3 assert m.takes_ref(x) == 2 assert m.takes_ref_wrap(x) == 2 assert m.takes_const_ptr(x) == 5 assert m.takes_const_ref(x) == 4 assert m.takes_const_ref_wrap(x) == 4 aoflagger-v3.4.0/external/pybind11/tests/test_pickling.py0000644000175000017500000000524014507760431022155 0ustar olesolesimport pickle import re import pytest import env from pybind11_tests import pickling as m def test_pickle_simple_callable(): assert m.simple_callable() == 20220426 if env.PYPY: serialized = pickle.dumps(m.simple_callable) deserialized = pickle.loads(serialized) assert deserialized() == 20220426 else: # To document broken behavior: currently it fails universally with # all C Python versions. with pytest.raises(TypeError) as excinfo: pickle.dumps(m.simple_callable) assert re.search("can.*t pickle .*PyCapsule.* object", str(excinfo.value)) @pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"]) def test_roundtrip(cls_name): cls = getattr(m, cls_name) p = cls("test_value") p.setExtra1(15) p.setExtra2(48) data = pickle.dumps(p, 2) # Must use pickle protocol >= 2 p2 = pickle.loads(data) assert p2.value() == p.value() assert p2.extra1() == p.extra1() assert p2.extra2() == p.extra2() @pytest.mark.xfail("env.PYPY") @pytest.mark.parametrize("cls_name", ["PickleableWithDict", "PickleableWithDictNew"]) def test_roundtrip_with_dict(cls_name): cls = getattr(m, cls_name) p = cls("test_value") p.extra = 15 p.dynamic = "Attribute" data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL) p2 = pickle.loads(data) assert p2.value == p.value assert p2.extra == p.extra assert p2.dynamic == p.dynamic def test_enum_pickle(): from pybind11_tests import enums as e data = pickle.dumps(e.EOne, 2) assert e.EOne == pickle.loads(data) # # exercise_trampoline # class SimplePyDerived(m.SimpleBase): pass def test_roundtrip_simple_py_derived(): p = SimplePyDerived() p.num = 202 p.stored_in_dict = 303 data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL) p2 = pickle.loads(data) assert isinstance(p2, SimplePyDerived) assert p2.num == 202 assert p2.stored_in_dict == 303 def test_roundtrip_simple_cpp_derived(): p = m.make_SimpleCppDerivedAsBase() assert m.check_dynamic_cast_SimpleCppDerived(p) p.num = 404 if not env.PYPY: # To ensure that this unit test is not accidentally invalidated. with pytest.raises(AttributeError): # Mimics the `setstate` C++ implementation. setattr(p, "__dict__", {}) # noqa: B010 data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL) p2 = pickle.loads(data) assert isinstance(p2, m.SimpleBase) assert p2.num == 404 # Issue #3062: pickleable base C++ classes can incur object slicing # if derived typeid is not registered with pybind11 assert not m.check_dynamic_cast_SimpleCppDerived(p2) aoflagger-v3.4.0/external/pybind11/tests/test_call_policies.cpp0000644000175000017500000001002614507760431023307 0ustar olesoles/* tests/test_call_policies.cpp -- keep_alive and call_guard Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "pybind11_tests.h" struct CustomGuard { static bool enabled; CustomGuard() { enabled = true; } ~CustomGuard() { enabled = false; } static const char *report_status() { return enabled ? "guarded" : "unguarded"; } }; bool CustomGuard::enabled = false; struct DependentGuard { static bool enabled; DependentGuard() { enabled = CustomGuard::enabled; } ~DependentGuard() { enabled = false; } static const char *report_status() { return enabled ? "guarded" : "unguarded"; } }; bool DependentGuard::enabled = false; TEST_SUBMODULE(call_policies, m) { // Parent/Child are used in: // test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived, // test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor class Child { public: Child() { py::print("Allocating child."); } Child(const Child &) = default; Child(Child &&) = default; ~Child() { py::print("Releasing child."); } }; py::class_(m, "Child").def(py::init<>()); class Parent { public: Parent() { py::print("Allocating parent."); } Parent(const Parent &parent) = default; ~Parent() { py::print("Releasing parent."); } void addChild(Child *) {} Child *returnChild() { return new Child(); } Child *returnNullChild() { return nullptr; } static Child *staticFunction(Parent *) { return new Child(); } }; py::class_(m, "Parent") .def(py::init<>()) .def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>()) .def("addChild", &Parent::addChild) .def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>()) .def("returnChild", &Parent::returnChild) .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()) .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>()) .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>()) .def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>()); m.def( "free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>()); m.def( "invalid_arg_index", [] {}, py::keep_alive<0, 1>()); #if !defined(PYPY_VERSION) // test_alive_gc class ParentGC : public Parent { public: using Parent::Parent; }; py::class_(m, "ParentGC", py::dynamic_attr()).def(py::init<>()); #endif // test_call_guard m.def("unguarded_call", &CustomGuard::report_status); m.def("guarded_call", &CustomGuard::report_status, py::call_guard()); m.def( "multiple_guards_correct_order", []() { return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status(); }, py::call_guard()); m.def( "multiple_guards_wrong_order", []() { return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status(); }, py::call_guard()); #if defined(WITH_THREAD) && !defined(PYPY_VERSION) // `py::call_guard()` should work in PyPy as well, // but it's unclear how to test it without `PyGILState_GetThisThreadState`. auto report_gil_status = []() { auto is_gil_held = false; if (auto *tstate = py::detail::get_thread_state_unchecked()) { is_gil_held = (tstate == PyGILState_GetThisThreadState()); } return is_gil_held ? "GIL held" : "GIL released"; }; m.def("with_gil", report_gil_status); m.def("without_gil", report_gil_status, py::call_guard()); #endif } aoflagger-v3.4.0/external/pybind11/tests/local_bindings.h0000644000175000017500000000543714507760431022074 0ustar olesoles#pragma once #include "pybind11_tests.h" #include /// Simple class used to test py::local: template class LocalBase { public: explicit LocalBase(int i) : i(i) {} int i = -1; }; /// Registered with py::module_local in both main and secondary modules: using LocalType = LocalBase<0>; /// Registered without py::module_local in both modules: using NonLocalType = LocalBase<1>; /// A second non-local type (for stl_bind tests): using NonLocal2 = LocalBase<2>; /// Tests within-module, different-compilation-unit local definition conflict: using LocalExternal = LocalBase<3>; /// Mixed: registered local first, then global using MixedLocalGlobal = LocalBase<4>; /// Mixed: global first, then local using MixedGlobalLocal = LocalBase<5>; /// Registered with py::module_local only in the secondary module: using ExternalType1 = LocalBase<6>; using ExternalType2 = LocalBase<7>; using LocalVec = std::vector; using LocalVec2 = std::vector; using LocalMap = std::unordered_map; using NonLocalVec = std::vector; using NonLocalVec2 = std::vector; using NonLocalMap = std::unordered_map; using NonLocalMap2 = std::unordered_map; // Exception that will be caught via the module local translator. class LocalException : public std::exception { public: explicit LocalException(const char *m) : message{m} {} const char *what() const noexcept override { return message.c_str(); } private: std::string message = ""; }; // Exception that will be registered with register_local_exception_translator class LocalSimpleException : public std::exception { public: explicit LocalSimpleException(const char *m) : message{m} {} const char *what() const noexcept override { return message.c_str(); } private: std::string message = ""; }; PYBIND11_MAKE_OPAQUE(LocalVec); PYBIND11_MAKE_OPAQUE(LocalVec2); PYBIND11_MAKE_OPAQUE(LocalMap); PYBIND11_MAKE_OPAQUE(NonLocalVec); // PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2 PYBIND11_MAKE_OPAQUE(NonLocalMap); PYBIND11_MAKE_OPAQUE(NonLocalMap2); // Simple bindings (used with the above): template py::class_ bind_local(Args &&...args) { return py::class_(std::forward(args)...).def(py::init()).def("get", [](T &i) { return i.i + Adjust; }); }; // Simulate a foreign library base class (to match the example in the docs): namespace pets { class Pet { public: explicit Pet(std::string name) : name_(std::move(name)) {} std::string name_; const std::string &name() const { return name_; } }; } // namespace pets struct MixGL { int i; explicit MixGL(int i) : i{i} {} }; struct MixGL2 { int i; explicit MixGL2(int i) : i{i} {} }; aoflagger-v3.4.0/external/pybind11/tests/test_modules.py0000644000175000017500000000771314507760431022034 0ustar olesolesimport builtins import pytest import env from pybind11_tests import ConstructorStats from pybind11_tests import modules as m from pybind11_tests.modules import subsubmodule as ms def test_nested_modules(): import pybind11_tests assert pybind11_tests.__name__ == "pybind11_tests" assert pybind11_tests.modules.__name__ == "pybind11_tests.modules" assert ( pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule" ) assert m.__name__ == "pybind11_tests.modules" assert ms.__name__ == "pybind11_tests.modules.subsubmodule" assert ms.submodule_func() == "submodule_func()" def test_reference_internal(): b = ms.B() assert str(b.get_a1()) == "A[1]" assert str(b.a1) == "A[1]" assert str(b.get_a2()) == "A[2]" assert str(b.a2) == "A[2]" b.a1 = ms.A(42) b.a2 = ms.A(43) assert str(b.get_a1()) == "A[42]" assert str(b.a1) == "A[42]" assert str(b.get_a2()) == "A[43]" assert str(b.a2) == "A[43]" astats, bstats = ConstructorStats.get(ms.A), ConstructorStats.get(ms.B) assert astats.alive() == 2 assert bstats.alive() == 1 del b assert astats.alive() == 0 assert bstats.alive() == 0 assert astats.values() == ["1", "2", "42", "43"] assert bstats.values() == [] assert astats.default_constructions == 0 assert bstats.default_constructions == 1 assert astats.copy_constructions == 0 assert bstats.copy_constructions == 0 # assert astats.move_constructions >= 0 # Don't invoke any # assert bstats.move_constructions >= 0 # Don't invoke any assert astats.copy_assignments == 2 assert bstats.copy_assignments == 0 assert astats.move_assignments == 0 assert bstats.move_assignments == 0 def test_importing(): from collections import OrderedDict from pybind11_tests.modules import OD assert OD is OrderedDict assert str(OD([(1, "a"), (2, "b")])) == "OrderedDict([(1, 'a'), (2, 'b')])" def test_pydoc(): """Pydoc needs to be able to provide help() for everything inside a pybind11 module""" import pydoc import pybind11_tests assert pybind11_tests.__name__ == "pybind11_tests" assert pybind11_tests.__doc__ == "pybind11 test module" assert pydoc.text.docmodule(pybind11_tests) def test_duplicate_registration(): """Registering two things with the same name""" assert m.duplicate_registration() == [] def test_builtin_key_type(): """Test that all the keys in the builtin modules have type str. Previous versions of pybind11 would add a unicode key in python 2. """ assert all(type(k) == str for k in dir(builtins)) @pytest.mark.xfail("env.PYPY", reason="PyModule_GetName()") def test_def_submodule_failures(): sm = m.def_submodule(m, b"ScratchSubModuleName") # Using bytes to show it works. assert sm.__name__ == m.__name__ + "." + "ScratchSubModuleName" malformed_utf8 = b"\x80" if env.PYPY: # It is not worth the effort finding a trigger for a failure when running with PyPy. pytest.skip("Sufficiently exercised on platforms other than PyPy.") else: # Meant to trigger PyModule_GetName() failure: sm_name_orig = sm.__name__ sm.__name__ = malformed_utf8 try: # We want to assert that a bad __name__ causes some kind of failure, although we do not want to exercise # the internals of PyModule_GetName(). Currently all supported Python versions raise SystemError. If that # changes in future Python versions, simply add the new expected exception types here. with pytest.raises(SystemError): m.def_submodule(sm, b"SubSubModuleName") finally: # Clean up to ensure nothing gets upset by a module with an invalid __name__. sm.__name__ = sm_name_orig # Purely precautionary. # Meant to trigger PyImport_AddModule() failure: with pytest.raises(UnicodeDecodeError): m.def_submodule(sm, malformed_utf8) aoflagger-v3.4.0/external/pybind11/tests/test_eigen_tensor.inl0000644000175000017500000002453614507760431023201 0ustar olesoles/* tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include PYBIND11_NAMESPACE_BEGIN(eigen_tensor_test) namespace py = pybind11; PYBIND11_WARNING_DISABLE_MSVC(4127) template void reset_tensor(M &x) { for (int i = 0; i < x.dimension(0); i++) { for (int j = 0; j < x.dimension(1); j++) { for (int k = 0; k < x.dimension(2); k++) { x(i, j, k) = i * (5 * 2) + j * 2 + k; } } } } template bool check_tensor(M &x) { for (int i = 0; i < x.dimension(0); i++) { for (int j = 0; j < x.dimension(1); j++) { for (int k = 0; k < x.dimension(2); k++) { if (x(i, j, k) != (i * (5 * 2) + j * 2 + k)) { return false; } } } } return true; } template Eigen::Tensor &get_tensor() { static Eigen::Tensor *x; if (!x) { x = new Eigen::Tensor(3, 5, 2); reset_tensor(*x); } return *x; } template Eigen::TensorMap> &get_tensor_map() { static Eigen::TensorMap> *x; if (!x) { x = new Eigen::TensorMap>(get_tensor()); } return *x; } template Eigen::TensorFixedSize, Options> &get_fixed_tensor() { static Eigen::TensorFixedSize, Options> *x; if (!x) { Eigen::aligned_allocator, Options>> allocator; x = new (allocator.allocate(1)) Eigen::TensorFixedSize, Options>(); reset_tensor(*x); } return *x; } template const Eigen::Tensor &get_const_tensor() { return get_tensor(); } template struct CustomExample { CustomExample() : member(get_tensor()), view_member(member) {} Eigen::Tensor member; Eigen::TensorMap> view_member; }; template void init_tensor_module(pybind11::module &m) { const char *needed_options = ""; if (Options == Eigen::ColMajor) { needed_options = "F"; } else { needed_options = "C"; } m.attr("needed_options") = needed_options; m.def("setup", []() { reset_tensor(get_tensor()); reset_tensor(get_fixed_tensor()); }); m.def("is_ok", []() { return check_tensor(get_tensor()) && check_tensor(get_fixed_tensor()); }); py::class_>(m, "CustomExample", py::module_local()) .def(py::init<>()) .def_readonly( "member", &CustomExample::member, py::return_value_policy::reference_internal) .def_readonly("member_view", &CustomExample::view_member, py::return_value_policy::reference_internal); m.def( "copy_fixed_tensor", []() { return &get_fixed_tensor(); }, py::return_value_policy::copy); m.def( "copy_tensor", []() { return &get_tensor(); }, py::return_value_policy::copy); m.def( "copy_const_tensor", []() { return &get_const_tensor(); }, py::return_value_policy::copy); m.def( "move_fixed_tensor_copy", []() -> Eigen::TensorFixedSize, Options> { return get_fixed_tensor(); }, py::return_value_policy::move); m.def( "move_tensor_copy", []() -> Eigen::Tensor { return get_tensor(); }, py::return_value_policy::move); m.def( "move_const_tensor", []() -> const Eigen::Tensor & { return get_const_tensor(); }, py::return_value_policy::move); m.def( "take_fixed_tensor", []() { Eigen::aligned_allocator< Eigen::TensorFixedSize, Options>> allocator; return new (allocator.allocate(1)) Eigen::TensorFixedSize, Options>( get_fixed_tensor()); }, py::return_value_policy::take_ownership); m.def( "take_tensor", []() { return new Eigen::Tensor(get_tensor()); }, py::return_value_policy::take_ownership); m.def( "take_const_tensor", []() -> const Eigen::Tensor * { return new Eigen::Tensor(get_tensor()); }, py::return_value_policy::take_ownership); m.def( "take_view_tensor", []() -> const Eigen::TensorMap> * { return new Eigen::TensorMap>(get_tensor()); }, py::return_value_policy::take_ownership); m.def( "reference_tensor", []() { return &get_tensor(); }, py::return_value_policy::reference); m.def( "reference_tensor_v2", []() -> Eigen::Tensor & { return get_tensor(); }, py::return_value_policy::reference); m.def( "reference_tensor_internal", []() { return &get_tensor(); }, py::return_value_policy::reference_internal); m.def( "reference_fixed_tensor", []() { return &get_tensor(); }, py::return_value_policy::reference); m.def( "reference_const_tensor", []() { return &get_const_tensor(); }, py::return_value_policy::reference); m.def( "reference_const_tensor_v2", []() -> const Eigen::Tensor & { return get_const_tensor(); }, py::return_value_policy::reference); m.def( "reference_view_of_tensor", []() -> Eigen::TensorMap> { return get_tensor_map(); }, py::return_value_policy::reference); m.def( "reference_view_of_tensor_v2", // NOLINTNEXTLINE(readability-const-return-type) []() -> const Eigen::TensorMap> { return get_tensor_map(); // NOLINT(readability-const-return-type) }, // NOLINT(readability-const-return-type) py::return_value_policy::reference); m.def( "reference_view_of_tensor_v3", []() -> Eigen::TensorMap> * { return &get_tensor_map(); }, py::return_value_policy::reference); m.def( "reference_view_of_tensor_v4", []() -> const Eigen::TensorMap> * { return &get_tensor_map(); }, py::return_value_policy::reference); m.def( "reference_view_of_tensor_v5", []() -> Eigen::TensorMap> & { return get_tensor_map(); }, py::return_value_policy::reference); m.def( "reference_view_of_tensor_v6", []() -> const Eigen::TensorMap> & { return get_tensor_map(); }, py::return_value_policy::reference); m.def( "reference_view_of_fixed_tensor", []() { return Eigen::TensorMap< Eigen::TensorFixedSize, Options>>( get_fixed_tensor()); }, py::return_value_policy::reference); m.def("round_trip_tensor", [](const Eigen::Tensor &tensor) { return tensor; }); m.def( "round_trip_tensor_noconvert", [](const Eigen::Tensor &tensor) { return tensor; }, py::arg("tensor").noconvert()); m.def("round_trip_tensor2", [](const Eigen::Tensor &tensor) { return tensor; }); m.def("round_trip_fixed_tensor", [](const Eigen::TensorFixedSize, Options> &tensor) { return tensor; }); m.def( "round_trip_view_tensor", [](Eigen::TensorMap> view) { return view; }, py::return_value_policy::reference); m.def( "round_trip_view_tensor_ref", [](Eigen::TensorMap> &view) { return view; }, py::return_value_policy::reference); m.def( "round_trip_view_tensor_ptr", [](Eigen::TensorMap> *view) { return view; }, py::return_value_policy::reference); m.def( "round_trip_aligned_view_tensor", [](Eigen::TensorMap, Eigen::Aligned> view) { return view; }, py::return_value_policy::reference); m.def( "round_trip_const_view_tensor", [](Eigen::TensorMap> view) { return Eigen::Tensor(view); }, py::return_value_policy::move); m.def( "round_trip_rank_0", [](const Eigen::Tensor &tensor) { return tensor; }, py::return_value_policy::move); m.def( "round_trip_rank_0_noconvert", [](const Eigen::Tensor &tensor) { return tensor; }, py::arg("tensor").noconvert(), py::return_value_policy::move); m.def( "round_trip_rank_0_view", [](Eigen::TensorMap> &tensor) { return tensor; }, py::return_value_policy::reference); } void test_module(py::module_ &m) { auto f_style = m.def_submodule("f_style"); auto c_style = m.def_submodule("c_style"); init_tensor_module(f_style); init_tensor_module(c_style); } PYBIND11_NAMESPACE_END(eigen_tensor_test) aoflagger-v3.4.0/external/pybind11/tests/test_multiple_inheritance.cpp0000644000175000017500000003002114507760431024706 0ustar olesoles/* tests/test_multiple_inheritance.cpp -- multiple inheritance, implicit MI casts Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "constructor_stats.h" #include "pybind11_tests.h" namespace { // Many bases for testing that multiple inheritance from many classes (i.e. requiring extra // space for holder constructed flags) works. template struct BaseN { explicit BaseN(int i) : i(i) {} int i; }; // test_mi_static_properties struct Vanilla { std::string vanilla() { return "Vanilla"; }; }; struct WithStatic1 { static std::string static_func1() { return "WithStatic1"; }; static int static_value1; }; struct WithStatic2 { static std::string static_func2() { return "WithStatic2"; }; static int static_value2; }; struct VanillaStaticMix1 : Vanilla, WithStatic1, WithStatic2 { static std::string static_func() { return "VanillaStaticMix1"; } static int static_value; }; struct VanillaStaticMix2 : WithStatic1, Vanilla, WithStatic2 { static std::string static_func() { return "VanillaStaticMix2"; } static int static_value; }; int WithStatic1::static_value1 = 1; int WithStatic2::static_value2 = 2; int VanillaStaticMix1::static_value = 12; int VanillaStaticMix2::static_value = 12; // test_multiple_inheritance_virtbase struct Base1a { explicit Base1a(int i) : i(i) {} int foo() const { return i; } int i; }; struct Base2a { explicit Base2a(int i) : i(i) {} int bar() const { return i; } int i; }; struct Base12a : Base1a, Base2a { Base12a(int i, int j) : Base1a(i), Base2a(j) {} }; // test_mi_unaligned_base // test_mi_base_return struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; }; struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; }; struct I801C : I801B1, I801B2 {}; struct I801D : I801C {}; // Indirect MI } // namespace TEST_SUBMODULE(multiple_inheritance, m) { // Please do not interleave `struct` and `class` definitions with bindings code, // but implement `struct`s and `class`es in the anonymous namespace above. // This helps keeping the smart_holder branch in sync with master. // test_multiple_inheritance_mix1 // test_multiple_inheritance_mix2 struct Base1 { explicit Base1(int i) : i(i) {} int foo() const { return i; } int i; }; py::class_ b1(m, "Base1"); b1.def(py::init()).def("foo", &Base1::foo); struct Base2 { explicit Base2(int i) : i(i) {} int bar() const { return i; } int i; }; py::class_ b2(m, "Base2"); b2.def(py::init()).def("bar", &Base2::bar); // test_multiple_inheritance_cpp struct Base12 : Base1, Base2 { Base12(int i, int j) : Base1(i), Base2(j) {} }; struct MIType : Base12 { MIType(int i, int j) : Base12(i, j) {} }; py::class_(m, "Base12"); py::class_(m, "MIType").def(py::init()); // test_multiple_inheritance_python_many_bases #define PYBIND11_BASEN(N) \ py::class_>(m, "BaseN" #N).def(py::init()).def("f" #N, [](BaseN &b) { \ return b.i + (N); \ }) PYBIND11_BASEN(1); PYBIND11_BASEN(2); PYBIND11_BASEN(3); PYBIND11_BASEN(4); PYBIND11_BASEN(5); PYBIND11_BASEN(6); PYBIND11_BASEN(7); PYBIND11_BASEN(8); PYBIND11_BASEN(9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12); PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16); PYBIND11_BASEN(17); // Uncommenting this should result in a compile time failure (MI can only be specified via // template parameters because pybind has to know the types involved; see discussion in #742 // for details). // struct Base12v2 : Base1, Base2 { // Base12v2(int i, int j) : Base1(i), Base2(j) { } // }; // py::class_(m, "Base12v2", b1, b2) // .def(py::init()); // test_multiple_inheritance_virtbase // Test the case where not all base classes are specified, and where pybind11 requires the // py::multiple_inheritance flag to perform proper casting between types. py::class_>(m, "Base1a") .def(py::init()) .def("foo", &Base1a::foo); py::class_>(m, "Base2a") .def(py::init()) .def("bar", &Base2a::bar); py::class_>( m, "Base12a", py::multiple_inheritance()) .def(py::init()); m.def("bar_base2a", [](Base2a *b) { return b->bar(); }); m.def("bar_base2a_sharedptr", [](const std::shared_ptr &b) { return b->bar(); }); // test_mi_unaligned_base // test_mi_base_return // Issue #801: invalid casting to derived type with MI bases // Unregistered classes: struct I801B3 { int c = 3; virtual ~I801B3() = default; }; struct I801E : I801B3, I801D {}; py::class_>(m, "I801B1") .def(py::init<>()) .def_readonly("a", &I801B1::a); py::class_>(m, "I801B2") .def(py::init<>()) .def_readonly("b", &I801B2::b); py::class_>(m, "I801C").def(py::init<>()); py::class_>(m, "I801D").def(py::init<>()); // Two separate issues here: first, we want to recognize a pointer to a base type as being a // known instance even when the pointer value is unequal (i.e. due to a non-first // multiple-inheritance base class): m.def("i801b1_c", [](I801C *c) { return static_cast(c); }); m.def("i801b2_c", [](I801C *c) { return static_cast(c); }); m.def("i801b1_d", [](I801D *d) { return static_cast(d); }); m.def("i801b2_d", [](I801D *d) { return static_cast(d); }); // Second, when returned a base class pointer to a derived instance, we cannot assume that the // pointer is `reinterpret_cast`able to the derived pointer because, like above, the base class // pointer could be offset. m.def("i801c_b1", []() -> I801B1 * { return new I801C(); }); m.def("i801c_b2", []() -> I801B2 * { return new I801C(); }); m.def("i801d_b1", []() -> I801B1 * { return new I801D(); }); m.def("i801d_b2", []() -> I801B2 * { return new I801D(); }); // Return a base class pointer to a pybind-registered type when the actual derived type // isn't pybind-registered (and uses multiple-inheritance to offset the pybind base) m.def("i801e_c", []() -> I801C * { return new I801E(); }); m.def("i801e_b2", []() -> I801B2 * { return new I801E(); }); // test_mi_static_properties py::class_(m, "Vanilla").def(py::init<>()).def("vanilla", &Vanilla::vanilla); py::class_(m, "WithStatic1") .def(py::init<>()) .def_static("static_func1", &WithStatic1::static_func1) .def_readwrite_static("static_value1", &WithStatic1::static_value1); py::class_(m, "WithStatic2") .def(py::init<>()) .def_static("static_func2", &WithStatic2::static_func2) .def_readwrite_static("static_value2", &WithStatic2::static_value2); py::class_(m, "VanillaStaticMix1") .def(py::init<>()) .def_static("static_func", &VanillaStaticMix1::static_func) .def_readwrite_static("static_value", &VanillaStaticMix1::static_value); py::class_(m, "VanillaStaticMix2") .def(py::init<>()) .def_static("static_func", &VanillaStaticMix2::static_func) .def_readwrite_static("static_value", &VanillaStaticMix2::static_value); struct WithDict {}; struct VanillaDictMix1 : Vanilla, WithDict {}; struct VanillaDictMix2 : WithDict, Vanilla {}; py::class_(m, "WithDict", py::dynamic_attr()).def(py::init<>()); py::class_(m, "VanillaDictMix1").def(py::init<>()); py::class_(m, "VanillaDictMix2").def(py::init<>()); // test_diamond_inheritance // Issue #959: segfault when constructing diamond inheritance instance // All of these have int members so that there will be various unequal pointers involved. struct B { int b; B() = default; B(const B &) = default; virtual ~B() = default; }; struct C0 : public virtual B { int c0; }; struct C1 : public virtual B { int c1; }; struct D : public C0, public C1 { int d; }; py::class_(m, "B").def("b", [](B *self) { return self; }); py::class_(m, "C0").def("c0", [](C0 *self) { return self; }); py::class_(m, "C1").def("c1", [](C1 *self) { return self; }); py::class_(m, "D").def(py::init<>()); // test_pr3635_diamond_* // - functions are get_{base}_{var}, return {var} struct MVB { MVB() = default; MVB(const MVB &) = default; virtual ~MVB() = default; int b = 1; int get_b_b() const { return b; } }; struct MVC : virtual MVB { int c = 2; int get_c_b() const { return b; } int get_c_c() const { return c; } }; struct MVD0 : virtual MVC { int d0 = 3; int get_d0_b() const { return b; } int get_d0_c() const { return c; } int get_d0_d0() const { return d0; } }; struct MVD1 : virtual MVC { int d1 = 4; int get_d1_b() const { return b; } int get_d1_c() const { return c; } int get_d1_d1() const { return d1; } }; struct MVE : virtual MVD0, virtual MVD1 { int e = 5; int get_e_b() const { return b; } int get_e_c() const { return c; } int get_e_d0() const { return d0; } int get_e_d1() const { return d1; } int get_e_e() const { return e; } }; struct MVF : virtual MVE { int f = 6; int get_f_b() const { return b; } int get_f_c() const { return c; } int get_f_d0() const { return d0; } int get_f_d1() const { return d1; } int get_f_e() const { return e; } int get_f_f() const { return f; } }; py::class_(m, "MVB") .def(py::init<>()) .def("get_b_b", &MVB::get_b_b) .def_readwrite("b", &MVB::b); py::class_(m, "MVC") .def(py::init<>()) .def("get_c_b", &MVC::get_c_b) .def("get_c_c", &MVC::get_c_c) .def_readwrite("c", &MVC::c); py::class_(m, "MVD0") .def(py::init<>()) .def("get_d0_b", &MVD0::get_d0_b) .def("get_d0_c", &MVD0::get_d0_c) .def("get_d0_d0", &MVD0::get_d0_d0) .def_readwrite("d0", &MVD0::d0); py::class_(m, "MVD1") .def(py::init<>()) .def("get_d1_b", &MVD1::get_d1_b) .def("get_d1_c", &MVD1::get_d1_c) .def("get_d1_d1", &MVD1::get_d1_d1) .def_readwrite("d1", &MVD1::d1); py::class_(m, "MVE") .def(py::init<>()) .def("get_e_b", &MVE::get_e_b) .def("get_e_c", &MVE::get_e_c) .def("get_e_d0", &MVE::get_e_d0) .def("get_e_d1", &MVE::get_e_d1) .def("get_e_e", &MVE::get_e_e) .def_readwrite("e", &MVE::e); py::class_(m, "MVF") .def(py::init<>()) .def("get_f_b", &MVF::get_f_b) .def("get_f_c", &MVF::get_f_c) .def("get_f_d0", &MVF::get_f_d0) .def("get_f_d1", &MVF::get_f_d1) .def("get_f_e", &MVF::get_f_e) .def("get_f_f", &MVF::get_f_f) .def_readwrite("f", &MVF::f); } aoflagger-v3.4.0/external/pybind11/tests/test_exceptions.h0000644000175000017500000000061714507760431022340 0ustar olesoles#pragma once #include "pybind11_tests.h" #include // shared exceptions for cross_module_tests class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exception { public: using builtin_exception::builtin_exception; explicit shared_exception() : shared_exception("") {} void set_error() const override { PyErr_SetString(PyExc_RuntimeError, what()); } }; aoflagger-v3.4.0/external/pybind11/tests/test_custom_type_casters.cpp0000644000175000017500000001616014507760431024611 0ustar olesoles/* tests/test_custom_type_casters.cpp -- tests type_caster Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "constructor_stats.h" #include "pybind11_tests.h" // py::arg/py::arg_v testing: these arguments just record their argument when invoked class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; }; class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; }; class ArgAlwaysConverts {}; namespace PYBIND11_NAMESPACE { namespace detail { template <> struct type_caster { public: // Classic #ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1")); #else PYBIND11_TYPE_CASTER(ArgInspector1, const_name("ArgInspector1")); #endif bool load(handle src, bool convert) { value.arg = "loading ArgInspector1 argument " + std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " "Argument value = " + (std::string) str(src); return true; } static handle cast(const ArgInspector1 &src, return_value_policy, handle) { return str(src.arg).release(); } }; template <> struct type_caster { public: PYBIND11_TYPE_CASTER(ArgInspector2, const_name("ArgInspector2")); bool load(handle src, bool convert) { value.arg = "loading ArgInspector2 argument " + std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " "Argument value = " + (std::string) str(src); return true; } static handle cast(const ArgInspector2 &src, return_value_policy, handle) { return str(src.arg).release(); } }; template <> struct type_caster { public: PYBIND11_TYPE_CASTER(ArgAlwaysConverts, const_name("ArgAlwaysConverts")); bool load(handle, bool convert) { return convert; } static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) { return py::none().release(); } }; } // namespace detail } // namespace PYBIND11_NAMESPACE // test_custom_caster_destruction class DestructionTester { public: DestructionTester() { print_default_created(this); } ~DestructionTester() { print_destroyed(this); } DestructionTester(const DestructionTester &) { print_copy_created(this); } DestructionTester(DestructionTester &&) noexcept { print_move_created(this); } DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } DestructionTester &operator=(DestructionTester &&) noexcept { print_move_assigned(this); return *this; } }; namespace PYBIND11_NAMESPACE { namespace detail { template <> struct type_caster { PYBIND11_TYPE_CASTER(DestructionTester, const_name("DestructionTester")); bool load(handle, bool) { return true; } static handle cast(const DestructionTester &, return_value_policy, handle) { return py::bool_(true).release(); } }; } // namespace detail } // namespace PYBIND11_NAMESPACE // Define type caster outside of `pybind11::detail` and then alias it. namespace other_lib { struct MyType {}; // Corrupt `py` shorthand alias for surrounding context. namespace py {} // Corrupt unqualified relative `pybind11` namespace. namespace PYBIND11_NAMESPACE {} // Correct alias. namespace py_ = ::pybind11; // Define caster. This is effectively no-op, we only ensure it compiles and we // don't have any symbol collision when using macro mixin. struct my_caster { PYBIND11_TYPE_CASTER(MyType, py_::detail::const_name("MyType")); bool load(py_::handle, bool) { return true; } static py_::handle cast(const MyType &, py_::return_value_policy, py_::handle) { return py_::bool_(true).release(); } }; } // namespace other_lib // Effectively "alias" it into correct namespace (via inheritance). namespace PYBIND11_NAMESPACE { namespace detail { template <> struct type_caster : public other_lib::my_caster {}; } // namespace detail } // namespace PYBIND11_NAMESPACE TEST_SUBMODULE(custom_type_casters, m) { // test_custom_type_casters // test_noconvert_args // // Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass // fail so that our call always ends up happening via the second dispatch (the one that allows // some conversion). class ArgInspector { public: ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; } std::string g(const ArgInspector1 &a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) { return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg; } static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } }; // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. py::class_(m, "ArgInspector") .def(py::init<>()) .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts()) .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert() = 13, "d"_a = ArgInspector2(), py::arg() = ArgAlwaysConverts()) .def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts()); m.def( "arg_inspect_func", [](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; }, py::arg{}.noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts()); m.def( "floats_preferred", [](double f) { return 0.5 * f; }, "f"_a); m.def( "floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert()); m.def( "ints_preferred", [](int i) { return i / 2; }, "i"_a); m.def( "ints_only", [](int i) { return i / 2; }, "i"_a.noconvert()); // test_custom_caster_destruction // Test that `take_ownership` works on types with a custom type caster when given a pointer // default policy: don't take ownership: m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; }); m.def( "custom_caster_destroy", []() { return new DestructionTester(); }, py::return_value_policy::take_ownership); // Takes ownership: destroy when finished m.def( "custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) m.def("destruction_tester_cstats", &ConstructorStats::get, py::return_value_policy::reference); m.def("other_lib_type", [](other_lib::MyType x) { return x; }); } aoflagger-v3.4.0/external/pybind11/tests/test_constants_and_functions.cpp0000644000175000017500000001275714507760431025450 0ustar olesoles/* tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "pybind11_tests.h" enum MyEnum { EFirstEntry = 1, ESecondEntry }; std::string test_function1() { return "test_function()"; } std::string test_function2(MyEnum k) { return "test_function(enum=" + std::to_string(k) + ")"; } std::string test_function3(int i) { return "test_function(" + std::to_string(i) + ")"; } py::str test_function4() { return "test_function()"; } py::str test_function4(char *) { return "test_function(char *)"; } py::str test_function4(int, float) { return "test_function(int, float)"; } py::str test_function4(float, int) { return "test_function(float, int)"; } py::bytes return_bytes() { const char *data = "\x01\x00\x02\x00"; return std::string(data, 4); } std::string print_bytes(const py::bytes &bytes) { std::string ret = "bytes["; const auto value = static_cast(bytes); for (char c : value) { ret += std::to_string(static_cast(c)) + ' '; } ret.back() = ']'; return ret; } // Test that we properly handle C++17 exception specifiers (which are part of the function // signature in C++17). These should all still work before C++17, but don't affect the function // signature. namespace test_exc_sp { // [workaround(intel)] Unable to use noexcept instead of noexcept(true) // Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as // it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827). #if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17) int f1(int x) noexcept(true) { return x + 1; } #else int f1(int x) noexcept { return x + 1; } #endif int f2(int x) noexcept(true) { return x + 2; } int f3(int x) noexcept(false) { return x + 3; } PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated") PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated") // NOLINTNEXTLINE(modernize-use-noexcept) int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true) PYBIND11_WARNING_POP struct C { int m1(int x) noexcept { return x - 1; } int m2(int x) const noexcept { return x - 2; } int m3(int x) noexcept(true) { return x - 3; } int m4(int x) const noexcept(true) { return x - 4; } int m5(int x) noexcept(false) { return x - 5; } int m6(int x) const noexcept(false) { return x - 6; } PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated") PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated") // NOLINTNEXTLINE(modernize-use-noexcept) int m7(int x) throw() { return x - 7; } // NOLINTNEXTLINE(modernize-use-noexcept) int m8(int x) const throw() { return x - 8; } PYBIND11_WARNING_POP }; } // namespace test_exc_sp TEST_SUBMODULE(constants_and_functions, m) { // test_constants m.attr("some_constant") = py::int_(14); // test_function_overloading m.def("test_function", &test_function1); m.def("test_function", &test_function2); m.def("test_function", &test_function3); #if defined(PYBIND11_OVERLOAD_CAST) m.def("test_function", py::overload_cast<>(&test_function4)); m.def("test_function", py::overload_cast(&test_function4)); m.def("test_function", py::overload_cast(&test_function4)); m.def("test_function", py::overload_cast(&test_function4)); #else m.def("test_function", static_cast(&test_function4)); m.def("test_function", static_cast(&test_function4)); m.def("test_function", static_cast(&test_function4)); m.def("test_function", static_cast(&test_function4)); #endif py::enum_(m, "MyEnum") .value("EFirstEntry", EFirstEntry) .value("ESecondEntry", ESecondEntry) .export_values(); // test_bytes m.def("return_bytes", &return_bytes); m.def("print_bytes", &print_bytes); // test_exception_specifiers using namespace test_exc_sp; py::class_(m, "C") .def(py::init<>()) .def("m1", &C::m1) .def("m2", &C::m2) .def("m3", &C::m3) .def("m4", &C::m4) .def("m5", &C::m5) .def("m6", &C::m6) .def("m7", &C::m7) .def("m8", &C::m8); m.def("f1", f1); m.def("f2", f2); PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_INTEL(878) // incompatible exception specifications m.def("f3", f3); PYBIND11_WARNING_POP m.def("f4", f4); // test_function_record_leaks m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) { // This should always be enough to trigger the alternative branch // where `sizeof(capture) > sizeof(rec->data)` uint64_t capture[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; #if defined(__GNUC__) && __GNUC__ == 4 // CentOS7 py::detail::silence_unused_warnings(capture); #endif m.def( "should_raise", [capture](int) { return capture[9] + 33; }, py::kw_only(), py::arg()); }); m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) { m.def( "should_raise", [](int, int, const py::object &) { return 42; }, "some docstring", py::arg_v("x", 42), py::arg_v("y", 42, ""), py::arg_v("z", default_value)); }); } aoflagger-v3.4.0/external/pybind11/tests/valgrind-numpy-scipy.supp0000644000175000017500000000623214507760431023760 0ustar olesoles# Valgrind suppression file for NumPy & SciPy errors and leaks in pybind11 tests # # On updating a dependency, to get a list of "default" leaks in e.g. NumPy, run # `PYTHONMALLOC=malloc valgrind --leak-check=full --show-leak-kinds=definite,indirect python3.9-dbg -c "import numpy"` # To use these suppression files, add e.g. `--suppressions=valgrind-numpy-scipy.supp` { Leaks when importing NumPy Memcheck:Leak fun:malloc fun:_PyMem_RawMalloc fun:PyObject_Malloc fun:_PyObject_GC_Alloc fun:_PyObject_GC_Malloc fun:_PyObject_GC_NewVar fun:tuple_alloc fun:PyTuple_Pack ... fun:__pyx_pymod_exec_* } { Leaks when importing NumPy (bis) Memcheck:Leak fun:malloc fun:_PyMem_RawMalloc fun:PyObject_Malloc fun:_PyObject_New fun:PyCode_NewWithPosOnlyArgs fun:PyCode_New ... fun:__pyx_pymod_exec_* } { Leaks when importing NumPy (ter) Memcheck:Leak fun:malloc fun:_PyMem_RawMalloc fun:PyObject_Malloc fun:_PyObject_GC_Alloc fun:_PyObject_GC_Malloc fun:_PyObject_GC_NewVar fun:tuple_alloc fun:_PyTuple_FromArray fun:_PyObject_MakeTpCall fun:_PyObject_VectorcallTstate fun:PyObject_Vectorcall fun:call_function fun:_PyEval_EvalFrameDefault fun:_PyEval_EvalFrame fun:function_code_fastcall fun:_PyFunction_Vectorcall } { Leaks when importing NumPy (quater) Memcheck:Leak fun:malloc fun:_PyMem_RawMalloc fun:PyObject_Malloc fun:_PyObject_GC_Alloc fun:_PyObject_GC_Malloc fun:_PyObject_GC_NewVar fun:tuple_alloc fun:_PyTuple_FromArray fun:_PyObject_MakeTpCall fun:_PyObject_VectorcallTstate fun:_PyObject_CallFunctionVa fun:PyObject_CallFunction fun:PyImport_Import } { Leaks when importing NumPy (quinquies) Memcheck:Leak fun:malloc fun:_PyMem_RawMalloc fun:PyObject_Malloc fun:_PyObject_GC_Alloc fun:_PyObject_GC_Malloc fun:_PyObject_GC_NewVar fun:tuple_alloc fun:PyTuple_New fun:r_object fun:r_object fun:r_object fun:r_object } { Leaks when importing NumPy (sexies) Memcheck:Leak fun:malloc fun:_PyMem_RawMalloc fun:PyObject_Malloc fun:_PyObject_GC_Alloc fun:_PyObject_GC_Malloc fun:_PyObject_GC_NewVar fun:tuple_alloc fun:PyTuple_New fun:dictiter_iternextitem fun:list_extend fun:_PyList_Extend fun:PySequence_List } { Leak when importing scipy.fft Memcheck:Leak fun:_Znwm fun:PyInit_pypocketfft fun:_PyImport_LoadDynamicModuleWithSpec fun:_imp_create_dynamic_impl* fun:_imp_create_dynamic fun:cfunction_vectorcall_FASTCALL fun:PyVectorcall_Call fun:_PyObject_Call fun:PyObject_Call fun:do_call_core fun:_PyEval_EvalFrameDefault fun:_PyEval_EvalFrame fun:_PyEval_EvalCode } { NumPy leaks when spawning a subprocess Memcheck:Leak fun:malloc ... fun:_buffer_get_info fun:array_getbuffer fun:PyObject_GetBuffer fun:__Pyx__GetBufferAndValidate* fun:__pyx_f_5numpy_6random_13bit_generator_12SeedSequence_mix_entropy fun:__pyx_pw_5numpy_6random_13bit_generator_12SeedSequence_1__init__ fun:type_call fun:__Pyx__PyObject_CallOneArg fun:__pyx_pw_5numpy_6random_13bit_generator_12BitGenerator_1__init__ } aoflagger-v3.4.0/external/pybind11/tests/test_opaque_types.py0000644000175000017500000000346714507760431023104 0ustar olesolesimport pytest from pybind11_tests import ConstructorStats, UserType from pybind11_tests import opaque_types as m def test_string_list(): lst = m.StringList() lst.push_back("Element 1") lst.push_back("Element 2") assert m.print_opaque_list(lst) == "Opaque list: [Element 1, Element 2]" assert lst.back() == "Element 2" for i, k in enumerate(lst, start=1): assert k == f"Element {i}" lst.pop_back() assert m.print_opaque_list(lst) == "Opaque list: [Element 1]" cvp = m.ClassWithSTLVecProperty() assert m.print_opaque_list(cvp.stringList) == "Opaque list: []" cvp.stringList = lst cvp.stringList.push_back("Element 3") assert m.print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]" def test_pointers(msg): living_before = ConstructorStats.get(UserType).alive() assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234 assert m.get_void_ptr_value(UserType()) # Should also work for other C++ types assert ConstructorStats.get(UserType).alive() == living_before with pytest.raises(TypeError) as excinfo: m.get_void_ptr_value([1, 2, 3]) # This should not work assert ( msg(excinfo.value) == """ get_void_ptr_value(): incompatible function arguments. The following argument types are supported: 1. (arg0: capsule) -> int Invoked with: [1, 2, 3] """ ) assert m.return_null_str() is None assert m.get_null_str_value(m.return_null_str()) is not None ptr = m.return_unique_ptr() assert "StringList" in repr(ptr) assert m.print_opaque_list(ptr) == "Opaque list: [some value]" def test_unions(): int_float_union = m.IntFloat() int_float_union.i = 42 assert int_float_union.i == 42 int_float_union.f = 3.0 assert int_float_union.f == 3.0 aoflagger-v3.4.0/external/pybind11/tests/test_call_policies.py0000644000175000017500000001462514507760431023166 0ustar olesolesimport pytest import env # noqa: F401 from pybind11_tests import ConstructorStats from pybind11_tests import call_policies as m @pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False) def test_keep_alive_argument(capture): n_inst = ConstructorStats.detail_reg_inst() with capture: p = m.Parent() assert capture == "Allocating parent." with capture: p.addChild(m.Child()) assert ConstructorStats.detail_reg_inst() == n_inst + 1 assert ( capture == """ Allocating child. Releasing child. """ ) with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert capture == "Releasing parent." with capture: p = m.Parent() assert capture == "Allocating parent." with capture: p.addChildKeepAlive(m.Child()) assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert capture == "Allocating child." with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert ( capture == """ Releasing parent. Releasing child. """ ) p = m.Parent() c = m.Child() assert ConstructorStats.detail_reg_inst() == n_inst + 2 m.free_function(p, c) del c assert ConstructorStats.detail_reg_inst() == n_inst + 2 del p assert ConstructorStats.detail_reg_inst() == n_inst with pytest.raises(RuntimeError) as excinfo: m.invalid_arg_index() assert str(excinfo.value) == "Could not activate keep_alive!" def test_keep_alive_return_value(capture): n_inst = ConstructorStats.detail_reg_inst() with capture: p = m.Parent() assert capture == "Allocating parent." with capture: p.returnChild() assert ConstructorStats.detail_reg_inst() == n_inst + 1 assert ( capture == """ Allocating child. Releasing child. """ ) with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert capture == "Releasing parent." with capture: p = m.Parent() assert capture == "Allocating parent." with capture: p.returnChildKeepAlive() assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert capture == "Allocating child." with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert ( capture == """ Releasing parent. Releasing child. """ ) p = m.Parent() assert ConstructorStats.detail_reg_inst() == n_inst + 1 with capture: m.Parent.staticFunction(p) assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert capture == "Allocating child." with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert ( capture == """ Releasing parent. Releasing child. """ ) # https://foss.heptapod.net/pypy/pypy/-/issues/2447 @pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented") def test_alive_gc(capture): n_inst = ConstructorStats.detail_reg_inst() p = m.ParentGC() p.addChildKeepAlive(m.Child()) assert ConstructorStats.detail_reg_inst() == n_inst + 2 lst = [p] lst.append(lst) # creates a circular reference with capture: del p, lst assert ConstructorStats.detail_reg_inst() == n_inst assert ( capture == """ Releasing parent. Releasing child. """ ) def test_alive_gc_derived(capture): class Derived(m.Parent): pass n_inst = ConstructorStats.detail_reg_inst() p = Derived() p.addChildKeepAlive(m.Child()) assert ConstructorStats.detail_reg_inst() == n_inst + 2 lst = [p] lst.append(lst) # creates a circular reference with capture: del p, lst assert ConstructorStats.detail_reg_inst() == n_inst assert ( capture == """ Releasing parent. Releasing child. """ ) def test_alive_gc_multi_derived(capture): class Derived(m.Parent, m.Child): def __init__(self): m.Parent.__init__(self) m.Child.__init__(self) n_inst = ConstructorStats.detail_reg_inst() p = Derived() p.addChildKeepAlive(m.Child()) # +3 rather than +2 because Derived corresponds to two registered instances assert ConstructorStats.detail_reg_inst() == n_inst + 3 lst = [p] lst.append(lst) # creates a circular reference with capture: del p, lst assert ConstructorStats.detail_reg_inst() == n_inst assert ( capture == """ Releasing parent. Releasing child. Releasing child. """ ) def test_return_none(capture): n_inst = ConstructorStats.detail_reg_inst() with capture: p = m.Parent() assert capture == "Allocating parent." with capture: p.returnNullChildKeepAliveChild() assert ConstructorStats.detail_reg_inst() == n_inst + 1 assert capture == "" with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert capture == "Releasing parent." with capture: p = m.Parent() assert capture == "Allocating parent." with capture: p.returnNullChildKeepAliveParent() assert ConstructorStats.detail_reg_inst() == n_inst + 1 assert capture == "" with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert capture == "Releasing parent." def test_keep_alive_constructor(capture): n_inst = ConstructorStats.detail_reg_inst() with capture: p = m.Parent(m.Child()) assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert ( capture == """ Allocating child. Allocating parent. """ ) with capture: del p assert ConstructorStats.detail_reg_inst() == n_inst assert ( capture == """ Releasing parent. Releasing child. """ ) def test_call_guard(): assert m.unguarded_call() == "unguarded" assert m.guarded_call() == "guarded" assert m.multiple_guards_correct_order() == "guarded & guarded" assert m.multiple_guards_wrong_order() == "unguarded & guarded" if hasattr(m, "with_gil"): assert m.with_gil() == "GIL held" assert m.without_gil() == "GIL released" aoflagger-v3.4.0/external/pybind11/tests/test_docstring_options.py0000644000175000017500000000456714507760431024137 0ustar olesolesfrom pybind11_tests import docstring_options as m def test_docstring_options(): # options.disable_function_signatures() assert not m.test_function1.__doc__ assert m.test_function2.__doc__ == "A custom docstring" # docstring specified on just the first overload definition: assert m.test_overloaded1.__doc__ == "Overload docstring" # docstring on both overloads: assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2" # docstring on only second overload: assert m.test_overloaded3.__doc__ == "Overload docstr" # options.enable_function_signatures() assert m.test_function3.__doc__.startswith("test_function3(a: int, b: int) -> None") assert m.test_function4.__doc__.startswith("test_function4(a: int, b: int) -> None") assert m.test_function4.__doc__.endswith("A custom docstring\n") # options.disable_function_signatures() # options.disable_user_defined_docstrings() assert not m.test_function5.__doc__ # nested options.enable_user_defined_docstrings() assert m.test_function6.__doc__ == "A custom docstring" # RAII destructor assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None") assert m.test_function7.__doc__.endswith("A custom docstring\n") # when all options are disabled, no docstring (instead of an empty one) should be generated assert m.test_function8.__doc__ is None # Suppression of user-defined docstrings for non-function objects assert not m.DocstringTestFoo.__doc__ assert not m.DocstringTestFoo.value_prop.__doc__ # Check existig behaviour of enum docstings assert ( m.DocstringTestEnum1.__doc__ == "Enum docstring\n\nMembers:\n\n Member1\n\n Member2" ) # options.enable_enum_members_docstring() assert ( m.DocstringTestEnum2.__doc__ == "Enum docstring\n\nMembers:\n\n Member1\n\n Member2" ) # options.disable_enum_members_docstring() assert m.DocstringTestEnum3.__doc__ == "Enum docstring" # options.disable_user_defined_docstrings() assert m.DocstringTestEnum4.__doc__ == "Members:\n\n Member1\n\n Member2" # options.disable_user_defined_docstrings() # options.disable_enum_members_docstring() # When all options are disabled, no docstring (instead of an empty one) should be generated assert m.DocstringTestEnum5.__doc__ is None aoflagger-v3.4.0/external/pybind11/tests/test_numpy_array.cpp0000644000175000017500000004662514507760431023071 0ustar olesoles/* tests/test_numpy_array.cpp -- test core array functionality Copyright (c) 2016 Ivan Smirnov All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include "pybind11_tests.h" #include #include // Size / dtype checks. struct DtypeCheck { py::dtype numpy{}; py::dtype pybind11{}; }; template DtypeCheck get_dtype_check(const char *name) { py::module_ np = py::module_::import("numpy"); DtypeCheck check{}; check.numpy = np.attr("dtype")(np.attr(name)); check.pybind11 = py::dtype::of(); return check; } std::vector get_concrete_dtype_checks() { return {// Normalization get_dtype_check("int8"), get_dtype_check("uint8"), get_dtype_check("int16"), get_dtype_check("uint16"), get_dtype_check("int32"), get_dtype_check("uint32"), get_dtype_check("int64"), get_dtype_check("uint64")}; } struct DtypeSizeCheck { std::string name{}; int size_cpp{}; int size_numpy{}; // For debugging. py::dtype dtype{}; }; template DtypeSizeCheck get_dtype_size_check() { DtypeSizeCheck check{}; check.name = py::type_id(); check.size_cpp = sizeof(T); check.dtype = py::dtype::of(); check.size_numpy = check.dtype.attr("itemsize").template cast(); return check; } std::vector get_platform_dtype_size_checks() { return { get_dtype_size_check(), get_dtype_size_check(), get_dtype_size_check(), get_dtype_size_check(), get_dtype_size_check(), get_dtype_size_check(), get_dtype_size_check(), get_dtype_size_check(), }; } // Arrays. using arr = py::array; using arr_t = py::array_t; static_assert(std::is_same::value, ""); template arr data(const arr &a, Ix... index) { return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...)); } template arr data_t(const arr_t &a, Ix... index) { return arr(a.size() - a.index_at(index...), a.data(index...)); } template arr &mutate_data(arr &a, Ix... index) { auto *ptr = (uint8_t *) a.mutable_data(index...); for (py::ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) { ptr[i] = (uint8_t) (ptr[i] * 2); } return a; } template arr_t &mutate_data_t(arr_t &a, Ix... index) { auto ptr = a.mutable_data(index...); for (py::ssize_t i = 0; i < a.size() - a.index_at(index...); i++) { ptr[i]++; } return a; } template py::ssize_t index_at(const arr &a, Ix... idx) { return a.index_at(idx...); } template py::ssize_t index_at_t(const arr_t &a, Ix... idx) { return a.index_at(idx...); } template py::ssize_t offset_at(const arr &a, Ix... idx) { return a.offset_at(idx...); } template py::ssize_t offset_at_t(const arr_t &a, Ix... idx) { return a.offset_at(idx...); } template py::ssize_t at_t(const arr_t &a, Ix... idx) { return a.at(idx...); } template arr_t &mutate_at_t(arr_t &a, Ix... idx) { a.mutable_at(idx...)++; return a; } #define def_index_fn(name, type) \ sm.def(#name, [](type a) { return name(a); }); \ sm.def(#name, [](type a, int i) { return name(a, i); }); \ sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \ sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); }); template py::handle auxiliaries(T &&r, T2 &&r2) { if (r.ndim() != 2) { throw std::domain_error("error: ndim != 2"); } py::list l; l.append(*r.data(0, 0)); l.append(*r2.mutable_data(0, 0)); l.append(r.data(0, 1) == r2.mutable_data(0, 1)); l.append(r.ndim()); l.append(r.itemsize()); l.append(r.shape(0)); l.append(r.shape(1)); l.append(r.size()); l.append(r.nbytes()); return l.release(); } // note: declaration at local scope would create a dangling reference! static int data_i = 42; TEST_SUBMODULE(numpy_array, sm) { try { py::module_::import("numpy"); } catch (const py::error_already_set &) { return; } // test_dtypes py::class_(sm, "DtypeCheck") .def_readonly("numpy", &DtypeCheck::numpy) .def_readonly("pybind11", &DtypeCheck::pybind11) .def("__repr__", [](const DtypeCheck &self) { return py::str("").format(self.numpy, self.pybind11); }); sm.def("get_concrete_dtype_checks", &get_concrete_dtype_checks); py::class_(sm, "DtypeSizeCheck") .def_readonly("name", &DtypeSizeCheck::name) .def_readonly("size_cpp", &DtypeSizeCheck::size_cpp) .def_readonly("size_numpy", &DtypeSizeCheck::size_numpy) .def("__repr__", [](const DtypeSizeCheck &self) { return py::str("") .format(self.name, self.size_cpp, self.size_numpy, self.dtype); }); sm.def("get_platform_dtype_size_checks", &get_platform_dtype_size_checks); // test_array_attributes sm.def("ndim", [](const arr &a) { return a.ndim(); }); sm.def("shape", [](const arr &a) { return arr(a.ndim(), a.shape()); }); sm.def("shape", [](const arr &a, py::ssize_t dim) { return a.shape(dim); }); sm.def("strides", [](const arr &a) { return arr(a.ndim(), a.strides()); }); sm.def("strides", [](const arr &a, py::ssize_t dim) { return a.strides(dim); }); sm.def("writeable", [](const arr &a) { return a.writeable(); }); sm.def("size", [](const arr &a) { return a.size(); }); sm.def("itemsize", [](const arr &a) { return a.itemsize(); }); sm.def("nbytes", [](const arr &a) { return a.nbytes(); }); sm.def("owndata", [](const arr &a) { return a.owndata(); }); // test_index_offset def_index_fn(index_at, const arr &); def_index_fn(index_at_t, const arr_t &); def_index_fn(offset_at, const arr &); def_index_fn(offset_at_t, const arr_t &); // test_data def_index_fn(data, const arr &); def_index_fn(data_t, const arr_t &); // test_mutate_data, test_mutate_readonly def_index_fn(mutate_data, arr &); def_index_fn(mutate_data_t, arr_t &); def_index_fn(at_t, const arr_t &); def_index_fn(mutate_at_t, arr_t &); // test_make_c_f_array sm.def("make_f_array", [] { return py::array_t({2, 2}, {4, 8}); }); sm.def("make_c_array", [] { return py::array_t({2, 2}, {8, 4}); }); // test_empty_shaped_array sm.def("make_empty_shaped_array", [] { return py::array(py::dtype("f"), {}, {}); }); // test numpy scalars (empty shape, ndim==0) sm.def("scalar_int", []() { return py::array(py::dtype("i"), {}, {}, &data_i); }); // test_wrap sm.def("wrap", [](const py::array &a) { return py::array(a.dtype(), {a.shape(), a.shape() + a.ndim()}, {a.strides(), a.strides() + a.ndim()}, a.data(), a); }); // test_numpy_view struct ArrayClass { int data[2] = {1, 2}; ArrayClass() { py::print("ArrayClass()"); } ~ArrayClass() { py::print("~ArrayClass()"); } }; py::class_(sm, "ArrayClass") .def(py::init<>()) .def("numpy_view", [](py::object &obj) { py::print("ArrayClass::numpy_view()"); auto &a = obj.cast(); return py::array_t({2}, {4}, a.data, obj); }); // test_cast_numpy_int64_to_uint64 sm.def("function_taking_uint64", [](uint64_t) {}); // test_isinstance sm.def("isinstance_untyped", [](py::object yes, py::object no) { return py::isinstance(std::move(yes)) && !py::isinstance(std::move(no)); }); sm.def("isinstance_typed", [](const py::object &o) { return py::isinstance>(o) && !py::isinstance>(o); }); // test_constructors sm.def("default_constructors", []() { return py::dict("array"_a = py::array(), "array_t"_a = py::array_t(), "array_t"_a = py::array_t()); }); sm.def("converting_constructors", [](const py::object &o) { return py::dict("array"_a = py::array(o), "array_t"_a = py::array_t(o), "array_t"_a = py::array_t(o)); }); // test_overload_resolution sm.def("overloaded", [](const py::array_t &) { return "double"; }); sm.def("overloaded", [](const py::array_t &) { return "float"; }); sm.def("overloaded", [](const py::array_t &) { return "int"; }); sm.def("overloaded", [](const py::array_t &) { return "unsigned short"; }); sm.def("overloaded", [](const py::array_t &) { return "long long"; }); sm.def("overloaded", [](const py::array_t> &) { return "double complex"; }); sm.def("overloaded", [](const py::array_t> &) { return "float complex"; }); sm.def("overloaded2", [](const py::array_t> &) { return "double complex"; }); sm.def("overloaded2", [](const py::array_t &) { return "double"; }); sm.def("overloaded2", [](const py::array_t> &) { return "float complex"; }); sm.def("overloaded2", [](const py::array_t &) { return "float"; }); // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // Only accept the exact types: sm.def( "overloaded3", [](const py::array_t &) { return "int"; }, py::arg{}.noconvert()); sm.def( "overloaded3", [](const py::array_t &) { return "double"; }, py::arg{}.noconvert()); // Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but // rather that float gets converted via the safe (conversion to double) overload: sm.def("overloaded4", [](const py::array_t &) { return "long long"; }); sm.def("overloaded4", [](const py::array_t &) { return "double"; }); // But we do allow conversion to int if forcecast is enabled (but only if no overload matches // without conversion) sm.def("overloaded5", [](const py::array_t &) { return "unsigned int"; }); sm.def("overloaded5", [](const py::array_t &) { return "double"; }); // test_greedy_string_overload // Issue 685: ndarray shouldn't go to std::string overload sm.def("issue685", [](const std::string &) { return "string"; }); sm.def("issue685", [](const py::array &) { return "array"; }); sm.def("issue685", [](const py::object &) { return "other"; }); // test_array_unchecked_fixed_dims sm.def( "proxy_add2", [](py::array_t a, double v) { auto r = a.mutable_unchecked<2>(); for (py::ssize_t i = 0; i < r.shape(0); i++) { for (py::ssize_t j = 0; j < r.shape(1); j++) { r(i, j) += v; } } }, py::arg{}.noconvert(), py::arg()); sm.def("proxy_init3", [](double start) { py::array_t a({3, 3, 3}); auto r = a.mutable_unchecked<3>(); for (py::ssize_t i = 0; i < r.shape(0); i++) { for (py::ssize_t j = 0; j < r.shape(1); j++) { for (py::ssize_t k = 0; k < r.shape(2); k++) { r(i, j, k) = start++; } } } return a; }); sm.def("proxy_init3F", [](double start) { py::array_t a({3, 3, 3}); auto r = a.mutable_unchecked<3>(); for (py::ssize_t k = 0; k < r.shape(2); k++) { for (py::ssize_t j = 0; j < r.shape(1); j++) { for (py::ssize_t i = 0; i < r.shape(0); i++) { r(i, j, k) = start++; } } } return a; }); sm.def("proxy_squared_L2_norm", [](const py::array_t &a) { auto r = a.unchecked<1>(); double sumsq = 0; for (py::ssize_t i = 0; i < r.shape(0); i++) { sumsq += r[i] * r(i); // Either notation works for a 1D array } return sumsq; }); sm.def("proxy_auxiliaries2", [](py::array_t a) { auto r = a.unchecked<2>(); auto r2 = a.mutable_unchecked<2>(); return auxiliaries(r, r2); }); sm.def("proxy_auxiliaries1_const_ref", [](py::array_t a) { const auto &r = a.unchecked<1>(); const auto &r2 = a.mutable_unchecked<1>(); return r(0) == r2(0) && r[0] == r2[0]; }); sm.def("proxy_auxiliaries2_const_ref", [](py::array_t a) { const auto &r = a.unchecked<2>(); const auto &r2 = a.mutable_unchecked<2>(); return r(0, 0) == r2(0, 0); }); // test_array_unchecked_dyn_dims // Same as the above, but without a compile-time dimensions specification: sm.def( "proxy_add2_dyn", [](py::array_t a, double v) { auto r = a.mutable_unchecked(); if (r.ndim() != 2) { throw std::domain_error("error: ndim != 2"); } for (py::ssize_t i = 0; i < r.shape(0); i++) { for (py::ssize_t j = 0; j < r.shape(1); j++) { r(i, j) += v; } } }, py::arg{}.noconvert(), py::arg()); sm.def("proxy_init3_dyn", [](double start) { py::array_t a({3, 3, 3}); auto r = a.mutable_unchecked(); if (r.ndim() != 3) { throw std::domain_error("error: ndim != 3"); } for (py::ssize_t i = 0; i < r.shape(0); i++) { for (py::ssize_t j = 0; j < r.shape(1); j++) { for (py::ssize_t k = 0; k < r.shape(2); k++) { r(i, j, k) = start++; } } } return a; }); sm.def("proxy_auxiliaries2_dyn", [](py::array_t a) { return auxiliaries(a.unchecked(), a.mutable_unchecked()); }); sm.def("array_auxiliaries2", [](py::array_t a) { return auxiliaries(a, a); }); // test_array_failures // Issue #785: Uninformative "Unknown internal error" exception when constructing array from // empty object: sm.def("array_fail_test", []() { return py::array(py::object()); }); sm.def("array_t_fail_test", []() { return py::array_t(py::object()); }); // Make sure the error from numpy is being passed through: sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); }); // test_initializer_list // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous sm.def("array_initializer_list1", []() { return py::array_t(1); }); // { 1 } also works for the above, but clang warns about it sm.def("array_initializer_list2", []() { return py::array_t({1, 2}); }); sm.def("array_initializer_list3", []() { return py::array_t({1, 2, 3}); }); sm.def("array_initializer_list4", []() { return py::array_t({1, 2, 3, 4}); }); // test_array_resize // reshape array to 2D without changing size sm.def("array_reshape2", [](py::array_t a) { const auto dim_sz = (py::ssize_t) std::sqrt(a.size()); if (dim_sz * dim_sz != a.size()) { throw std::domain_error( "array_reshape2: input array total size is not a squared integer"); } a.resize({dim_sz, dim_sz}); }); // resize to 3D array with each dimension = N sm.def("array_resize3", [](py::array_t a, size_t N, bool refcheck) { a.resize({N, N, N}, refcheck); }); // test_array_create_and_resize // return 2D array with Nrows = Ncols = N sm.def("create_and_resize", [](size_t N) { py::array_t a; a.resize({N, N}); std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.); return a; }); sm.def("array_view", [](py::array_t a, const std::string &dtype) { return a.view(dtype); }); sm.def("reshape_initializer_list", [](py::array_t a, size_t N, size_t M, size_t O) { return a.reshape({N, M, O}); }); sm.def("reshape_tuple", [](py::array_t a, const std::vector &new_shape) { return a.reshape(new_shape); }); sm.def("index_using_ellipsis", [](const py::array &a) { return a[py::make_tuple(0, py::ellipsis(), 0)]; }); // test_argument_conversions sm.def( "accept_double", [](const py::array_t &) {}, py::arg("a")); sm.def( "accept_double_forcecast", [](const py::array_t &) {}, py::arg("a")); sm.def( "accept_double_c_style", [](const py::array_t &) {}, py::arg("a")); sm.def( "accept_double_c_style_forcecast", [](const py::array_t &) {}, py::arg("a")); sm.def( "accept_double_f_style", [](const py::array_t &) {}, py::arg("a")); sm.def( "accept_double_f_style_forcecast", [](const py::array_t &) {}, py::arg("a")); sm.def( "accept_double_noconvert", [](const py::array_t &) {}, "a"_a.noconvert()); sm.def( "accept_double_forcecast_noconvert", [](const py::array_t &) {}, "a"_a.noconvert()); sm.def( "accept_double_c_style_noconvert", [](const py::array_t &) {}, "a"_a.noconvert()); sm.def( "accept_double_c_style_forcecast_noconvert", [](const py::array_t &) {}, "a"_a.noconvert()); sm.def( "accept_double_f_style_noconvert", [](const py::array_t &) {}, "a"_a.noconvert()); sm.def( "accept_double_f_style_forcecast_noconvert", [](const py::array_t &) {}, "a"_a.noconvert()); // Check that types returns correct npy format descriptor sm.def("test_fmt_desc_float", [](const py::array_t &) {}); sm.def("test_fmt_desc_double", [](const py::array_t &) {}); sm.def("test_fmt_desc_const_float", [](const py::array_t &) {}); sm.def("test_fmt_desc_const_double", [](const py::array_t &) {}); sm.def("round_trip_float", [](double d) { return d; }); } aoflagger-v3.4.0/external/pybind11/tests/test_eigen_tensor.cpp0000644000175000017500000000073114507760431023170 0ustar olesoles/* tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #define PYBIND11_TEST_EIGEN_TENSOR_NAMESPACE eigen_tensor #ifdef EIGEN_AVOID_STL_ARRAY # undef EIGEN_AVOID_STL_ARRAY #endif #include "test_eigen_tensor.inl" #include "pybind11_tests.h" test_initializer egien_tensor("eigen_tensor", eigen_tensor_test::test_module); aoflagger-v3.4.0/external/pybind11/tests/cross_module_interleaved_error_already_set.cpp0000644000175000017500000000336014507760431030316 0ustar olesoles/* Copyright (c) 2022 Google LLC All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include // This file mimics a DSO that makes pybind11 calls but does not define a PYBIND11_MODULE, // so that the first call of cross_module_error_already_set() triggers the first call of // pybind11::detail::get_internals(). namespace { namespace py = pybind11; void interleaved_error_already_set() { PyErr_SetString(PyExc_RuntimeError, "1st error."); try { throw py::error_already_set(); } catch (const py::error_already_set &) { // The 2nd error could be conditional in a real application. PyErr_SetString(PyExc_RuntimeError, "2nd error."); } // Here the 1st error is destroyed before the 2nd error is fetched. // The error_already_set dtor triggers a pybind11::detail::get_internals() // call via pybind11::gil_scoped_acquire. if (PyErr_Occurred()) { throw py::error_already_set(); } } constexpr char kModuleName[] = "cross_module_interleaved_error_already_set"; struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr}; } // namespace extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_interleaved_error_already_set() { PyObject *m = PyModule_Create(&moduledef); if (m != nullptr) { static_assert(sizeof(&interleaved_error_already_set) == sizeof(void *), "Function pointer must have the same size as void *"); PyModule_AddObject( m, "funcaddr", PyLong_FromVoidPtr(reinterpret_cast(&interleaved_error_already_set))); } return m; } aoflagger-v3.4.0/external/pybind11/tests/requirements.txt0000644000175000017500000000113014507760431022222 0ustar olesolesbuild==0.8.0 numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7" numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6" numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10" numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10" and python_version<"3.11" pytest==7.0.0 pytest-timeout scipy==1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10" scipy==1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10" aoflagger-v3.4.0/external/pybind11/tests/test_stl_binders.py0000644000175000017500000002166214507760431022673 0ustar olesolesimport pytest from pybind11_tests import stl_binders as m def test_vector_int(): v_int = m.VectorInt([0, 0]) assert len(v_int) == 2 assert bool(v_int) is True # test construction from a generator v_int1 = m.VectorInt(x for x in range(5)) assert v_int1 == m.VectorInt([0, 1, 2, 3, 4]) v_int2 = m.VectorInt([0, 0]) assert v_int == v_int2 v_int2[1] = 1 assert v_int != v_int2 v_int2.append(2) v_int2.insert(0, 1) v_int2.insert(0, 2) v_int2.insert(0, 3) v_int2.insert(6, 3) assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]" with pytest.raises(IndexError): v_int2.insert(8, 4) v_int.append(99) v_int2[2:-2] = v_int assert v_int2 == m.VectorInt([3, 2, 0, 0, 99, 2, 3]) del v_int2[1:3] assert v_int2 == m.VectorInt([3, 0, 99, 2, 3]) del v_int2[0] assert v_int2 == m.VectorInt([0, 99, 2, 3]) v_int2.extend(m.VectorInt([4, 5])) assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5]) v_int2.extend([6, 7]) assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7]) # test error handling, and that the vector is unchanged with pytest.raises(RuntimeError): v_int2.extend([8, "a"]) assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7]) # test extending from a generator v_int2.extend(x for x in range(5)) assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4]) # test negative indexing assert v_int2[-1] == 4 # insert with negative index v_int2.insert(-1, 88) assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88, 4]) # delete negative index del v_int2[-1] assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88]) v_int2.clear() assert len(v_int2) == 0 # Older PyPy's failed here, related to the PyPy's buffer protocol. def test_vector_buffer(): b = bytearray([1, 2, 3, 4]) v = m.VectorUChar(b) assert v[1] == 2 v[2] = 5 mv = memoryview(v) # We expose the buffer interface assert mv[2] == 5 mv[2] = 6 assert v[2] == 6 mv = memoryview(b) v = m.VectorUChar(mv[::2]) assert v[1] == 3 with pytest.raises(RuntimeError) as excinfo: m.create_undeclstruct() # Undeclared struct contents, no buffer interface assert "NumPy type info missing for " in str(excinfo.value) def test_vector_buffer_numpy(): np = pytest.importorskip("numpy") a = np.array([1, 2, 3, 4], dtype=np.int32) with pytest.raises(TypeError): m.VectorInt(a) a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.uintc) v = m.VectorInt(a[0, :]) assert len(v) == 4 assert v[2] == 3 ma = np.asarray(v) ma[2] = 5 assert v[2] == 5 v = m.VectorInt(a[:, 1]) assert len(v) == 3 assert v[2] == 10 v = m.get_vectorstruct() assert v[0].x == 5 ma = np.asarray(v) ma[1]["x"] = 99 assert v[1].x == 99 v = m.VectorStruct( np.zeros( 3, dtype=np.dtype( [("w", "bool"), ("x", "I"), ("y", "float64"), ("z", "bool")], align=True ), ) ) assert len(v) == 3 b = np.array([1, 2, 3, 4], dtype=np.uint8) v = m.VectorUChar(b[::2]) assert v[1] == 3 def test_vector_bool(): import pybind11_cross_module_tests as cm vv_c = cm.VectorBool() for i in range(10): vv_c.append(i % 2 == 0) for i in range(10): assert vv_c[i] == (i % 2 == 0) assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]" def test_vector_custom(): v_a = m.VectorEl() v_a.append(m.El(1)) v_a.append(m.El(2)) assert str(v_a) == "VectorEl[El{1}, El{2}]" vv_a = m.VectorVectorEl() vv_a.append(v_a) vv_b = vv_a[0] assert str(vv_b) == "VectorEl[El{1}, El{2}]" def test_map_string_double(): mm = m.MapStringDouble() mm["a"] = 1 mm["b"] = 2.5 assert list(mm) == ["a", "b"] assert str(mm) == "MapStringDouble{a: 1, b: 2.5}" assert "b" in mm assert "c" not in mm assert 123 not in mm # Check that keys, values, items are views, not merely iterable keys = mm.keys() values = mm.values() items = mm.items() assert list(keys) == ["a", "b"] assert len(keys) == 2 assert "a" in keys assert "c" not in keys assert 123 not in keys assert list(items) == [("a", 1), ("b", 2.5)] assert len(items) == 2 assert ("b", 2.5) in items assert "hello" not in items assert ("b", 2.5, None) not in items assert list(values) == [1, 2.5] assert len(values) == 2 assert 1 in values assert 2 not in values # Check that views update when the map is updated mm["c"] = -1 assert list(keys) == ["a", "b", "c"] assert list(values) == [1, 2.5, -1] assert list(items) == [("a", 1), ("b", 2.5), ("c", -1)] um = m.UnorderedMapStringDouble() um["ua"] = 1.1 um["ub"] = 2.6 assert sorted(um) == ["ua", "ub"] assert list(um.keys()) == list(um) assert sorted(um.items()) == [("ua", 1.1), ("ub", 2.6)] assert list(zip(um.keys(), um.values())) == list(um.items()) assert "UnorderedMapStringDouble" in str(um) def test_map_string_double_const(): mc = m.MapStringDoubleConst() mc["a"] = 10 mc["b"] = 20.5 assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}" umc = m.UnorderedMapStringDoubleConst() umc["a"] = 11 umc["b"] = 21.5 str(umc) def test_noncopyable_containers(): # std::vector vnc = m.get_vnc(5) for i in range(0, 5): assert vnc[i].value == i + 1 for i, j in enumerate(vnc, start=1): assert j.value == i # std::deque dnc = m.get_dnc(5) for i in range(0, 5): assert dnc[i].value == i + 1 i = 1 for j in dnc: assert j.value == i i += 1 # std::map mnc = m.get_mnc(5) for i in range(1, 6): assert mnc[i].value == 10 * i vsum = 0 for k, v in mnc.items(): assert v.value == 10 * k vsum += v.value assert vsum == 150 # std::unordered_map mnc = m.get_umnc(5) for i in range(1, 6): assert mnc[i].value == 10 * i vsum = 0 for k, v in mnc.items(): assert v.value == 10 * k vsum += v.value assert vsum == 150 # nested std::map nvnc = m.get_nvnc(5) for i in range(1, 6): for j in range(0, 5): assert nvnc[i][j].value == j + 1 # Note: maps do not have .values() for _, v in nvnc.items(): for i, j in enumerate(v, start=1): assert j.value == i # nested std::map nmnc = m.get_nmnc(5) for i in range(1, 6): for j in range(10, 60, 10): assert nmnc[i][j].value == 10 * j vsum = 0 for _, v_o in nmnc.items(): for k_i, v_i in v_o.items(): assert v_i.value == 10 * k_i vsum += v_i.value assert vsum == 7500 # nested std::unordered_map numnc = m.get_numnc(5) for i in range(1, 6): for j in range(10, 60, 10): assert numnc[i][j].value == 10 * j vsum = 0 for _, v_o in numnc.items(): for k_i, v_i in v_o.items(): assert v_i.value == 10 * k_i vsum += v_i.value assert vsum == 7500 def test_map_delitem(): mm = m.MapStringDouble() mm["a"] = 1 mm["b"] = 2.5 assert list(mm) == ["a", "b"] assert list(mm.items()) == [("a", 1), ("b", 2.5)] del mm["a"] assert list(mm) == ["b"] assert list(mm.items()) == [("b", 2.5)] um = m.UnorderedMapStringDouble() um["ua"] = 1.1 um["ub"] = 2.6 assert sorted(um) == ["ua", "ub"] assert sorted(um.items()) == [("ua", 1.1), ("ub", 2.6)] del um["ua"] assert sorted(um) == ["ub"] assert sorted(um.items()) == [("ub", 2.6)] def test_map_view_types(): map_string_double = m.MapStringDouble() unordered_map_string_double = m.UnorderedMapStringDouble() map_string_double_const = m.MapStringDoubleConst() unordered_map_string_double_const = m.UnorderedMapStringDoubleConst() assert map_string_double.keys().__class__.__name__ == "KeysView[str]" assert map_string_double.values().__class__.__name__ == "ValuesView[float]" assert map_string_double.items().__class__.__name__ == "ItemsView[str, float]" keys_type = type(map_string_double.keys()) assert type(unordered_map_string_double.keys()) is keys_type assert type(map_string_double_const.keys()) is keys_type assert type(unordered_map_string_double_const.keys()) is keys_type values_type = type(map_string_double.values()) assert type(unordered_map_string_double.values()) is values_type assert type(map_string_double_const.values()) is values_type assert type(unordered_map_string_double_const.values()) is values_type items_type = type(map_string_double.items()) assert type(unordered_map_string_double.items()) is items_type assert type(map_string_double_const.items()) is items_type assert type(unordered_map_string_double_const.items()) is items_type aoflagger-v3.4.0/external/pybind11/tests/test_operator_overloading.py0000644000175000017500000001035414507760431024603 0ustar olesolesimport pytest from pybind11_tests import ConstructorStats from pybind11_tests import operators as m def test_operator_overloading(): v1 = m.Vector2(1, 2) v2 = m.Vector(3, -1) v3 = m.Vector2(1, 2) # Same value as v1, but different instance. assert v1 is not v3 assert str(v1) == "[1.000000, 2.000000]" assert str(v2) == "[3.000000, -1.000000]" assert str(-v2) == "[-3.000000, 1.000000]" assert str(v1 + v2) == "[4.000000, 1.000000]" assert str(v1 - v2) == "[-2.000000, 3.000000]" assert str(v1 - 8) == "[-7.000000, -6.000000]" assert str(v1 + 8) == "[9.000000, 10.000000]" assert str(v1 * 8) == "[8.000000, 16.000000]" assert str(v1 / 8) == "[0.125000, 0.250000]" assert str(8 - v1) == "[7.000000, 6.000000]" assert str(8 + v1) == "[9.000000, 10.000000]" assert str(8 * v1) == "[8.000000, 16.000000]" assert str(8 / v1) == "[8.000000, 4.000000]" assert str(v1 * v2) == "[3.000000, -2.000000]" assert str(v2 / v1) == "[3.000000, -0.500000]" assert v1 == v3 assert v1 != v2 assert hash(v1) == 4 # TODO(eric.cousineau): Make this work. # assert abs(v1) == "abs(Vector2)" v1 += 2 * v2 assert str(v1) == "[7.000000, 0.000000]" v1 -= v2 assert str(v1) == "[4.000000, 1.000000]" v1 *= 2 assert str(v1) == "[8.000000, 2.000000]" v1 /= 16 assert str(v1) == "[0.500000, 0.125000]" v1 *= v2 assert str(v1) == "[1.500000, -0.125000]" v2 /= v1 assert str(v2) == "[2.000000, 8.000000]" cstats = ConstructorStats.get(m.Vector2) assert cstats.alive() == 3 del v1 assert cstats.alive() == 2 del v2 assert cstats.alive() == 1 del v3 assert cstats.alive() == 0 assert cstats.values() == [ "[1.000000, 2.000000]", "[3.000000, -1.000000]", "[1.000000, 2.000000]", "[-3.000000, 1.000000]", "[4.000000, 1.000000]", "[-2.000000, 3.000000]", "[-7.000000, -6.000000]", "[9.000000, 10.000000]", "[8.000000, 16.000000]", "[0.125000, 0.250000]", "[7.000000, 6.000000]", "[9.000000, 10.000000]", "[8.000000, 16.000000]", "[8.000000, 4.000000]", "[3.000000, -2.000000]", "[3.000000, -0.500000]", "[6.000000, -2.000000]", ] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 10 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 def test_operators_notimplemented(): """#393: need to return NotSupported to ensure correct arithmetic operator behavior""" c1, c2 = m.C1(), m.C2() assert c1 + c1 == 11 assert c2 + c2 == 22 assert c2 + c1 == 21 assert c1 + c2 == 12 def test_nested(): """#328: first member in a class can't be used in operators""" a = m.NestA() b = m.NestB() c = m.NestC() a += 10 assert m.get_NestA(a) == 13 b.a += 100 assert m.get_NestA(b.a) == 103 c.b.a += 1000 assert m.get_NestA(c.b.a) == 1003 b -= 1 assert m.get_NestB(b) == 3 c.b -= 3 assert m.get_NestB(c.b) == 1 c *= 7 assert m.get_NestC(c) == 35 abase = a.as_base() assert abase.value == -2 a.as_base().value += 44 assert abase.value == 42 assert c.b.a.as_base().value == -2 c.b.a.as_base().value += 44 assert c.b.a.as_base().value == 42 del c pytest.gc_collect() del a # Shouldn't delete while abase is still alive pytest.gc_collect() assert abase.value == 42 del abase, b pytest.gc_collect() def test_overriding_eq_reset_hash(): assert m.Comparable(15) is not m.Comparable(15) assert m.Comparable(15) == m.Comparable(15) with pytest.raises(TypeError) as excinfo: hash(m.Comparable(15)) assert str(excinfo.value).startswith("unhashable type:") for hashable in (m.Hashable, m.Hashable2): assert hashable(15) is not hashable(15) assert hashable(15) == hashable(15) assert hash(hashable(15)) == 15 assert hash(hashable(15)) == hash(hashable(15)) def test_return_set_of_unhashable(): with pytest.raises(TypeError) as excinfo: m.get_unhashable_HashMe_set() assert str(excinfo.value.__cause__).startswith("unhashable type:") aoflagger-v3.4.0/external/pybind11/tests/test_sequences_and_iterators.cpp0000644000175000017500000005124114507760431025422 0ustar olesoles/* tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators, etc. Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include "constructor_stats.h" #include "pybind11_tests.h" #include #include #include #ifdef PYBIND11_HAS_OPTIONAL # include #endif // PYBIND11_HAS_OPTIONAL template class NonZeroIterator { const T *ptr_; public: explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {} const T &operator*() const { return *ptr_; } NonZeroIterator &operator++() { ++ptr_; return *this; } }; class NonZeroSentinel {}; template bool operator==(const NonZeroIterator> &it, const NonZeroSentinel &) { return !(*it).first || !(*it).second; } /* Iterator where dereferencing returns prvalues instead of references. */ template class NonRefIterator { const T *ptr_; public: explicit NonRefIterator(const T *ptr) : ptr_(ptr) {} T operator*() const { return T(*ptr_); } NonRefIterator &operator++() { ++ptr_; return *this; } bool operator==(const NonRefIterator &other) const { return ptr_ == other.ptr_; } }; class NonCopyableInt { public: explicit NonCopyableInt(int value) : value_(value) {} NonCopyableInt(const NonCopyableInt &) = delete; NonCopyableInt(NonCopyableInt &&other) noexcept : value_(other.value_) { other.value_ = -1; // detect when an unwanted move occurs } NonCopyableInt &operator=(const NonCopyableInt &) = delete; NonCopyableInt &operator=(NonCopyableInt &&other) noexcept { value_ = other.value_; other.value_ = -1; // detect when an unwanted move occurs return *this; } int get() const { return value_; } void set(int value) { value_ = value; } ~NonCopyableInt() = default; private: int value_; }; using NonCopyableIntPair = std::pair; PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(std::vector); template py::list test_random_access_iterator(PythonType x) { if (x.size() < 5) { throw py::value_error("Please provide at least 5 elements for testing."); } auto checks = py::list(); auto assert_equal = [&checks](py::handle a, py::handle b) { auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ); if (result == -1) { throw py::error_already_set(); } checks.append(result != 0); }; auto it = x.begin(); assert_equal(x[0], *it); assert_equal(x[0], it[0]); assert_equal(x[1], it[1]); assert_equal(x[1], *(++it)); assert_equal(x[1], *(it++)); assert_equal(x[2], *it); assert_equal(x[3], *(it += 1)); assert_equal(x[2], *(--it)); assert_equal(x[2], *(it--)); assert_equal(x[1], *it); assert_equal(x[0], *(it -= 1)); assert_equal(it->attr("real"), x[0].attr("real")); assert_equal((it + 1)->attr("real"), x[1].attr("real")); assert_equal(x[1], *(it + 1)); assert_equal(x[1], *(1 + it)); it += 3; assert_equal(x[1], *(it - 2)); checks.append(static_cast(x.end() - x.begin()) == x.size()); checks.append((x.begin() + static_cast(x.size())) == x.end()); checks.append(x.begin() < x.end()); return checks; } TEST_SUBMODULE(sequences_and_iterators, m) { // test_sliceable class Sliceable { public: explicit Sliceable(int n) : size(n) {} int start, stop, step; int size; }; py::class_(m, "Sliceable") .def(py::init()) .def("__getitem__", [](const Sliceable &s, const py::slice &slice) { py::ssize_t start = 0, stop = 0, step = 0, slicelength = 0; if (!slice.compute(s.size, &start, &stop, &step, &slicelength)) { throw py::error_already_set(); } int istart = static_cast(start); int istop = static_cast(stop); int istep = static_cast(step); return std::make_tuple(istart, istop, istep); }); m.def("make_forward_slice_size_t", []() { return py::slice(0, -1, 1); }); m.def("make_reversed_slice_object", []() { return py::slice(py::none(), py::none(), py::int_(-1)); }); #ifdef PYBIND11_HAS_OPTIONAL m.attr("has_optional") = true; m.def("make_reversed_slice_size_t_optional_verbose", []() { return py::slice(std::nullopt, std::nullopt, -1); }); // Warning: The following spelling may still compile if optional<> is not present and give // wrong answers. Please use with caution. m.def("make_reversed_slice_size_t_optional", []() { return py::slice({}, {}, -1); }); #else m.attr("has_optional") = false; #endif // test_sequence class Sequence { public: explicit Sequence(size_t size) : m_size(size) { print_created(this, "of size", m_size); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) m_data = new float[size]; memset(m_data, 0, sizeof(float) * size); } explicit Sequence(const std::vector &value) : m_size(value.size()) { print_created(this, "of size", m_size, "from std::vector"); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) m_data = new float[m_size]; memcpy(m_data, &value[0], sizeof(float) * m_size); } Sequence(const Sequence &s) : m_size(s.m_size) { print_copy_created(this); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) m_data = new float[m_size]; memcpy(m_data, s.m_data, sizeof(float) * m_size); } Sequence(Sequence &&s) noexcept : m_size(s.m_size), m_data(s.m_data) { print_move_created(this); s.m_size = 0; s.m_data = nullptr; } ~Sequence() { print_destroyed(this); delete[] m_data; } Sequence &operator=(const Sequence &s) { if (&s != this) { delete[] m_data; m_size = s.m_size; m_data = new float[m_size]; memcpy(m_data, s.m_data, sizeof(float) * m_size); } print_copy_assigned(this); return *this; } Sequence &operator=(Sequence &&s) noexcept { if (&s != this) { delete[] m_data; m_size = s.m_size; m_data = s.m_data; s.m_size = 0; s.m_data = nullptr; } print_move_assigned(this); return *this; } bool operator==(const Sequence &s) const { if (m_size != s.size()) { return false; } for (size_t i = 0; i < m_size; ++i) { if (m_data[i] != s[i]) { return false; } } return true; } bool operator!=(const Sequence &s) const { return !operator==(s); } float operator[](size_t index) const { return m_data[index]; } float &operator[](size_t index) { return m_data[index]; } bool contains(float v) const { for (size_t i = 0; i < m_size; ++i) { if (v == m_data[i]) { return true; } } return false; } Sequence reversed() const { Sequence result(m_size); for (size_t i = 0; i < m_size; ++i) { result[m_size - i - 1] = m_data[i]; } return result; } size_t size() const { return m_size; } const float *begin() const { return m_data; } const float *end() const { return m_data + m_size; } private: size_t m_size; float *m_data; }; py::class_(m, "Sequence") .def(py::init()) .def(py::init &>()) /// Bare bones interface .def("__getitem__", [](const Sequence &s, size_t i) { if (i >= s.size()) { throw py::index_error(); } return s[i]; }) .def("__setitem__", [](Sequence &s, size_t i, float v) { if (i >= s.size()) { throw py::index_error(); } s[i] = v; }) .def("__len__", &Sequence::size) /// Optional sequence protocol operations .def( "__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) /// Slicing protocol (optional) .def("__getitem__", [](const Sequence &s, const py::slice &slice) -> Sequence * { size_t start = 0, stop = 0, step = 0, slicelength = 0; if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) { throw py::error_already_set(); } auto *seq = new Sequence(slicelength); for (size_t i = 0; i < slicelength; ++i) { (*seq)[i] = s[start]; start += step; } return seq; }) .def("__setitem__", [](Sequence &s, const py::slice &slice, const Sequence &value) { size_t start = 0, stop = 0, step = 0, slicelength = 0; if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) { throw py::error_already_set(); } if (slicelength != value.size()) { throw std::runtime_error( "Left and right hand size of slice assignment have different sizes!"); } for (size_t i = 0; i < slicelength; ++i) { s[start] = value[i]; start += step; } }) /// Comparisons .def(py::self == py::self) .def(py::self != py::self) // Could also define py::self + py::self for concatenation, etc. ; // test_map_iterator // Interface of a map-like object that isn't (directly) an unordered_map, but provides some // basic map-like functionality. class StringMap { public: StringMap() = default; explicit StringMap(std::unordered_map init) : map(std::move(init)) {} void set(const std::string &key, std::string val) { map[key] = std::move(val); } std::string get(const std::string &key) const { return map.at(key); } size_t size() const { return map.size(); } private: std::unordered_map map; public: decltype(map.cbegin()) begin() const { return map.cbegin(); } decltype(map.cend()) end() const { return map.cend(); } }; py::class_(m, "StringMap") .def(py::init<>()) .def(py::init>()) .def("__getitem__", [](const StringMap &map, const std::string &key) { try { return map.get(key); } catch (const std::out_of_range &) { throw py::key_error("key '" + key + "' does not exist"); } }) .def("__setitem__", &StringMap::set) .def("__len__", &StringMap::size) .def( "__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, py::keep_alive<0, 1>()) .def( "items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, py::keep_alive<0, 1>()) .def( "values", [](const StringMap &map) { return py::make_value_iterator(map.begin(), map.end()); }, py::keep_alive<0, 1>()); // test_generalized_iterators class IntPairs { public: explicit IntPairs(std::vector> data) : data_(std::move(data)) {} const std::pair *begin() const { return data_.data(); } // .end() only required for py::make_iterator(self) overload const std::pair *end() const { return data_.data() + data_.size(); } private: std::vector> data_; }; py::class_(m, "IntPairs") .def(py::init>>()) .def( "nonzero", [](const IntPairs &s) { return py::make_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); }, py::keep_alive<0, 1>()) .def( "nonzero_keys", [](const IntPairs &s) { return py::make_key_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); }, py::keep_alive<0, 1>()) .def( "nonzero_values", [](const IntPairs &s) { return py::make_value_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); }, py::keep_alive<0, 1>()) // test iterator that returns values instead of references .def( "nonref", [](const IntPairs &s) { return py::make_iterator(NonRefIterator>(s.begin()), NonRefIterator>(s.end())); }, py::keep_alive<0, 1>()) .def( "nonref_keys", [](const IntPairs &s) { return py::make_key_iterator(NonRefIterator>(s.begin()), NonRefIterator>(s.end())); }, py::keep_alive<0, 1>()) .def( "nonref_values", [](const IntPairs &s) { return py::make_value_iterator(NonRefIterator>(s.begin()), NonRefIterator>(s.end())); }, py::keep_alive<0, 1>()) // test single-argument make_iterator .def( "simple_iterator", [](IntPairs &self) { return py::make_iterator(self); }, py::keep_alive<0, 1>()) .def( "simple_keys", [](IntPairs &self) { return py::make_key_iterator(self); }, py::keep_alive<0, 1>()) .def( "simple_values", [](IntPairs &self) { return py::make_value_iterator(self); }, py::keep_alive<0, 1>()) // Test iterator with an Extra (doesn't do anything useful, so not used // at runtime, but tests need to be able to compile with the correct // overload. See PR #3293. .def( "_make_iterator_extras", [](IntPairs &self) { return py::make_iterator(self, py::call_guard()); }, py::keep_alive<0, 1>()) .def( "_make_key_extras", [](IntPairs &self) { return py::make_key_iterator(self, py::call_guard()); }, py::keep_alive<0, 1>()) .def( "_make_value_extras", [](IntPairs &self) { return py::make_value_iterator(self, py::call_guard()); }, py::keep_alive<0, 1>()); // test_iterator_referencing py::class_(m, "NonCopyableInt") .def(py::init()) .def("set", &NonCopyableInt::set) .def("__int__", &NonCopyableInt::get); py::class_>(m, "VectorNonCopyableInt") .def(py::init<>()) .def("append", [](std::vector &vec, int value) { vec.emplace_back(value); }) .def("__iter__", [](std::vector &vec) { return py::make_iterator(vec.begin(), vec.end()); }); py::class_>(m, "VectorNonCopyableIntPair") .def(py::init<>()) .def("append", [](std::vector &vec, const std::pair &value) { vec.emplace_back(NonCopyableInt(value.first), NonCopyableInt(value.second)); }) .def("keys", [](std::vector &vec) { return py::make_key_iterator(vec.begin(), vec.end()); }) .def("values", [](std::vector &vec) { return py::make_value_iterator(vec.begin(), vec.end()); }); #if 0 // Obsolete: special data structure for exposing custom iterator types to python // kept here for illustrative purposes because there might be some use cases which // are not covered by the much simpler py::make_iterator struct PySequenceIterator { PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { } float next() { if (index == seq.size()) throw py::stop_iteration(); return seq[index++]; } const Sequence &seq; py::object ref; // keep a reference size_t index = 0; }; py::class_(seq, "Iterator") .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; }) .def("__next__", &PySequenceIterator::next); On the actual Sequence object, the iterator would be constructed as follows: .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast(), s); }) #endif // test_python_iterator_in_cpp m.def("object_to_list", [](const py::object &o) { auto l = py::list(); for (auto item : o) { l.append(item); } return l; }); m.def("iterator_to_list", [](py::iterator it) { auto l = py::list(); while (it != py::iterator::sentinel()) { l.append(*it); ++it; } return l; }); // test_sequence_length: check that Python sequences can be converted to py::sequence. m.def("sequence_length", [](const py::sequence &seq) { return seq.size(); }); // Make sure that py::iterator works with std algorithms m.def("count_none", [](const py::object &o) { return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); }); m.def("find_none", [](const py::object &o) { auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); return it->is_none(); }); m.def("count_nonzeros", [](const py::dict &d) { return std::count_if(d.begin(), d.end(), [](std::pair p) { return p.second.cast() != 0; }); }); m.def("tuple_iterator", &test_random_access_iterator); m.def("list_iterator", &test_random_access_iterator); m.def("sequence_iterator", &test_random_access_iterator); // test_iterator_passthrough // #181: iterator passthrough did not compile m.def("iterator_passthrough", [](py::iterator s) -> py::iterator { return py::make_iterator(std::begin(s), std::end(s)); }); // test_iterator_rvp // #388: Can't make iterators via make_iterator() with different r/v policies static std::vector list = {1, 2, 3}; m.def("make_iterator_1", []() { return py::make_iterator(list); }); m.def("make_iterator_2", []() { return py::make_iterator(list); }); // test_iterator on c arrays // #4100: ensure lvalue required as increment operand class CArrayHolder { public: CArrayHolder(double x, double y, double z) { values[0] = x; values[1] = y; values[2] = z; }; double values[3]; }; py::class_(m, "CArrayHolder") .def(py::init()) .def( "__iter__", [](const CArrayHolder &v) { return py::make_iterator(v.values, v.values + 3); }, py::keep_alive<0, 1>()); } aoflagger-v3.4.0/external/pybind11/tests/test_factory_constructors.cpp0000644000175000017500000004335314507760431025015 0ustar olesoles/* tests/test_factory_constructors.cpp -- tests construction from a factory function via py::init_factory() Copyright (c) 2017 Jason Rhinelander All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "constructor_stats.h" #include "pybind11_tests.h" #include #include #include // Classes for testing python construction via C++ factory function: // Not publicly constructible, copyable, or movable: class TestFactory1 { friend class TestFactoryHelper; TestFactory1() : value("(empty)") { print_default_created(this); } explicit TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); } explicit TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); } public: std::string value; TestFactory1(TestFactory1 &&) = delete; TestFactory1(const TestFactory1 &) = delete; TestFactory1 &operator=(TestFactory1 &&) = delete; TestFactory1 &operator=(const TestFactory1 &) = delete; ~TestFactory1() { print_destroyed(this); } }; // Non-public construction, but moveable: class TestFactory2 { friend class TestFactoryHelper; TestFactory2() : value("(empty2)") { print_default_created(this); } explicit TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } explicit TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } public: TestFactory2(TestFactory2 &&m) noexcept : value{std::move(m.value)} { print_move_created(this); } TestFactory2 &operator=(TestFactory2 &&m) noexcept { value = std::move(m.value); print_move_assigned(this); return *this; } std::string value; ~TestFactory2() { print_destroyed(this); } }; // Mixed direct/factory construction: class TestFactory3 { protected: friend class TestFactoryHelper; TestFactory3() : value("(empty3)") { print_default_created(this); } explicit TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } public: explicit TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } TestFactory3(TestFactory3 &&m) noexcept : value{std::move(m.value)} { print_move_created(this); } TestFactory3 &operator=(TestFactory3 &&m) noexcept { value = std::move(m.value); print_move_assigned(this); return *this; } std::string value; virtual ~TestFactory3() { print_destroyed(this); } }; // Inheritance test class TestFactory4 : public TestFactory3 { public: TestFactory4() : TestFactory3() { print_default_created(this); } explicit TestFactory4(int v) : TestFactory3(v) { print_created(this, v); } ~TestFactory4() override { print_destroyed(this); } }; // Another class for an invalid downcast test class TestFactory5 : public TestFactory3 { public: explicit TestFactory5(int i) : TestFactory3(i) { print_created(this, i); } ~TestFactory5() override { print_destroyed(this); } }; class TestFactory6 { protected: int value; bool alias = false; public: explicit TestFactory6(int i) : value{i} { print_created(this, i); } TestFactory6(TestFactory6 &&f) noexcept { print_move_created(this); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) value = f.value; // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) alias = f.alias; } TestFactory6(const TestFactory6 &f) { print_copy_created(this); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) value = f.value; // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) alias = f.alias; } virtual ~TestFactory6() { print_destroyed(this); } virtual int get() { return value; } bool has_alias() const { return alias; } }; class PyTF6 : public TestFactory6 { public: // Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only // when an alias is needed: explicit PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); } explicit PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); } PyTF6(PyTF6 &&f) noexcept : TestFactory6(std::move(f)) { print_move_created(this); } PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } explicit PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } ~PyTF6() override { print_destroyed(this); } int get() override { PYBIND11_OVERRIDE(int, TestFactory6, get, /*no args*/); } }; class TestFactory7 { protected: int value; bool alias = false; public: explicit TestFactory7(int i) : value{i} { print_created(this, i); } TestFactory7(TestFactory7 &&f) noexcept { print_move_created(this); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) value = f.value; // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) alias = f.alias; } TestFactory7(const TestFactory7 &f) { print_copy_created(this); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) value = f.value; // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) alias = f.alias; } virtual ~TestFactory7() { print_destroyed(this); } virtual int get() { return value; } bool has_alias() const { return alias; } }; class PyTF7 : public TestFactory7 { public: explicit PyTF7(int i) : TestFactory7(i) { // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) alias = true; print_created(this, i); } PyTF7(PyTF7 &&f) noexcept : TestFactory7(std::move(f)) { print_move_created(this); } PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } ~PyTF7() override { print_destroyed(this); } int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); } }; class TestFactoryHelper { public: // Non-movable, non-copyable type: // Return via pointer: static TestFactory1 *construct1() { return new TestFactory1(); } // Holder: static std::unique_ptr construct1(int a) { return std::unique_ptr(new TestFactory1(a)); } // pointer again static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(std::move(a)); } // Moveable type: // pointer: static TestFactory2 *construct2() { return new TestFactory2(); } // holder: static std::unique_ptr construct2(int a) { return std::unique_ptr(new TestFactory2(a)); } // by value moving: static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); } // shared_ptr holder type: // pointer: static TestFactory3 *construct3() { return new TestFactory3(); } // holder: static std::shared_ptr construct3(int a) { return std::shared_ptr(new TestFactory3(a)); } }; TEST_SUBMODULE(factory_constructors, m) { // Define various trivial types to allow simpler overload resolution: py::module_ m_tag = m.def_submodule("tag"); #define MAKE_TAG_TYPE(Name) \ struct Name##_tag {}; \ py::class_(m_tag, #Name "_tag").def(py::init<>()); \ m_tag.attr(#Name) = py::cast(Name##_tag{}) MAKE_TAG_TYPE(pointer); MAKE_TAG_TYPE(unique_ptr); MAKE_TAG_TYPE(move); MAKE_TAG_TYPE(shared_ptr); MAKE_TAG_TYPE(derived); MAKE_TAG_TYPE(TF4); MAKE_TAG_TYPE(TF5); MAKE_TAG_TYPE(null_ptr); MAKE_TAG_TYPE(null_unique_ptr); MAKE_TAG_TYPE(null_shared_ptr); MAKE_TAG_TYPE(base); MAKE_TAG_TYPE(invalid_base); MAKE_TAG_TYPE(alias); MAKE_TAG_TYPE(unaliasable); MAKE_TAG_TYPE(mixed); // test_init_factory_basic, test_bad_type py::class_(m, "TestFactory1") .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); })) .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); })) .def(py::init( [](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); })) .def_readwrite("value", &TestFactory1::value); py::class_(m, "TestFactory2") .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) .def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(std::move(v)); })) .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) .def_readwrite("value", &TestFactory2::value); // Stateful & reused: int c = 1; auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a); }; // test_init_factory_basic, test_init_factory_casting py::class_> pyTestFactory3(m, "TestFactory3"); pyTestFactory3 .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })); ignoreOldStyleInitWarnings([&pyTestFactory3]() { pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(std::move(v)); }); // placement-new ctor }); pyTestFactory3 // factories returning a derived type: .def(py::init(c4a)) // derived ptr .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); })) // derived shared ptr: .def(py::init( [](shared_ptr_tag, TF4_tag, int a) { return std::make_shared(a); })) .def(py::init( [](shared_ptr_tag, TF5_tag, int a) { return std::make_shared(a); })) // Returns nullptr: .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; })) .def(py::init([](null_unique_ptr_tag) { return std::unique_ptr(); })) .def(py::init([](null_shared_ptr_tag) { return std::shared_ptr(); })) .def_readwrite("value", &TestFactory3::value); // test_init_factory_casting py::class_>(m, "TestFactory4") .def(py::init(c4a)) // pointer ; // Doesn't need to be registered, but registering makes getting ConstructorStats easier: py::class_>(m, "TestFactory5"); // test_init_factory_alias // Alias testing py::class_(m, "TestFactory6") .def(py::init([](base_tag, int i) { return TestFactory6(i); })) .def(py::init([](alias_tag, int i) { return PyTF6(i); })) .def(py::init([](alias_tag, std::string s) { return PyTF6(std::move(s)); })) .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) .def(py::init( [](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) .def("get", &TestFactory6::get) .def("has_alias", &TestFactory6::has_alias) .def_static( "get_cstats", &ConstructorStats::get, py::return_value_policy::reference) .def_static( "get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference); // test_init_factory_dual // Separate alias constructor testing py::class_>(m, "TestFactory7") .def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); })) .def(py::init([](pointer_tag, int i) { return new TestFactory7(i); }, [](pointer_tag, int i) { return new PyTF7(i); })) .def(py::init([](mixed_tag, int i) { return new TestFactory7(i); }, [](mixed_tag, int i) { return PyTF7(i); })) .def(py::init([](mixed_tag, const std::string &s) { return TestFactory7((int) s.size()); }, [](mixed_tag, const std::string &s) { return new PyTF7((int) s.size()); })) .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, [](alias_tag, pointer_tag, int i) { return new PyTF7(10 * i); })) .def(py::init( [](shared_ptr_tag, base_tag, int i) { return std::make_shared(i); }, [](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr(p); })) .def(py::init([](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); }, [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); })) // <-- invalid alias factory .def("get", &TestFactory7::get) .def("has_alias", &TestFactory7::has_alias) .def_static( "get_cstats", &ConstructorStats::get, py::return_value_policy::reference) .def_static( "get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference); // test_placement_new_alternative // Class with a custom new operator but *without* a placement new operator (issue #948) class NoPlacementNew { public: explicit NoPlacementNew(int i) : i(i) {} static void *operator new(std::size_t s) { auto *p = ::operator new(s); py::print("operator new called, returning", reinterpret_cast(p)); return p; } static void operator delete(void *p) { py::print("operator delete called on", reinterpret_cast(p)); ::operator delete(p); } int i; }; // As of 2.2, `py::init` no longer requires placement new py::class_(m, "NoPlacementNew") .def(py::init()) .def(py::init([]() { return new NoPlacementNew(100); })) .def_readwrite("i", &NoPlacementNew::i); // test_reallocations // Class that has verbose operator_new/operator_delete calls struct NoisyAlloc { NoisyAlloc(const NoisyAlloc &) = default; explicit NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); } explicit NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); } ~NoisyAlloc() { py::print("~NoisyAlloc()"); } static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); } static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; } static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); } static void operator delete(void *, void *) { py::print("noisy placement delete"); } }; py::class_ pyNoisyAlloc(m, "NoisyAlloc"); // Since these overloads have the same number of arguments, the dispatcher will try each of // them until the arguments convert. Thus we can get a pre-allocation here when passing a // single non-integer: ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { pyNoisyAlloc.def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }); // Regular constructor, runs first, requires preallocation }); pyNoisyAlloc.def(py::init([](double d) { return new NoisyAlloc(d); })); // The two-argument version: first the factory pointer overload. pyNoisyAlloc.def(py::init([](int i, int) { return new NoisyAlloc(i); })); // Return-by-value: pyNoisyAlloc.def(py::init([](double d, int) { return NoisyAlloc(d); })); // Old-style placement new init; requires preallocation ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { pyNoisyAlloc.def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); }); }); // Requires deallocation of previous overload preallocated value: pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); })); // Regular again: requires yet another preallocation ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { pyNoisyAlloc.def( "__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); }); }); // static_assert testing (the following def's should all fail with appropriate compilation // errors): #if 0 struct BadF1Base {}; struct BadF1 : BadF1Base {}; struct PyBadF1 : BadF1 {}; py::class_> bf1(m, "BadF1"); // wrapped factory function must return a compatible pointer, holder, or value bf1.def(py::init([]() { return 3; })); // incompatible factory function pointer return type bf1.def(py::init([]() { static int three = 3; return &three; })); // incompatible factory function std::shared_ptr return type: cannot convert shared_ptr to holder // (non-polymorphic base) bf1.def(py::init([]() { return std::shared_ptr(new BadF1()); })); #endif } aoflagger-v3.4.0/external/pybind11/tests/test_stl.py0000644000175000017500000002771014507760431021165 0ustar olesolesimport pytest from pybind11_tests import ConstructorStats, UserType from pybind11_tests import stl as m def test_vector(doc): """std::vector <-> list""" lst = m.cast_vector() assert lst == [1] lst.append(2) assert m.load_vector(lst) assert m.load_vector(tuple(lst)) assert m.cast_bool_vector() == [True, False] assert m.load_bool_vector([True, False]) assert m.load_bool_vector((True, False)) assert doc(m.cast_vector) == "cast_vector() -> List[int]" assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool" # Test regression caused by 936: pointers to stl containers weren't castable assert m.cast_ptr_vector() == ["lvalue", "lvalue"] def test_deque(): """std::deque <-> list""" lst = m.cast_deque() assert lst == [1] lst.append(2) assert m.load_deque(lst) assert m.load_deque(tuple(lst)) def test_array(doc): """std::array <-> list""" lst = m.cast_array() assert lst == [1, 2] assert m.load_array(lst) assert m.load_array(tuple(lst)) assert doc(m.cast_array) == "cast_array() -> List[int[2]]" assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool" def test_valarray(doc): """std::valarray <-> list""" lst = m.cast_valarray() assert lst == [1, 4, 9] assert m.load_valarray(lst) assert m.load_valarray(tuple(lst)) assert doc(m.cast_valarray) == "cast_valarray() -> List[int]" assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool" def test_map(doc): """std::map <-> dict""" d = m.cast_map() assert d == {"key": "value"} assert "key" in d d["key2"] = "value2" assert "key2" in d assert m.load_map(d) assert doc(m.cast_map) == "cast_map() -> Dict[str, str]" assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool" def test_set(doc): """std::set <-> set""" s = m.cast_set() assert s == {"key1", "key2"} s.add("key3") assert m.load_set(s) assert m.load_set(frozenset(s)) assert doc(m.cast_set) == "cast_set() -> Set[str]" assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool" def test_recursive_casting(): """Tests that stl casters preserve lvalue/rvalue context for container values""" assert m.cast_rv_vector() == ["rvalue", "rvalue"] assert m.cast_lv_vector() == ["lvalue", "lvalue"] assert m.cast_rv_array() == ["rvalue", "rvalue", "rvalue"] assert m.cast_lv_array() == ["lvalue", "lvalue"] assert m.cast_rv_map() == {"a": "rvalue"} assert m.cast_lv_map() == {"a": "lvalue", "b": "lvalue"} assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]] assert m.cast_lv_nested() == { "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]], "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]], } # Issue #853 test case: z = m.cast_unique_ptr_vector() assert z[0].value == 7 assert z[1].value == 42 def test_move_out_container(): """Properties use the `reference_internal` policy by default. If the underlying function returns an rvalue, the policy is automatically changed to `move` to avoid referencing a temporary. In case the return value is a container of user-defined types, the policy also needs to be applied to the elements, not just the container.""" c = m.MoveOutContainer() moved_out_list = c.move_list assert [x.value for x in moved_out_list] == [0, 1, 2] @pytest.mark.skipif(not hasattr(m, "has_optional"), reason="no ") def test_optional(): assert m.double_or_zero(None) == 0 assert m.double_or_zero(42) == 84 pytest.raises(TypeError, m.double_or_zero, "foo") assert m.half_or_none(0) is None assert m.half_or_none(42) == 21 pytest.raises(TypeError, m.half_or_none, "foo") assert m.test_nullopt() == 42 assert m.test_nullopt(None) == 42 assert m.test_nullopt(42) == 42 assert m.test_nullopt(43) == 43 assert m.test_no_assign() == 42 assert m.test_no_assign(None) == 42 assert m.test_no_assign(m.NoAssign(43)) == 43 pytest.raises(TypeError, m.test_no_assign, 43) assert m.nodefer_none_optional(None) holder = m.OptionalHolder() mvalue = holder.member assert mvalue.initialized assert holder.member_initialized() props = m.OptionalProperties() assert int(props.access_by_ref) == 42 assert int(props.access_by_copy) == 42 @pytest.mark.skipif( not hasattr(m, "has_exp_optional"), reason="no " ) def test_exp_optional(): assert m.double_or_zero_exp(None) == 0 assert m.double_or_zero_exp(42) == 84 pytest.raises(TypeError, m.double_or_zero_exp, "foo") assert m.half_or_none_exp(0) is None assert m.half_or_none_exp(42) == 21 pytest.raises(TypeError, m.half_or_none_exp, "foo") assert m.test_nullopt_exp() == 42 assert m.test_nullopt_exp(None) == 42 assert m.test_nullopt_exp(42) == 42 assert m.test_nullopt_exp(43) == 43 assert m.test_no_assign_exp() == 42 assert m.test_no_assign_exp(None) == 42 assert m.test_no_assign_exp(m.NoAssign(43)) == 43 pytest.raises(TypeError, m.test_no_assign_exp, 43) holder = m.OptionalExpHolder() mvalue = holder.member assert mvalue.initialized assert holder.member_initialized() props = m.OptionalExpProperties() assert int(props.access_by_ref) == 42 assert int(props.access_by_copy) == 42 @pytest.mark.skipif(not hasattr(m, "has_boost_optional"), reason="no ") def test_boost_optional(): assert m.double_or_zero_boost(None) == 0 assert m.double_or_zero_boost(42) == 84 pytest.raises(TypeError, m.double_or_zero_boost, "foo") assert m.half_or_none_boost(0) is None assert m.half_or_none_boost(42) == 21 pytest.raises(TypeError, m.half_or_none_boost, "foo") assert m.test_nullopt_boost() == 42 assert m.test_nullopt_boost(None) == 42 assert m.test_nullopt_boost(42) == 42 assert m.test_nullopt_boost(43) == 43 assert m.test_no_assign_boost() == 42 assert m.test_no_assign_boost(None) == 42 assert m.test_no_assign_boost(m.NoAssign(43)) == 43 pytest.raises(TypeError, m.test_no_assign_boost, 43) holder = m.OptionalBoostHolder() mvalue = holder.member assert mvalue.initialized assert holder.member_initialized() props = m.OptionalBoostProperties() assert int(props.access_by_ref) == 42 assert int(props.access_by_copy) == 42 def test_reference_sensitive_optional(): assert m.double_or_zero_refsensitive(None) == 0 assert m.double_or_zero_refsensitive(42) == 84 pytest.raises(TypeError, m.double_or_zero_refsensitive, "foo") assert m.half_or_none_refsensitive(0) is None assert m.half_or_none_refsensitive(42) == 21 pytest.raises(TypeError, m.half_or_none_refsensitive, "foo") assert m.test_nullopt_refsensitive() == 42 assert m.test_nullopt_refsensitive(None) == 42 assert m.test_nullopt_refsensitive(42) == 42 assert m.test_nullopt_refsensitive(43) == 43 assert m.test_no_assign_refsensitive() == 42 assert m.test_no_assign_refsensitive(None) == 42 assert m.test_no_assign_refsensitive(m.NoAssign(43)) == 43 pytest.raises(TypeError, m.test_no_assign_refsensitive, 43) holder = m.OptionalRefSensitiveHolder() mvalue = holder.member assert mvalue.initialized assert holder.member_initialized() props = m.OptionalRefSensitiveProperties() assert int(props.access_by_ref) == 42 assert int(props.access_by_copy) == 42 @pytest.mark.skipif(not hasattr(m, "has_filesystem"), reason="no ") def test_fs_path(): from pathlib import Path class PseudoStrPath: def __fspath__(self): return "foo/bar" class PseudoBytesPath: def __fspath__(self): return b"foo/bar" assert m.parent_path(Path("foo/bar")) == Path("foo") assert m.parent_path("foo/bar") == Path("foo") assert m.parent_path(b"foo/bar") == Path("foo") assert m.parent_path(PseudoStrPath()) == Path("foo") assert m.parent_path(PseudoBytesPath()) == Path("foo") @pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no ") def test_variant(doc): assert m.load_variant(1) == "int" assert m.load_variant("1") == "std::string" assert m.load_variant(1.0) == "double" assert m.load_variant(None) == "std::nullptr_t" assert m.load_variant_2pass(1) == "int" assert m.load_variant_2pass(1.0) == "double" assert m.cast_variant() == (5, "Hello") assert ( doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str" ) @pytest.mark.skipif( not hasattr(m, "load_monostate_variant"), reason="no std::monostate" ) def test_variant_monostate(doc): assert m.load_monostate_variant(None) == "std::monostate" assert m.load_monostate_variant(1) == "int" assert m.load_monostate_variant("1") == "std::string" assert m.cast_monostate_variant() == (None, 5, "Hello") assert ( doc(m.load_monostate_variant) == "load_monostate_variant(arg0: Union[None, int, str]) -> str" ) def test_vec_of_reference_wrapper(): """#171: Can't return reference wrappers (or STL structures containing them)""" assert ( str(m.return_vec_of_reference_wrapper(UserType(4))) == "[UserType(1), UserType(2), UserType(3), UserType(4)]" ) def test_stl_pass_by_pointer(msg): """Passing nullptr or None to an STL container pointer is not expected to work""" with pytest.raises(TypeError) as excinfo: m.stl_pass_by_pointer() # default value is `nullptr` assert ( msg(excinfo.value) == """ stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: 1. (v: List[int] = None) -> List[int] Invoked with: """ ) with pytest.raises(TypeError) as excinfo: m.stl_pass_by_pointer(None) assert ( msg(excinfo.value) == """ stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: 1. (v: List[int] = None) -> List[int] Invoked with: None """ ) assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3] def test_missing_header_message(): """Trying convert `list` to a `std::vector`, or vice versa, without including should result in a helpful suggestion in the error message""" import pybind11_cross_module_tests as cm expected_message = ( "Did you forget to `#include `? Or ,\n" ", , etc. Some automatic\n" "conversions are optional and require extra headers to be included\n" "when compiling your pybind11 module." ) with pytest.raises(TypeError) as excinfo: cm.missing_header_arg([1.0, 2.0, 3.0]) assert expected_message in str(excinfo.value) with pytest.raises(TypeError) as excinfo: cm.missing_header_return() assert expected_message in str(excinfo.value) def test_function_with_string_and_vector_string_arg(): """Check if a string is NOT implicitly converted to a list, which was the behavior before fix of issue #1258""" assert m.func_with_string_or_vector_string_arg_overload(("A", "B")) == 2 assert m.func_with_string_or_vector_string_arg_overload(["A", "B"]) == 2 assert m.func_with_string_or_vector_string_arg_overload("A") == 3 def test_stl_ownership(): cstats = ConstructorStats.get(m.Placeholder) assert cstats.alive() == 0 r = m.test_stl_ownership() assert len(r) == 1 del r assert cstats.alive() == 0 def test_array_cast_sequence(): assert m.array_cast_sequence((1, 2, 3)) == [1, 2, 3] def test_issue_1561(): """check fix for issue #1561""" bar = m.Issue1561Outer() bar.list = [m.Issue1561Inner("bar")] bar.list assert bar.list[0].data == "bar" def test_return_vector_bool_raw_ptr(): # Add `while True:` for manual leak checking. v = m.return_vector_bool_raw_ptr() assert isinstance(v, list) assert len(v) == 4513 aoflagger-v3.4.0/external/pybind11/tests/test_numpy_dtypes.py0000644000175000017500000003370014507760431023117 0ustar olesolesimport re import pytest import env # noqa: F401 from pybind11_tests import numpy_dtypes as m np = pytest.importorskip("numpy") @pytest.fixture(scope="module") def simple_dtype(): ld = np.dtype("longdouble") return np.dtype( { "names": ["bool_", "uint_", "float_", "ldbl_"], "formats": ["?", "u4", "f4", f"f{ld.itemsize}"], "offsets": [0, 4, 8, (16 if ld.alignment > 4 else 12)], } ) @pytest.fixture(scope="module") def packed_dtype(): return np.dtype([("bool_", "?"), ("uint_", "u4"), ("float_", "f4"), ("ldbl_", "g")]) def dt_fmt(): from sys import byteorder e = "<" if byteorder == "little" else ">" return ( "{{'names':['bool_','uint_','float_','ldbl_']," "'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}']," "'offsets':[0,4,8,{}],'itemsize':{}}}" ) def simple_dtype_fmt(): ld = np.dtype("longdouble") simple_ld_off = 12 + 4 * (ld.alignment > 4) return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize) def packed_dtype_fmt(): from sys import byteorder return "[('bool_','?'),('uint_','{e}u4'),('float_','{e}f4'),('ldbl_','{e}f{}')]".format( np.dtype("longdouble").itemsize, e="<" if byteorder == "little" else ">" ) def partial_ld_offset(): return ( 12 + 4 * (np.dtype("uint64").alignment > 4) + 8 + 8 * (np.dtype("longdouble").alignment > 8) ) def partial_dtype_fmt(): ld = np.dtype("longdouble") partial_ld_off = partial_ld_offset() partial_size = partial_ld_off + ld.itemsize partial_end_padding = partial_size % np.dtype("uint64").alignment return dt_fmt().format( ld.itemsize, partial_ld_off, partial_size + partial_end_padding ) def partial_nested_fmt(): ld = np.dtype("longdouble") partial_nested_off = 8 + 8 * (ld.alignment > 8) partial_ld_off = partial_ld_offset() partial_size = partial_ld_off + ld.itemsize partial_end_padding = partial_size % np.dtype("uint64").alignment partial_nested_size = partial_nested_off * 2 + partial_size + partial_end_padding return "{{'names':['a'],'formats':[{}],'offsets':[{}],'itemsize':{}}}".format( partial_dtype_fmt(), partial_nested_off, partial_nested_size ) def assert_equal(actual, expected_data, expected_dtype): np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype)) def test_format_descriptors(): with pytest.raises(RuntimeError) as excinfo: m.get_format_unbound() assert re.match( "^NumPy type info missing for .*UnboundStruct.*$", str(excinfo.value) ) ld = np.dtype("longdouble") ldbl_fmt = ("4x" if ld.alignment > 4 else "") + ld.char ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}" dbl = np.dtype("double") end_padding = ld.itemsize % np.dtype("uint64").alignment partial_fmt = ( "^T{?:bool_:3xI:uint_:f:float_:" + str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) + "xg:ldbl_:" + (str(end_padding) + "x}" if end_padding > 0 else "}") ) nested_extra = str(max(8, ld.alignment)) assert m.print_format_descriptors() == [ ss_fmt, "^T{?:bool_:I:uint_:f:float_:g:ldbl_:}", "^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}", partial_fmt, "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}", "^T{3s:a:3s:b:}", "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}", "^T{q:e1:B:e2:}", "^T{Zf:cflt:Zd:cdbl:}", ] def test_dtype(simple_dtype): from sys import byteorder e = "<" if byteorder == "little" else ">" assert [x.replace(" ", "") for x in m.print_dtypes()] == [ simple_dtype_fmt(), packed_dtype_fmt(), f"[('a',{simple_dtype_fmt()}),('b',{packed_dtype_fmt()})]", partial_dtype_fmt(), partial_nested_fmt(), "[('a','S3'),('b','S3')]", ( "{'names':['a','b','c','d']," f"'formats':[('S4',(3,)),('{e}i4',(2,)),('u1',(3,)),('{e}f4',(4,2))]," "'offsets':[0,12,20,24],'itemsize':56}" ), "[('e1','" + e + "i8'),('e2','u1')]", "[('x','i1'),('y','" + e + "u8')]", "[('cflt','" + e + "c8'),('cdbl','" + e + "c16')]", ] d1 = np.dtype( { "names": ["a", "b"], "formats": ["int32", "float64"], "offsets": [1, 10], "itemsize": 20, } ) d2 = np.dtype([("a", "i4"), ("b", "f4")]) assert m.test_dtype_ctors() == [ np.dtype("int32"), np.dtype("float64"), np.dtype("bool"), d1, d1, np.dtype("uint32"), d2, np.dtype("d"), ] assert m.test_dtype_methods() == [ np.dtype("int32"), simple_dtype, False, True, np.dtype("int32").itemsize, simple_dtype.itemsize, ] assert m.trailing_padding_dtype() == m.buffer_to_dtype( np.zeros(1, m.trailing_padding_dtype()) ) expected_chars = "bhilqBHILQefdgFDG?MmO" assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO") assert m.test_dtype_char_() == list(expected_chars) assert m.test_dtype_num() == [np.dtype(ch).num for ch in expected_chars] assert m.test_dtype_byteorder() == [np.dtype(ch).byteorder for ch in expected_chars] assert m.test_dtype_alignment() == [np.dtype(ch).alignment for ch in expected_chars] assert m.test_dtype_flags() == [chr(np.dtype(ch).flags) for ch in expected_chars] def test_recarray(simple_dtype, packed_dtype): elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)] for func, dtype in [ (m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype), ]: arr = func(0) assert arr.dtype == dtype assert_equal(arr, [], simple_dtype) assert_equal(arr, [], packed_dtype) arr = func(3) assert arr.dtype == dtype assert_equal(arr, elements, simple_dtype) assert_equal(arr, elements, packed_dtype) # Show what recarray's look like in NumPy. assert type(arr[0]) == np.void assert type(arr[0].item()) == tuple if dtype == simple_dtype: assert m.print_rec_simple(arr) == [ "s:0,0,0,-0", "s:1,1,1.5,-2.5", "s:0,2,3,-5", ] else: assert m.print_rec_packed(arr) == [ "p:0,0,0,-0", "p:1,1,1.5,-2.5", "p:0,2,3,-5", ] nested_dtype = np.dtype([("a", simple_dtype), ("b", packed_dtype)]) arr = m.create_rec_nested(0) assert arr.dtype == nested_dtype assert_equal(arr, [], nested_dtype) arr = m.create_rec_nested(3) assert arr.dtype == nested_dtype assert_equal( arr, [ ((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)), ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)), ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5)), ], nested_dtype, ) assert m.print_rec_nested(arr) == [ "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5", "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5", "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5", ] arr = m.create_rec_partial(3) assert str(arr.dtype).replace(" ", "") == partial_dtype_fmt() partial_dtype = arr.dtype assert "" not in arr.dtype.fields assert partial_dtype.itemsize > simple_dtype.itemsize assert_equal(arr, elements, simple_dtype) assert_equal(arr, elements, packed_dtype) arr = m.create_rec_partial_nested(3) assert str(arr.dtype).replace(" ", "") == partial_nested_fmt() assert "" not in arr.dtype.fields assert "" not in arr.dtype.fields["a"][0].fields assert arr.dtype.itemsize > partial_dtype.itemsize np.testing.assert_equal(arr["a"], m.create_rec_partial(3)) def test_array_constructors(): data = np.arange(1, 7, dtype="int32") for i in range(8): np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2))) np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2))) for i in range(5): np.testing.assert_array_equal(m.test_array_ctors(30 + i), data) np.testing.assert_array_equal(m.test_array_ctors(40 + i), data) def test_string_array(): arr = m.create_string_array(True) assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]" assert m.print_string_array(arr) == [ "a='',b=''", "a='a',b='a'", "a='ab',b='ab'", "a='abc',b='abc'", ] dtype = arr.dtype assert arr["a"].tolist() == [b"", b"a", b"ab", b"abc"] assert arr["b"].tolist() == [b"", b"a", b"ab", b"abc"] arr = m.create_string_array(False) assert dtype == arr.dtype def test_array_array(): from sys import byteorder e = "<" if byteorder == "little" else ">" arr = m.create_array_array(3) assert str(arr.dtype).replace(" ", "") == ( "{'names':['a','b','c','d']," f"'formats':[('S4',(3,)),('{e}i4',(2,)),('u1',(3,)),('{e}f4',(4,2))]," "'offsets':[0,12,20,24],'itemsize':56}" ) assert m.print_array_array(arr) == [ "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}", "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}", "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}", ] assert arr["a"].tolist() == [ [b"ABCD", b"KLMN", b"UVWX"], [b"WXYZ", b"GHIJ", b"QRST"], [b"STUV", b"CDEF", b"MNOP"], ] assert arr["b"].tolist() == [[0, 1], [1000, 1001], [2000, 2001]] assert m.create_array_array(0).dtype == arr.dtype def test_enum_array(): from sys import byteorder e = "<" if byteorder == "little" else ">" arr = m.create_enum_array(3) dtype = arr.dtype assert dtype == np.dtype([("e1", e + "i8"), ("e2", "u1")]) assert m.print_enum_array(arr) == ["e1=A,e2=X", "e1=B,e2=Y", "e1=A,e2=X"] assert arr["e1"].tolist() == [-1, 1, -1] assert arr["e2"].tolist() == [1, 2, 1] assert m.create_enum_array(0).dtype == dtype def test_complex_array(): from sys import byteorder e = "<" if byteorder == "little" else ">" arr = m.create_complex_array(3) dtype = arr.dtype assert dtype == np.dtype([("cflt", e + "c8"), ("cdbl", e + "c16")]) assert m.print_complex_array(arr) == [ "c:(0,0.25),(0.5,0.75)", "c:(1,1.25),(1.5,1.75)", "c:(2,2.25),(2.5,2.75)", ] assert arr["cflt"].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j] assert arr["cdbl"].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j] assert m.create_complex_array(0).dtype == dtype def test_signature(doc): assert ( doc(m.create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" ) def test_scalar_conversion(): n = 3 arrays = [ m.create_rec_simple(n), m.create_rec_packed(n), m.create_rec_nested(n), m.create_enum_array(n), ] funcs = [m.f_simple, m.f_packed, m.f_nested] for i, func in enumerate(funcs): for j, arr in enumerate(arrays): if i == j and i < 2: assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)] else: with pytest.raises(TypeError) as excinfo: func(arr[0]) assert "incompatible function arguments" in str(excinfo.value) def test_vectorize(): n = 3 array = m.create_rec_simple(n) values = m.f_simple_vectorized(array) np.testing.assert_array_equal(values, [0, 10, 20]) array_2 = m.f_simple_pass_thru_vectorized(array) np.testing.assert_array_equal(array, array_2) def test_cls_and_dtype_conversion(simple_dtype): s = m.SimpleStruct() assert s.astuple() == (False, 0, 0.0, 0.0) assert m.SimpleStruct.fromtuple(s.astuple()).astuple() == s.astuple() s.uint_ = 2 assert m.f_simple(s) == 20 # Try as recarray of shape==(1,). s_recarray = np.array([(False, 2, 0.0, 0.0)], dtype=simple_dtype) # Show that this will work for vectorized case. np.testing.assert_array_equal(m.f_simple_vectorized(s_recarray), [20]) # Show as a scalar that inherits from np.generic. s_scalar = s_recarray[0] assert isinstance(s_scalar, np.void) assert m.f_simple(s_scalar) == 20 # Show that an *array* scalar (np.ndarray.shape == ()) does not convert. # More specifically, conversion to SimpleStruct is not implicit. s_recarray_scalar = s_recarray.reshape(()) assert isinstance(s_recarray_scalar, np.ndarray) assert s_recarray_scalar.dtype == simple_dtype with pytest.raises(TypeError) as excinfo: m.f_simple(s_recarray_scalar) assert "incompatible function arguments" in str(excinfo.value) # Explicitly convert to m.SimpleStruct. assert m.f_simple(m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20 # Show that an array of dtype=object does *not* convert. s_array_object = np.array([s]) assert s_array_object.dtype == object with pytest.raises(TypeError) as excinfo: m.f_simple_vectorized(s_array_object) assert "incompatible function arguments" in str(excinfo.value) # Explicitly convert to `np.array(..., dtype=simple_dtype)` s_array = np.array([s.astuple()], dtype=simple_dtype) np.testing.assert_array_equal(m.f_simple_vectorized(s_array), [20]) def test_register_dtype(): with pytest.raises(RuntimeError) as excinfo: m.register_dtype() assert "dtype is already registered" in str(excinfo.value) @pytest.mark.xfail("env.PYPY") def test_str_leak(): from sys import getrefcount fmt = "f4" pytest.gc_collect() start = getrefcount(fmt) d = m.dtype_wrapper(fmt) assert d is np.dtype("f4") del d pytest.gc_collect() assert getrefcount(fmt) == start def test_compare_buffer_info(): assert all(m.compare_buffer_info()) aoflagger-v3.4.0/external/pybind11/tests/test_smart_ptr.py0000644000175000017500000002247214507760431022376 0ustar olesolesimport pytest m = pytest.importorskip("pybind11_tests.smart_ptr") from pybind11_tests import ConstructorStats # noqa: E402 def test_smart_ptr(capture): # Object1 for i, o in enumerate( [m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1 ): assert o.getRefCount() == 1 with capture: m.print_object_1(o) m.print_object_2(o) m.print_object_3(o) m.print_object_4(o) assert capture == f"MyObject1[{i}]\n" * 4 for i, o in enumerate( [m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4 ): print(o) with capture: if not isinstance(o, int): m.print_object_1(o) m.print_object_2(o) m.print_object_3(o) m.print_object_4(o) m.print_myobject1_1(o) m.print_myobject1_2(o) m.print_myobject1_3(o) m.print_myobject1_4(o) times = 4 if isinstance(o, int) else 8 assert capture == f"MyObject1[{i}]\n" * times cstats = ConstructorStats.get(m.MyObject1) assert cstats.alive() == 0 expected_values = [f"MyObject1[{i}]" for i in range(1, 7)] + ["MyObject1[7]"] * 4 assert cstats.values() == expected_values assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Doesn't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 # Object2 for i, o in zip( [8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()] ): print(o) with capture: m.print_myobject2_1(o) m.print_myobject2_2(o) m.print_myobject2_3(o) m.print_myobject2_4(o) assert capture == f"MyObject2[{i}]\n" * 4 cstats = ConstructorStats.get(m.MyObject2) assert cstats.alive() == 1 o = None assert cstats.alive() == 0 assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Doesn't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 # Object3 for i, o in zip( [9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()] ): print(o) with capture: m.print_myobject3_1(o) m.print_myobject3_2(o) m.print_myobject3_3(o) m.print_myobject3_4(o) assert capture == f"MyObject3[{i}]\n" * 4 cstats = ConstructorStats.get(m.MyObject3) assert cstats.alive() == 1 o = None assert cstats.alive() == 0 assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Doesn't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 # Object cstats = ConstructorStats.get(m.Object) assert cstats.alive() == 0 assert cstats.values() == [] assert cstats.default_constructions == 10 assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Doesn't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 # ref<> cstats = m.cstats_ref() assert cstats.alive() == 0 assert cstats.values() == ["from pointer"] * 10 assert cstats.default_constructions == 30 assert cstats.copy_constructions == 12 # assert cstats.move_constructions >= 0 # Doesn't invoke any assert cstats.copy_assignments == 30 assert cstats.move_assignments == 0 def test_smart_ptr_refcounting(): assert m.test_object1_refcounting() def test_unique_nodelete(): o = m.MyObject4(23) assert o.value == 23 cstats = ConstructorStats.get(m.MyObject4) assert cstats.alive() == 1 del o assert cstats.alive() == 1 m.MyObject4.cleanup_all_instances() assert cstats.alive() == 0 def test_unique_nodelete4a(): o = m.MyObject4a(23) assert o.value == 23 cstats = ConstructorStats.get(m.MyObject4a) assert cstats.alive() == 1 del o assert cstats.alive() == 1 m.MyObject4a.cleanup_all_instances() assert cstats.alive() == 0 def test_unique_deleter(): m.MyObject4a(0) o = m.MyObject4b(23) assert o.value == 23 cstats4a = ConstructorStats.get(m.MyObject4a) assert cstats4a.alive() == 2 cstats4b = ConstructorStats.get(m.MyObject4b) assert cstats4b.alive() == 1 del o assert cstats4a.alive() == 1 # Should now only be one leftover assert cstats4b.alive() == 0 # Should be deleted m.MyObject4a.cleanup_all_instances() assert cstats4a.alive() == 0 assert cstats4b.alive() == 0 def test_large_holder(): o = m.MyObject5(5) assert o.value == 5 cstats = ConstructorStats.get(m.MyObject5) assert cstats.alive() == 1 del o assert cstats.alive() == 0 def test_shared_ptr_and_references(): s = m.SharedPtrRef() stats = ConstructorStats.get(m.A) assert stats.alive() == 2 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false) assert stats.alive() == 2 assert s.set_ref(ref) with pytest.raises(RuntimeError) as excinfo: assert s.set_holder(ref) assert "Unable to cast from non-held to held instance" in str(excinfo.value) copy = s.copy # init_holder_helper(holder_ptr=false, owned=true) assert stats.alive() == 3 assert s.set_ref(copy) assert s.set_holder(copy) holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false) assert stats.alive() == 3 assert s.set_ref(holder_ref) assert s.set_holder(holder_ref) holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true) assert stats.alive() == 3 assert s.set_ref(holder_copy) assert s.set_holder(holder_copy) del ref, copy, holder_ref, holder_copy, s assert stats.alive() == 0 def test_shared_ptr_from_this_and_references(): s = m.SharedFromThisRef() stats = ConstructorStats.get(m.B) assert stats.alive() == 2 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) assert stats.alive() == 2 assert s.set_ref(ref) assert s.set_holder( ref ) # std::enable_shared_from_this can create a holder from a reference bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true) assert stats.alive() == 2 assert s.set_ref(bad_wp) with pytest.raises(RuntimeError) as excinfo: assert s.set_holder(bad_wp) assert "Unable to cast from non-held to held instance" in str(excinfo.value) copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false) assert stats.alive() == 3 assert s.set_ref(copy) assert s.set_holder(copy) holder_ref = ( s.holder_ref ) # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) assert stats.alive() == 3 assert s.set_ref(holder_ref) assert s.set_holder(holder_ref) holder_copy = ( s.holder_copy ) # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false) assert stats.alive() == 3 assert s.set_ref(holder_copy) assert s.set_holder(holder_copy) del ref, bad_wp, copy, holder_ref, holder_copy, s assert stats.alive() == 0 z = m.SharedFromThisVirt.get() y = m.SharedFromThisVirt.get() assert y is z def test_move_only_holder(): a = m.TypeWithMoveOnlyHolder.make() b = m.TypeWithMoveOnlyHolder.make_as_object() stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder) assert stats.alive() == 2 del b assert stats.alive() == 1 del a assert stats.alive() == 0 def test_holder_with_addressof_operator(): # this test must not throw exception from c++ a = m.TypeForHolderWithAddressOf.make() a.print_object_1() a.print_object_2() a.print_object_3() a.print_object_4() stats = ConstructorStats.get(m.TypeForHolderWithAddressOf) assert stats.alive() == 1 np = m.TypeForHolderWithAddressOf.make() assert stats.alive() == 2 del a assert stats.alive() == 1 del np assert stats.alive() == 0 b = m.TypeForHolderWithAddressOf.make() c = b assert b.get() is c.get() assert stats.alive() == 1 del b assert stats.alive() == 1 del c assert stats.alive() == 0 def test_move_only_holder_with_addressof_operator(): a = m.TypeForMoveOnlyHolderWithAddressOf.make() a.print_object() stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf) assert stats.alive() == 1 a.value = 42 assert a.value == 42 del a assert stats.alive() == 0 def test_smart_ptr_from_default(): instance = m.HeldByDefaultHolder() with pytest.raises(RuntimeError) as excinfo: m.HeldByDefaultHolder.load_shared_ptr(instance) assert ( "Unable to load a custom holder type from a " "default-holder instance" in str(excinfo.value) ) def test_shared_ptr_gc(): """#187: issue involving std::shared_ptr<> return value policy & garbage collection""" el = m.ElementList() for i in range(10): el.add(m.ElementA(i)) pytest.gc_collect() for i, v in enumerate(el.get()): assert i == v.value() aoflagger-v3.4.0/external/pybind11/tests/CMakeLists.txt0000644000175000017500000005225314507760431021512 0ustar olesoles# CMakeLists.txt -- Build system for the pybind11 test suite # # Copyright (c) 2015 Wenzel Jakob # # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. cmake_minimum_required(VERSION 3.4) # The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.21) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.21) endif() # Only needed for CMake < 3.5 support include(CMakeParseArguments) # Filter out items; print an optional message if any items filtered. This ignores extensions. # # Usage: # pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "") # macro(pybind11_filter_tests LISTNAME) cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN}) set(PYBIND11_FILTER_TESTS_FOUND OFF) # Make a list of the test without any extensions, for easier filtering. set(_TMP_ACTUAL_LIST "${${LISTNAME}};") # enforce ';' at the end to allow matching last item. string(REGEX REPLACE "\\.[^.;]*;" ";" LIST_WITHOUT_EXTENSIONS "${_TMP_ACTUAL_LIST}") foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS) string(REGEX REPLACE "\\.[^.]*$" "" filename_no_ext ${filename}) # Search in the list without extensions. list(FIND LIST_WITHOUT_EXTENSIONS ${filename_no_ext} _FILE_FOUND) if(_FILE_FOUND GREATER -1) list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND}) # And remove from the list with extensions. list(REMOVE_AT LIST_WITHOUT_EXTENSIONS ${_FILE_FOUND} )# And our search list, to ensure it is in sync. set(PYBIND11_FILTER_TESTS_FOUND ON) endif() endforeach() if(PYBIND11_FILTER_TESTS_FOUND AND ARG_MESSAGE) message(STATUS "${ARG_MESSAGE}") endif() endmacro() macro(possibly_uninitialized) foreach(VARNAME ${ARGN}) if(NOT DEFINED "${VARNAME}") set("${VARNAME}" "") endif() endforeach() endmacro() # Function to add additional targets if any of the provided tests are found. # Needles; Specifies the test names to look for. # Additions; Specifies the additional test targets to add when any of the needles are found. macro(tests_extra_targets needles additions) # Add the index for this relation to the index extra targets map. list(LENGTH PYBIND11_TEST_EXTRA_TARGETS PYBIND11_TEST_EXTRA_TARGETS_LEN) list(APPEND PYBIND11_TEST_EXTRA_TARGETS ${PYBIND11_TEST_EXTRA_TARGETS_LEN}) # Add the test names to look for, and the associated test target additions. set(PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${needles}) set(PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${additions}) endmacro() # New Python support if(DEFINED Python_EXECUTABLE) set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}") set(PYTHON_VERSION "${Python_VERSION}") endif() # There's no harm in including a project in a project project(pybind11_tests CXX) # Access FindCatch and more list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools") option(PYBIND11_WERROR "Report all warnings as errors" OFF) option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF) option(PYBIND11_CUDA_TESTS "Enable building CUDA tests (requires CMake 3.12+)" OFF) set(PYBIND11_TEST_OVERRIDE "" CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests") set(PYBIND11_TEST_FILTER "" CACHE STRING "Tests from ;-separated list of *.cpp files will be removed from all tests") if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) # We're being loaded directly, i.e. not via add_subdirectory, so make this # work as its own project and load the pybind11Config to get the tools we need find_package(pybind11 REQUIRED CONFIG) endif() if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting tests build type to MinSizeRel as none was specified") set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() if(PYBIND11_CUDA_TESTS) enable_language(CUDA) if(DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD}) endif() set(CMAKE_CUDA_STANDARD_REQUIRED ON) endif() # Full set of test files (you can override these; see below, overrides ignore extension) # Any test that has no extension is both .py and .cpp, so 'foo' will add 'foo.cpp' and 'foo.py'. # Any test that has an extension is exclusively that and handled as such. set(PYBIND11_TEST_FILES test_async test_buffers test_builtin_casters test_call_policies test_callbacks test_chrono test_class test_const_name test_constants_and_functions test_copy_move test_custom_type_casters test_custom_type_setup test_docstring_options test_eigen_matrix test_eigen_tensor test_enum test_eval test_exceptions test_factory_constructors test_gil_scoped test_iostream test_kwargs_and_defaults test_local_bindings test_methods_and_attributes test_modules test_multiple_inheritance test_numpy_array test_numpy_dtypes test_numpy_vectorize test_opaque_types test_operator_overloading test_pickling test_pytypes test_sequences_and_iterators test_smart_ptr test_stl test_stl_binders test_tagbased_polymorphic test_thread test_union test_virtual_functions) # Invoking cmake with something like: # cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" .. # lets you override the tests that get compiled and run. You can restore to all tests with: # cmake -DPYBIND11_TEST_OVERRIDE= .. if(PYBIND11_TEST_OVERRIDE) # Instead of doing a direct override here, we iterate over the overrides without extension and # match them against entries from the PYBIND11_TEST_FILES, anything that not matches goes into the filter list. string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_OVERRIDE_NO_EXT "${PYBIND11_TEST_OVERRIDE};") string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_FILES_NO_EXT "${PYBIND11_TEST_FILES};") # This allows the override to be done with extensions, preserving backwards compatibility. foreach(test_name ${TEST_FILES_NO_EXT}) if(NOT ${test_name} IN_LIST TEST_OVERRIDE_NO_EXT )# If not in the allowlist, add to be filtered out. list(APPEND PYBIND11_TEST_FILTER ${test_name}) endif() endforeach() endif() # You can also filter tests: if(PYBIND11_TEST_FILTER) pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER}) endif() # Skip tests for CUDA check: # /pybind11/tests/test_constants_and_functions.cpp(125): # error: incompatible exception specifications if(PYBIND11_CUDA_TESTS) pybind11_filter_tests( PYBIND11_TEST_FILES test_constants_and_functions.cpp MESSAGE "Skipping test_constants_and_functions due to incompatible exception specifications") endif() # Now that the test filtering is complete, we need to split the list into the test for PYTEST # and the list for the cpp targets. set(PYBIND11_CPPTEST_FILES "") set(PYBIND11_PYTEST_FILES "") foreach(test_name ${PYBIND11_TEST_FILES}) if(test_name MATCHES "\\.py$") # Ends in .py, purely python test. list(APPEND PYBIND11_PYTEST_FILES ${test_name}) elseif(test_name MATCHES "\\.cpp$") # Ends in .cpp, purely cpp test. list(APPEND PYBIND11_CPPTEST_FILES ${test_name}) elseif(NOT test_name MATCHES "\\.") # No extension specified, assume both, add extension. list(APPEND PYBIND11_PYTEST_FILES ${test_name}.py) list(APPEND PYBIND11_CPPTEST_FILES ${test_name}.cpp) else() message(WARNING "Unhanded test extension in test: ${test_name}") endif() endforeach() set(PYBIND11_TEST_FILES ${PYBIND11_CPPTEST_FILES}) list(SORT PYBIND11_PYTEST_FILES) # Contains the set of test files that require pybind11_cross_module_tests to be # built; if none of these are built (i.e. because TEST_OVERRIDE is used and # doesn't include them) the second module doesn't get built. tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_stl_binders.py" "pybind11_cross_module_tests") # And add additional targets for other tests. tests_extra_targets("test_exceptions.py" "cross_module_interleaved_error_already_set") tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils") set(PYBIND11_EIGEN_REPO "https://gitlab.com/libeigen/eigen.git" CACHE STRING "Eigen repository to use for tests") # Always use a hash for reconfigure speed and security reasons # Include the version number for pretty printing (keep in sync) set(PYBIND11_EIGEN_VERSION_AND_HASH "3.4.0;929bc0e191d0927b1735b9a1ddc0e8b77e3a25ec" CACHE STRING "Eigen version to use for tests, format: VERSION;HASH") list(GET PYBIND11_EIGEN_VERSION_AND_HASH 0 PYBIND11_EIGEN_VERSION_STRING) list(GET PYBIND11_EIGEN_VERSION_AND_HASH 1 PYBIND11_EIGEN_VERSION_HASH) # Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but # keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed" # skip message). list(FIND PYBIND11_TEST_FILES test_eigen_matrix.cpp PYBIND11_TEST_FILES_EIGEN_I) if(PYBIND11_TEST_FILES_EIGEN_I EQUAL -1) list(FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I) endif() if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake). # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also # produces a fatal error if loaded from a pre-3.0 cmake. if(DOWNLOAD_EIGEN) if(CMAKE_VERSION VERSION_LESS 3.11) message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN") endif() include(FetchContent) FetchContent_Declare( eigen GIT_REPOSITORY "${PYBIND11_EIGEN_REPO}" GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}") FetchContent_GetProperties(eigen) if(NOT eigen_POPULATED) message( STATUS "Downloading Eigen ${PYBIND11_EIGEN_VERSION_STRING} (${PYBIND11_EIGEN_VERSION_HASH}) from ${PYBIND11_EIGEN_REPO}" ) FetchContent_Populate(eigen) endif() set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR}) set(EIGEN3_FOUND TRUE) # When getting locally, the version is not visible from a superprojet, # so just force it. set(EIGEN3_VERSION "${PYBIND11_EIGEN_VERSION_STRING}") else() find_package(Eigen3 3.2.7 QUIET CONFIG) if(NOT EIGEN3_FOUND) # Couldn't load via target, so fall back to allowing module mode finding, which will pick up # tools/FindEigen3.cmake find_package(Eigen3 3.2.7 QUIET) endif() endif() if(EIGEN3_FOUND) if(NOT TARGET Eigen3::Eigen) add_library(Eigen3::Eigen IMPORTED INTERFACE) set_property(TARGET Eigen3::Eigen PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${EIGEN3_INCLUDE_DIR}") endif() # Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed # rather than looking it up in the cmake script); older versions, and the # tools/FindEigen3.cmake, set EIGEN3_VERSION instead. if(NOT EIGEN3_VERSION AND EIGEN3_VERSION_STRING) set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING}) endif() message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}") if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)) tests_extra_targets("test_eigen_tensor.py" "eigen_tensor_avoid_stl_array") endif() else() list(FIND PYBIND11_TEST_FILES test_eigen_matrix.cpp PYBIND11_TEST_FILES_EIGEN_I) if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I}) endif() list(FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I) if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I}) endif() message( STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download") endif() endif() # Some code doesn't support gcc 4 if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) list(FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I) if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I}) endif() endif() # Optional dependency for some tests (boost::variant is only supported with version >= 1.56) find_package(Boost 1.56) if(Boost_FOUND) if(NOT TARGET Boost::headers) add_library(Boost::headers IMPORTED INTERFACE) if(TARGET Boost::boost) # Classic FindBoost set_property(TARGET Boost::boost PROPERTY INTERFACE_LINK_LIBRARIES Boost::boost) else() # Very old FindBoost, or newer Boost than CMake in older CMakes set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) endif() endif() endif() # Check if we need to add -lstdc++fs or -lc++fs or nothing if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 17) set(STD_FS_NO_LIB_NEEDED TRUE) elseif(MSVC) set(STD_FS_NO_LIB_NEEDED TRUE) else() file( WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp "#include \nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}" ) try_compile( STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR} SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp COMPILE_DEFINITIONS -std=c++17) try_compile( STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR} SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp COMPILE_DEFINITIONS -std=c++17 LINK_LIBRARIES stdc++fs) try_compile( STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR} SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp COMPILE_DEFINITIONS -std=c++17 LINK_LIBRARIES c++fs) endif() if(${STD_FS_NEEDS_STDCXXFS}) set(STD_FS_LIB stdc++fs) elseif(${STD_FS_NEEDS_CXXFS}) set(STD_FS_LIB c++fs) elseif(${STD_FS_NO_LIB_NEEDED}) set(STD_FS_LIB "") else() message(WARNING "Unknown C++17 compiler - not passing -lstdc++fs") set(STD_FS_LIB "") endif() # Compile with compiler warnings turned on function(pybind11_enable_warnings target_name) if(MSVC) target_compile_options(${target_name} PRIVATE /W4 /wd4189) elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS) target_compile_options( ${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated -Wundef -Wnon-virtual-dtor) endif() if(PYBIND11_WERROR) if(MSVC) target_compile_options(${target_name} PRIVATE /WX) elseif(PYBIND11_CUDA_TESTS) target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings") elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang|IntelLLVM)") target_compile_options(${target_name} PRIVATE -Werror) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") if(CMAKE_CXX_STANDARD EQUAL 17) # See PR #3570 target_compile_options(${target_name} PRIVATE -Wno-conversion) endif() target_compile_options( ${target_name} PRIVATE -Werror-all # "Inlining inhibited by limit max-size", "Inlining inhibited by limit max-total-size" -diag-disable 11074,11076) endif() endif() endfunction() set(test_targets pybind11_tests) # Check if any tests need extra targets by iterating through the mappings registered. foreach(i ${PYBIND11_TEST_EXTRA_TARGETS}) foreach(needle ${PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${i}}) if(needle IN_LIST PYBIND11_PYTEST_FILES) # Add all the additional targets to the test list. List join in newer cmake. foreach(extra_target ${PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${i}}) list(APPEND test_targets ${extra_target}) endforeach() break() # Breaks out of the needle search, continues with the next mapping. endif() endforeach() endforeach() # Support CUDA testing by forcing the target file to compile with NVCC if(PYBIND11_CUDA_TESTS) set_property(SOURCE ${PYBIND11_TEST_FILES} PROPERTY LANGUAGE CUDA) endif() foreach(target ${test_targets}) set(test_files ${PYBIND11_TEST_FILES}) if(NOT "${target}" STREQUAL "pybind11_tests") set(test_files "") endif() # Support CUDA testing by forcing the target file to compile with NVCC if(PYBIND11_CUDA_TESTS) set_property(SOURCE ${target}.cpp PROPERTY LANGUAGE CUDA) endif() # Create the binding library pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS}) pybind11_enable_warnings(${target}) if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) get_property( suffix TARGET ${target} PROPERTY SUFFIX) set(source_output "${CMAKE_CURRENT_SOURCE_DIR}/${target}${suffix}") if(suffix AND EXISTS "${source_output}") message(WARNING "Output file also in source directory; " "please remove to avoid confusion: ${source_output}") endif() endif() if(MSVC) target_compile_options(${target} PRIVATE /utf-8) endif() if(EIGEN3_FOUND) target_link_libraries(${target} PRIVATE Eigen3::Eigen) target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN) endif() if(Boost_FOUND) target_link_libraries(${target} PRIVATE Boost::headers) target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST) endif() target_link_libraries(${target} PRIVATE ${STD_FS_LIB}) # Always write the output file directly into the 'tests' directory (even on MSVC) if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") if(DEFINED CMAKE_CONFIGURATION_TYPES) foreach(config ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${config} config) set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} "${CMAKE_CURRENT_BINARY_DIR}") endforeach() endif() endif() endforeach() # Provide nice organisation in IDEs if(NOT CMAKE_VERSION VERSION_LESS 3.8) source_group( TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include" PREFIX "Header Files" FILES ${PYBIND11_HEADERS}) endif() # Make sure pytest is found or produce a warning pybind11_find_import(pytest VERSION 3.1) if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) # This is not used later in the build, so it's okay to regenerate each time. configure_file("${CMAKE_CURRENT_SOURCE_DIR}/pytest.ini" "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini" COPYONLY) file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini" "\ntestpaths = \"${CMAKE_CURRENT_SOURCE_DIR}\"") endif() # cmake 3.12 added list(transform prepend # but we can't use it yet string(REPLACE "test_" "${CMAKE_CURRENT_SOURCE_DIR}/test_" PYBIND11_ABS_PYTEST_FILES "${PYBIND11_PYTEST_FILES}") set(PYBIND11_TEST_PREFIX_COMMAND "" CACHE STRING "Put this before pytest, use for checkers and such") # A single command to compile and run the tests add_custom_target( pytest COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES} DEPENDS ${test_targets} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" USES_TERMINAL) if(PYBIND11_TEST_OVERRIDE) add_custom_command( TARGET pytest POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect") endif() # cmake-format: off add_custom_target( memcheck COMMAND PYTHONMALLOC=malloc valgrind --leak-check=full --show-leak-kinds=definite,indirect --errors-for-leak-kinds=definite,indirect --error-exitcode=1 --read-var-info=yes --track-origins=yes --suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-python.supp" --suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-numpy-scipy.supp" --gen-suppressions=all ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES} DEPENDS ${test_targets} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" USES_TERMINAL) # cmake-format: on # Add a check target to run all the tests, starting with pytest (we add dependencies to this below) add_custom_target(check DEPENDS pytest) # The remaining tests only apply when being built as part of the pybind11 project, but not if the # tests are being built independently. if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) return() endif() # Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it: add_custom_command( TARGET pybind11_tests POST_BUILD COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../tools/libsize.py $ ${CMAKE_CURRENT_BINARY_DIR}/sosize-$.txt) if(NOT PYBIND11_CUDA_TESTS) # Test embedding the interpreter. Provides the `cpptest` target. add_subdirectory(test_embed) # Test CMake build using functions and targets from subdirectory or installed location add_subdirectory(test_cmake_build) endif() aoflagger-v3.4.0/external/pybind11/tests/test_operator_overloading.cpp0000644000175000017500000002165414507760431024742 0ustar olesoles/* tests/test_operator_overloading.cpp -- operator overloading Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include "constructor_stats.h" #include "pybind11_tests.h" #include class Vector2 { public: Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); } Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); } Vector2(Vector2 &&v) noexcept : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; } Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; } Vector2 &operator=(Vector2 &&v) noexcept { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; } ~Vector2() { print_destroyed(this); } std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } Vector2 operator-() const { return Vector2(-x, -y); } Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); } Vector2 operator-(float value) const { return Vector2(x - value, y - value); } Vector2 operator+(float value) const { return Vector2(x + value, y + value); } Vector2 operator*(float value) const { return Vector2(x * value, y * value); } Vector2 operator/(float value) const { return Vector2(x / value, y / value); } Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); } Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); } Vector2 &operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } Vector2 &operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; } Vector2 &operator*=(float v) { x *= v; y *= v; return *this; } Vector2 &operator/=(float v) { x /= v; y /= v; return *this; } Vector2 &operator*=(const Vector2 &v) { x *= v.x; y *= v.y; return *this; } Vector2 &operator/=(const Vector2 &v) { x /= v.x; y /= v.y; return *this; } friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); } friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); } friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); } bool operator==(const Vector2 &v) const { return x == v.x && y == v.y; } bool operator!=(const Vector2 &v) const { return x != v.x || y != v.y; } private: float x, y; }; class C1 {}; class C2 {}; int operator+(const C1 &, const C1 &) { return 11; } int operator+(const C2 &, const C2 &) { return 22; } int operator+(const C2 &, const C1 &) { return 21; } int operator+(const C1 &, const C2 &) { return 12; } struct HashMe { std::string member; }; bool operator==(const HashMe &lhs, const HashMe &rhs) { return lhs.member == rhs.member; } // Note: Specializing explicit within `namespace std { ... }` is done due to a // bug in GCC<7. If you are supporting compilers later than this, consider // specializing `using template<> struct std::hash<...>` in the global // namespace instead, per this recommendation: // https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations namespace std { template <> struct hash { // Not a good hash function, but easy to test size_t operator()(const Vector2 &) { return 4; } }; // HashMe has a hash function in C++ but no `__hash__` for Python. template <> struct hash { std::size_t operator()(const HashMe &selector) const { return std::hash()(selector.member); } }; } // namespace std // Not a good abs function, but easy to test. std::string abs(const Vector2 &) { return "abs(Vector2)"; } // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `). // Here, we suppress the warning // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46 // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`). #if defined(__APPLE__) && defined(__clang__) # if (__clang_major__ >= 10) PYBIND11_WARNING_DISABLE_CLANG("-Wself-assign-overloaded") # endif #elif defined(__clang__) # if (__clang_major__ >= 7) PYBIND11_WARNING_DISABLE_CLANG("-Wself-assign-overloaded") # endif #endif TEST_SUBMODULE(operators, m) { // test_operator_overloading py::class_(m, "Vector2") .def(py::init()) .def(py::self + py::self) .def(py::self + float()) .def(py::self - py::self) .def(py::self - float()) .def(py::self * float()) .def(py::self / float()) .def(py::self * py::self) .def(py::self / py::self) .def(py::self += py::self) .def(py::self -= py::self) .def(py::self *= float()) .def(py::self /= float()) .def(py::self *= py::self) .def(py::self /= py::self) .def(float() + py::self) .def(float() - py::self) .def(float() * py::self) .def(float() / py::self) .def(-py::self) .def("__str__", &Vector2::toString) .def("__repr__", &Vector2::toString) .def(py::self == py::self) .def(py::self != py::self) .def(py::hash(py::self)) // N.B. See warning about usage of `py::detail::abs(py::self)` in // `operators.h`. .def("__abs__", [](const Vector2 &v) { return abs(v); }); m.attr("Vector") = m.attr("Vector2"); // test_operators_notimplemented // #393: need to return NotSupported to ensure correct arithmetic operator behavior py::class_(m, "C1").def(py::init<>()).def(py::self + py::self); py::class_(m, "C2") .def(py::init<>()) .def(py::self + py::self) .def("__add__", [](const C2 &c2, const C1 &c1) { return c2 + c1; }) .def("__radd__", [](const C2 &c2, const C1 &c1) { return c1 + c2; }); // test_nested // #328: first member in a class can't be used in operators struct NestABase { int value = -2; }; py::class_(m, "NestABase") .def(py::init<>()) .def_readwrite("value", &NestABase::value); struct NestA : NestABase { int value = 3; NestA &operator+=(int i) { value += i; return *this; } }; py::class_(m, "NestA") .def(py::init<>()) .def(py::self += int()) .def( "as_base", [](NestA &a) -> NestABase & { return (NestABase &) a; }, py::return_value_policy::reference_internal); m.def("get_NestA", [](const NestA &a) { return a.value; }); struct NestB { NestA a; int value = 4; NestB &operator-=(int i) { value -= i; return *this; } }; py::class_(m, "NestB") .def(py::init<>()) .def(py::self -= int()) .def_readwrite("a", &NestB::a); m.def("get_NestB", [](const NestB &b) { return b.value; }); struct NestC { NestB b; int value = 5; NestC &operator*=(int i) { value *= i; return *this; } }; py::class_(m, "NestC") .def(py::init<>()) .def(py::self *= int()) .def_readwrite("b", &NestC::b); m.def("get_NestC", [](const NestC &c) { return c.value; }); // test_overriding_eq_reset_hash // #2191 Overriding __eq__ should set __hash__ to None struct Comparable { int value; bool operator==(const Comparable &rhs) const { return value == rhs.value; } }; struct Hashable : Comparable { explicit Hashable(int value) : Comparable{value} {}; size_t hash() const { return static_cast(value); } }; struct Hashable2 : Hashable { using Hashable::Hashable; }; py::class_(m, "Comparable").def(py::init()).def(py::self == py::self); py::class_(m, "Hashable") .def(py::init()) .def(py::self == py::self) .def("__hash__", &Hashable::hash); // define __hash__ before __eq__ py::class_(m, "Hashable2") .def("__hash__", &Hashable::hash) .def(py::init()) .def(py::self == py::self); // define __eq__ but not __hash__ py::class_(m, "HashMe").def(py::self == py::self); m.def("get_unhashable_HashMe_set", []() { return std::unordered_set{{"one"}}; }); } aoflagger-v3.4.0/external/pybind11/tests/test_stl.cpp0000644000175000017500000005212314507760431021313 0ustar olesoles/* tests/test_stl.cpp -- STL type casters Copyright (c) 2017 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include "constructor_stats.h" #include "pybind11_tests.h" #ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL # define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL #endif #include #include #include #if defined(PYBIND11_TEST_BOOST) # include namespace PYBIND11_NAMESPACE { namespace detail { template struct type_caster> : optional_caster> {}; template <> struct type_caster : void_caster {}; } // namespace detail } // namespace PYBIND11_NAMESPACE #endif // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 #if defined(PYBIND11_HAS_VARIANT) using std::variant; # define PYBIND11_TEST_VARIANT 1 #elif defined(PYBIND11_TEST_BOOST) # include # define PYBIND11_TEST_VARIANT 1 using boost::variant; namespace PYBIND11_NAMESPACE { namespace detail { template struct type_caster> : variant_caster> {}; template <> struct visit_helper { template static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) { return boost::apply_visitor(args...); } }; } // namespace detail } // namespace PYBIND11_NAMESPACE #endif PYBIND11_MAKE_OPAQUE(std::vector>); /// Issue #528: templated constructor struct TplCtorClass { template explicit TplCtorClass(const T &) {} bool operator==(const TplCtorClass &) const { return true; } }; namespace std { template <> struct hash { size_t operator()(const TplCtorClass &) const { return 0; } }; } // namespace std template