//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ #ifndef vtk_m_filter_MIRFilter_hxx #define vtk_m_filter_MIRFilter_hxx #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace vtkm { /* Todos: Enable some sort of cell culling, so if a cell doesn't have any work to do, it doesn't get called in future invocations of MIR */ namespace filter { template inline VTKM_CONT void MIRFilter::ProcessPointField( const vtkm::cont::ArrayHandle& input, vtkm::cont::ArrayHandle& output) { vtkm::worklet::DestructPointWeightList destructWeightList; this->Invoke(destructWeightList, this->MIRIDs, this->MIRWeights, input, output); } //----------------------------------------------------------------------------- template inline VTKM_CONT vtkm::cont::DataSet MIRFilter::DoExecute( const vtkm::cont::DataSet& input, vtkm::filter::PolicyBase policy) { //{ //(void)input; //(void)policy; vtkm::worklet::CheckFor2D cellCheck; vtkm::cont::ArrayHandle count2D, count3D, countBad; this->Invoke(cellCheck, vtkm::filter::ApplyPolicyCellSet(input.GetCellSet(), policy, *this), count2D, count3D, countBad); vtkm::Id c2 = vtkm::cont::Algorithm::Reduce(count2D, vtkm::Id(0)); vtkm::Id c3 = vtkm::cont::Algorithm::Reduce(count3D, vtkm::Id(0)); vtkm::Id cB = vtkm::cont::Algorithm::Reduce(countBad, vtkm::Id(0)); if (cB > vtkm::Id(0)) { VTKM_LOG_S( vtkm::cont::LogLevel::Fatal, "Bad cell found in MIR filter input! Strictly only 2D -xor- 3D cell sets are permitted!"); } if (c2 > vtkm::Id(0) && c3 > vtkm::Id(0)) { VTKM_LOG_S( vtkm::cont::LogLevel::Fatal, "Bad cell mix found in MIR filter input! Input is not allowed to have both 2D and 3D cells."); } if (c2 == vtkm::Id(0) && c3 == vtkm::Id(0)) { VTKM_LOG_S(vtkm::cont::LogLevel::Fatal, "No cells found for MIR filter! Please don't call me with nothing!"); } const vtkm::cont::CoordinateSystem inputCoords = input.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex()); vtkm::cont::ArrayHandle avgSizeTot; vtkm::worklet::MeshQuality getVol; getVol.SetMetric(c3 > 0 ? vtkm::filter::CellMetric::VOLUME : vtkm::filter::CellMetric::AREA); this->Invoke(getVol, vtkm::filter::ApplyPolicyCellSet(input.GetCellSet(), policy, *this), inputCoords.GetData(), avgSizeTot); // First, load up all fields... vtkm::cont::Field or_pos = input.GetField(this->pos_name); vtkm::cont::Field or_len = input.GetField(this->len_name); vtkm::cont::Field or_ids = input.GetField(this->id_name); vtkm::cont::Field or_vfs = input.GetField(this->vf_name); // TODO: Check all fields for 'IsFieldCell' vtkm::cont::ArrayHandle vfsdata_or, vfsdata; vtkm::cont::ArrayHandle idsdata_or, idsdata, lendata_or, lendata, posdata_or, posdata, allids; or_pos.GetData().AsArrayHandle(posdata_or); or_len.GetData().AsArrayHandle(lendata_or); or_ids.GetData().AsArrayHandle(idsdata_or); or_vfs.GetData().AsArrayHandle(vfsdata_or); vtkm::cont::ArrayCopy(idsdata_or, allids); vtkm::cont::Algorithm::Sort(allids); vtkm::cont::Algorithm::Unique(allids); vtkm::IdComponent numIDs = static_cast(allids.GetNumberOfValues()); //using PortalConstType = vtkm::cont::ArrayHandle::PortalConstControl; //PortalConstType readPortal = allids.GetPortalConstControl(); using PortalConstType = vtkm::cont::ArrayHandle::ReadPortalType; PortalConstType readPortal = allids.ReadPortal(); vtkm::cont::ArrayCopy(idsdata_or, idsdata); vtkm::cont::ArrayCopy(lendata_or, lendata); vtkm::cont::ArrayCopy(posdata_or, posdata); vtkm::cont::ArrayCopy(vfsdata_or, vfsdata); //} vtkm::cont::DataSet saved; // % error of the whole system, multiplied by the number of cells vtkm::Float64 totalError = this->max_error + vtkm::Float64(1.1); // Dummy value vtkm::IdComponent currentIterationNum = 0; vtkm::worklet::MIRCases::MIRTables faceTableArray; vtkm::cont::ArrayHandle> pointWeights; vtkm::cont::ArrayHandle> pointIDs; vtkm::worklet::ConstructCellWeightList constructReverseInformation; vtkm::cont::ArrayHandleIndex pointCounter(input.GetNumberOfPoints()); this->Invoke(constructReverseInformation, pointCounter, pointIDs, pointWeights); do { saved = vtkm::cont::DataSet(); saved.AddCoordinateSystem(inputCoords); saved.SetCellSet(input.GetCellSet()); vtkm::cont::ArrayHandle currentcellIDs; vtkm::cont::ArrayHandle pointlen, pointpos, pointid; vtkm::cont::ArrayHandle pointvf; vtkm::worklet::CombineVFsForPoints_C convertOrigCellTo; vtkm::worklet::CombineVFsForPoints convertOrigCellTo_Full; this->Invoke(convertOrigCellTo, saved.GetCellSet(), lendata, posdata, idsdata, pointlen); vtkm::Id pointcount = vtkm::cont::Algorithm::ScanExclusive(pointlen, pointpos); pointvf.Allocate(pointcount); pointid.Allocate(pointcount); this->Invoke(convertOrigCellTo_Full, saved.GetCellSet(), lendata, posdata, idsdata, vfsdata, pointpos, pointid, pointvf); vtkm::worklet::MIRObject mirobj( pointlen, pointpos, pointid, pointvf); // This is point VF data... vtkm::cont::ArrayHandle prevMat; vtkm::cont::ArrayCopy( vtkm::cont::make_ArrayHandleConstant(-1, saved.GetCellSet().GetNumberOfCells()), prevMat); vtkm::cont::ArrayHandle cellLookback; vtkm::cont::ArrayHandleIndex tmp_ind(saved.GetCellSet().GetNumberOfCells()); vtkm::cont::ArrayCopy(tmp_ind, cellLookback); vtkm::IdComponent currentMatLoc = 0; while (currentMatLoc < numIDs) { vtkm::IdComponent currentMatID = static_cast(readPortal.Get(currentMatLoc++)); if (currentMatID < 1) { VTKM_LOG_S( vtkm::cont::LogLevel::Fatal, "MIR filter does not accept materials with an non-positive ID! Material id in offense: " << currentMatID << ". Please remap all ID values to only positive numbers to avoid this issue."); } // First go through and pick out the previous and current material VFs for each cell. //{ vtkm::worklet::ExtractVFsForMIR_C extractCurrentMatVF; vtkm::cont::ArrayHandle currentCellPointCounts; this->Invoke(extractCurrentMatVF, saved.GetCellSet(), currentCellPointCounts); vtkm::worklet::ExtractVFsForMIR extractCurrentMatVF_SC(currentMatID); vtkm::worklet::ScatterCounting extractCurrentMatVF_SC_scatter = extractCurrentMatVF_SC.MakeScatter(currentCellPointCounts); vtkm::cont::ArrayHandle currentMatVF; vtkm::cont::ArrayHandle previousMatVF; this->Invoke(extractCurrentMatVF_SC, extractCurrentMatVF_SC_scatter, saved.GetCellSet(), mirobj, prevMat, currentMatVF, previousMatVF); //} // Next see if we need to perform any work at all... if (currentMatLoc != 0) { // Run MIR, possibly changing colors... vtkm::cont::ArrayHandle cellVFPointOffsets; vtkm::cont::Algorithm::ScanExclusive(currentCellPointCounts, cellVFPointOffsets); vtkm::worklet::MIR mir; vtkm::cont::ArrayHandle newCellLookback, newCellID; vtkm::cont::CellSetExplicit<> out = mir.Run(saved.GetCellSet(), previousMatVF, currentMatVF, cellVFPointOffsets, prevMat, currentMatID, cellLookback, newCellID, newCellLookback); vtkm::cont::ArrayCopy(newCellLookback, cellLookback); vtkm::cont::ArrayCopy(newCellID, prevMat); auto data = saved.GetCoordinateSystem(0).GetDataAsMultiplexer(); auto coords = mir.ProcessPointField(data); // Now convert the point VFs... vtkm::cont::ArrayHandle plen, ppos, pids; vtkm::cont::ArrayHandle pvf; mir.ProcessMIRField(mirobj.getPointLenArr(), mirobj.getPointPosArr(), mirobj.getPointIDArr(), mirobj.getPointVFArr(), plen, ppos, pids, pvf); vtkm::cont::ArrayHandle> tmppointWeights; vtkm::cont::ArrayHandle> tmppointIDs; mir.ProcessSimpleMIRField(pointIDs, pointWeights, tmppointIDs, tmppointWeights); vtkm::cont::ArrayCopy(tmppointIDs, pointIDs); vtkm::cont::ArrayCopy(tmppointWeights, pointWeights); //FileSaver fs; //fs(("pID" + std::to_string(currentMatID) + ".txt").c_str(), pointIDs); //fs(("wID" + std::to_string(currentMatID) + ".txt").c_str(), pointWeights); mirobj = vtkm::worklet::MIRObject(plen, ppos, pids, pvf); saved = vtkm::cont::DataSet(); saved.SetCellSet(out); vtkm::cont::CoordinateSystem outCo2(inputCoords.GetName(), coords); saved.AddCoordinateSystem(outCo2); } } // Hacking workaround to not clone an entire dataset. vtkm::cont::ArrayHandle avgSize; this->Invoke(getVol, saved.GetCellSet(), saved.GetCoordinateSystem(0).GetData(), avgSize); vtkm::worklet::CalcError_C calcErrC; vtkm::worklet::Keys cellKeys(cellLookback); vtkm::cont::ArrayCopy(cellLookback, filterCellInterp); vtkm::cont::ArrayHandle lenOut, posOut, idsOut; vtkm::cont::ArrayHandle vfsOut, totalErrorOut; lenOut.Allocate(cellKeys.GetUniqueKeys().GetNumberOfValues()); this->Invoke(calcErrC, cellKeys, prevMat, lendata_or, posdata_or, idsdata_or, lenOut); vtkm::Id numIDsOut = vtkm::cont::Algorithm::ScanExclusive(lenOut, posOut); idsOut.Allocate(numIDsOut); vfsOut.Allocate(numIDsOut); vtkm::worklet::CalcError calcErr(this->error_scaling); this->Invoke(calcErr, cellKeys, prevMat, avgSize, lendata_or, posdata_or, idsdata_or, vfsdata_or, lendata, posdata, idsdata, vfsdata, lenOut, posOut, idsOut, vfsOut, avgSizeTot, totalErrorOut); totalError = vtkm::cont::Algorithm::Reduce(totalErrorOut, vtkm::Float64(0)); vtkm::cont::ArrayCopy(lenOut, lendata); vtkm::cont::ArrayCopy(posOut, posdata); vtkm::cont::ArrayCopy(idsOut, idsdata); vtkm::cont::ArrayCopy(vfsOut, vfsdata); // Clean up the cells by calculating their volumes, and then calculate the relative error for each cell. // Note that the total error needs to be rescaled by the number of cells to get the % error. totalError = totalError / vtkm::Float64( vtkm::filter::ApplyPolicyCellSet(input.GetCellSet(), policy, *this).GetNumberOfCells()); this->error_scaling *= this->scaling_decay; VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Mir iteration " << currentIterationNum + 1 << "/" << this->max_iter << "\t Total error: " << totalError); saved.AddField(vtkm::cont::Field( this->GetOutputFieldName(), vtkm::cont::Field::Association::CELL_SET, prevMat)); vtkm::cont::ArrayCopy(pointIDs, this->MIRIDs); vtkm::cont::ArrayCopy(pointWeights, this->MIRWeights); } while ((++currentIterationNum <= this->max_iter) && totalError >= this->max_error); return saved; } } } #endif