ContiguousMS::ContiguousMS(const string& msPath, const std::string& dataColumnName, const MSSelection& selection, PolarizationEnum polOut, size_t dataDescId) : _timestep(0), _time(0.0), _dataDescId(dataDescId), _isModelColumnPrepared(false), _selection(selection), _polOut(polOut), _msPath(msPath), _ms(msPath), _antenna1Column(_ms, casacore::MS::columnName(casacore::MSMainEnums::ANTENNA1)), _antenna2Column(_ms, casacore::MS::columnName(casacore::MSMainEnums::ANTENNA2)), _fieldIdColumn(_ms, casacore::MS::columnName(casacore::MSMainEnums::FIELD_ID)), _dataDescIdColumn(_ms, casacore::MS::columnName(casacore::MSMainEnums::DATA_DESC_ID)), _timeColumn(_ms, casacore::MS::columnName(casacore::MSMainEnums::TIME)), _uvwColumn(_ms, casacore::MS::columnName(casacore::MSMainEnums::UVW)), _dataColumnName(dataColumnName), _dataColumn(_ms, dataColumnName), _flagColumn(_ms, casacore::MS::columnName(casacore::MSMainEnums::FLAG)) { Logger::Info << "Opening " << msPath << ", spw " << _dataDescId << " with contiguous MS reader.\n"; _inputPolarizations = GetMSPolarizations(_ms); const casacore::IPosition shape(_dataColumn.shape(0)); _dataArray = casacore::Array<std::complex<float>>(shape); _weightSpectrumArray = casacore::Array<float>(shape); _imagingWeightSpectrumArray = casacore::Array<float>(shape); _flagArray = casacore::Array<bool>(shape); _bandData = MultiBandData(_ms.spectralWindow(), _ms.dataDescription()); _msHasWeightSpectrum = openWeightSpectrumColumn(_ms, _weightSpectrumColumn, shape); if(!_msHasWeightSpectrum) { casacore::IPosition scalarShape(1, shape[0]); _weightScalarArray = casacore::Array<float>(scalarShape); _weightScalarColumn.reset(new casacore::ROArrayColumn<float>(_ms, casacore::MS::columnName(casacore::MSMainEnums::WEIGHT))); } getRowRangeAndIDMap(_ms, selection, _startRow, _endRow, std::set<size_t>{dataDescId}, _idToMSRow); Reset(); }
void WSMSGridder::initializeMeasurementSet(size_t msIndex, WSMSGridder::MSData& msData) { MSProvider& msProvider = MeasurementSet(msIndex); msData.msProvider = &msProvider; casacore::MeasurementSet& ms(msProvider.MS()); if(ms.nrow() == 0) throw std::runtime_error("Table has no rows (no data)"); /** * Read some meta data from the measurement set */ casacore::MSAntenna aTable = ms.antenna(); size_t antennaCount = aTable.nrow(); if(antennaCount == 0) throw std::runtime_error("No antennae in set"); casacore::MPosition::ROScalarColumn antPosColumn(aTable, aTable.columnName(casacore::MSAntennaEnums::POSITION)); casacore::MPosition ant1Pos = antPosColumn(0); msData.bandData = MultiBandData(ms.spectralWindow(), ms.dataDescription()); if(Selection(msIndex).HasChannelRange()) { msData.startChannel = Selection(msIndex).ChannelRangeStart(); msData.endChannel = Selection(msIndex).ChannelRangeEnd(); std::cout << "Selected channels: " << msData.startChannel << '-' << msData.endChannel << '\n'; const BandData& firstBand = msData.bandData.FirstBand(); if(msData.startChannel >= firstBand.ChannelCount() || msData.endChannel > firstBand.ChannelCount() || msData.startChannel == msData.endChannel) { std::ostringstream str; str << "An invalid channel range was specified! Measurement set only has " << firstBand.ChannelCount() << " channels, requested imaging range is " << msData.startChannel << " -- " << msData.endChannel << '.'; throw std::runtime_error(str.str()); } } else { msData.startChannel = 0; msData.endChannel = msData.bandData.FirstBand().ChannelCount(); } casacore::MEpoch::ROScalarColumn timeColumn(ms, ms.columnName(casacore::MSMainEnums::TIME)); const MultiBandData selectedBand = msData.SelectedBand(); if(_hasFrequencies) { _freqLow = std::min(_freqLow, selectedBand.LowestFrequency()); _freqHigh = std::max(_freqHigh, selectedBand.HighestFrequency()); _bandStart = std::min(_bandStart, selectedBand.BandStart()); _bandEnd = std::max(_bandEnd, selectedBand.BandEnd()); _startTime = std::min(_startTime, msProvider.StartTime()); } else { _freqLow = selectedBand.LowestFrequency(); _freqHigh = selectedBand.HighestFrequency(); _bandStart = selectedBand.BandStart(); _bandEnd = selectedBand.BandEnd(); _startTime = msProvider.StartTime(); _hasFrequencies = true; } casacore::MSField fTable(ms.field()); casacore::MDirection::ROScalarColumn phaseDirColumn(fTable, fTable.columnName(casacore::MSFieldEnums::PHASE_DIR)); casacore::MDirection phaseDir = phaseDirColumn(Selection(msIndex).FieldId()); casacore::MEpoch curtime = timeColumn(0); casacore::MeasFrame frame(ant1Pos, curtime); casacore::MDirection::Ref j2000Ref(casacore::MDirection::J2000, frame); casacore::MDirection j2000 = casacore::MDirection::Convert(phaseDir, j2000Ref)(); casacore::Vector<casacore::Double> j2000Val = j2000.getValue().get(); _phaseCentreRA = j2000Val[0]; _phaseCentreDec = j2000Val[1]; if(fTable.keywordSet().isDefined("WSCLEAN_DL")) _phaseCentreDL = fTable.keywordSet().asDouble(casacore::RecordFieldId("WSCLEAN_DL")); else _phaseCentreDL = 0.0; if(fTable.keywordSet().isDefined("WSCLEAN_DM")) _phaseCentreDM = fTable.keywordSet().asDouble(casacore::RecordFieldId("WSCLEAN_DM")); else _phaseCentreDM = 0.0; _denormalPhaseCentre = _phaseCentreDL != 0.0 || _phaseCentreDM != 0.0; if(_denormalPhaseCentre) std::cout << "Set has denormal phase centre: dl=" << _phaseCentreDL << ", dm=" << _phaseCentreDM << '\n'; std::cout << "Determining min and max w & theoretical beam size... " << std::flush; msData.maxW = 0.0; msData.minW = 1e100; double maxBaseline = 0.0; std::vector<float> weightArray(selectedBand.MaxChannels()); msProvider.Reset(); while(msProvider.CurrentRowAvailable()) { size_t dataDescId; double uInM, vInM, wInM; msProvider.ReadMeta(uInM, vInM, wInM, dataDescId); const BandData& curBand = selectedBand[dataDescId]; double wHi = fabs(wInM / curBand.SmallestWavelength()); double wLo = fabs(wInM / curBand.LongestWavelength()); double baselineInM = sqrt(uInM*uInM + vInM*vInM + wInM*wInM); double halfWidth = 0.5*ImageWidth(), halfHeight = 0.5*ImageHeight(); if(wHi > msData.maxW || wLo < msData.minW || baselineInM / curBand.SmallestWavelength() > maxBaseline) { msProvider.ReadWeights(weightArray.data()); const float* weightPtr = weightArray.data(); for(size_t ch=0; ch!=curBand.ChannelCount(); ++ch) { if(*weightPtr != 0.0) { const double wavelength = curBand.ChannelWavelength(ch); double uInL = uInM/wavelength, vInL = vInM/wavelength, wInL = wInM/wavelength, x = uInL * PixelSizeX() * ImageWidth(), y = vInL * PixelSizeY() * ImageHeight(), imagingWeight = this->PrecalculatedWeightInfo()->GetWeight(uInL, vInL); if(imagingWeight != 0.0) { if(floor(x) > -halfWidth && ceil(x) < halfWidth && floor(y) > -halfHeight && ceil(y) < halfHeight) { msData.maxW = std::max(msData.maxW, fabs(wInL)); msData.minW = std::min(msData.minW, fabs(wInL)); maxBaseline = std::max(maxBaseline, baselineInM / wavelength); } } } ++weightPtr; } } msProvider.NextRow(); } if(msData.minW == 1e100) { msData.minW = 0.0; msData.maxW = 0.0; } _beamSize = 1.0 / maxBaseline; std::cout << "DONE (w=[" << msData.minW << ":" << msData.maxW << "] lambdas, maxuvw=" << maxBaseline << " lambda, beam=" << Angle::ToNiceString(_beamSize) << ")\n"; if(HasWLimit()) { msData.maxW *= (1.0 - WLimit()); if(msData.maxW < msData.minW) msData.maxW = msData.minW; } _actualInversionWidth = ImageWidth(); _actualInversionHeight = ImageHeight(); _actualPixelSizeX = PixelSizeX(); _actualPixelSizeY = PixelSizeY(); if(SmallInversion()) { double totalWidth = _actualInversionWidth * _actualPixelSizeX, totalHeight = _actualInversionHeight * _actualPixelSizeY; // Calc min res based on Nyquist sampling rate size_t minResX = size_t(ceil(totalWidth*2 / _beamSize)); if(minResX%4 != 0) minResX += 4 - (minResX%4); size_t minResY = size_t(ceil(totalHeight*2 / _beamSize)); if(minResY%4 != 0) minResY += 4 - (minResY%4); if(minResX < _actualInversionWidth || minResY < _actualInversionHeight) { _actualInversionWidth = std::max(std::min(minResX, _actualInversionWidth), size_t(32)); _actualInversionHeight = std::max(std::min(minResY, _actualInversionHeight), size_t(32)); std::cout << "Setting small inversion image size of " << _actualInversionWidth << " x " << _actualInversionHeight << "\n"; _actualPixelSizeX = totalWidth / _actualInversionWidth; _actualPixelSizeY = totalHeight / _actualInversionHeight; } else { std::cout << "Small inversion enabled, but inversion resolution already smaller than beam size: not using optimization.\n"; } } if(Verbose() || !HasWGridSize()) { double maxL = ImageWidth() * PixelSizeX() * 0.5 + fabs(_phaseCentreDL), maxM = ImageHeight() * PixelSizeY() * 0.5 + fabs(_phaseCentreDM), lmSq = maxL * maxL + maxM * maxM; double cMinW = IsComplex() ? -msData.maxW : msData.minW; double radiansForAllLayers; if(lmSq < 1.0) radiansForAllLayers = 2 * M_PI * (msData.maxW - cMinW) * (1.0 - sqrt(1.0 - lmSq)); else radiansForAllLayers = 2 * M_PI * (msData.maxW - cMinW); size_t suggestedGridSize = size_t(ceil(radiansForAllLayers)); if(suggestedGridSize == 0) suggestedGridSize = 1; if(suggestedGridSize < _cpuCount) { // When nwlayers is lower than the nr of cores, we cannot parallellize well. // However, we don't want extra w-layers if we are low on mem, as that might slow down the process double memoryRequired = double(_cpuCount) * double(sizeof(double))*double(_actualInversionWidth*_actualInversionHeight); if(4.0 * memoryRequired < double(_memSize)) { std::cout << "The theoretically suggested number of w-layers (" << suggestedGridSize << ") is less than the number of availables\n" "cores (" << _cpuCount << "). Changing suggested number of w-layers to " << _cpuCount << ".\n"; suggestedGridSize = _cpuCount; } else { std::cout << "The theoretically suggested number of w-layers (" << suggestedGridSize << ") is less than the number of availables\n" "cores (" << _cpuCount << "), but there is not enough memory available to increase the number of w-layers.\n" "Not all cores can be used efficiently.\n"; } } if(Verbose()) std::cout << "Suggested number of w-layers: " << ceil(suggestedGridSize) << '\n'; if(!HasWGridSize()) SetWGridSize(suggestedGridSize); } }