void MinusMD::doMinus(typename MDEventWorkspace<MDE, nd>::sptr ws) { typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws; typename MDEventWorkspace<MDE, nd>::sptr ws2 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(m_operand_event); if (!ws1 || !ws2) throw std::runtime_error("Incompatible workspace types passed to MinusMD."); MDBoxBase<MDE, nd> *box1 = ws1->getBox(); MDBoxBase<MDE, nd> *box2 = ws2->getBox(); Progress prog(this, 0.0, 0.4, box2->getBoxController()->getTotalNumMDBoxes()); // How many events you started with size_t initial_numEvents = ws1->getNPoints(); // Make a leaf-only iterator through all boxes with events in the RHS // workspace MDBoxIterator<MDE, nd> it2(box2, 1000, true); do { MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(it2.getBox()); if (box) { // Copy the events from WS2 and add them into WS1 const std::vector<MDE> &events = box->getConstEvents(); // Perform a copy while flipping the signal std::vector<MDE> eventsCopy; eventsCopy.reserve(events.size()); for (auto it = events.begin(); it != events.end(); it++) { MDE eventCopy(*it); eventCopy.setSignal(-eventCopy.getSignal()); eventsCopy.push_back(eventCopy); } // Add events, with bounds checking box1->addEvents(eventsCopy); box->releaseEvents(); } prog.report("Substracting Events"); } while (it2.next()); this->progress(0.41, "Splitting Boxes"); Progress *prog2 = new Progress(this, 0.4, 0.9, 100); ThreadScheduler *ts = new ThreadSchedulerFIFO(); ThreadPool tp(ts, 0, prog2); ws1->splitAllIfNeeded(ts); prog2->resetNumSteps(ts->size(), 0.4, 0.6); tp.joinAll(); this->progress(0.95, "Refreshing cache"); ws1->refreshCache(); // Set a marker that the file-back-end needs updating if the # of events // changed. if (ws1->getNPoints() != initial_numEvents) ws1->setFileNeedsUpdating(true); }
void addDetectors(DataObjects::Peak &peak, MDBoxBase<MDE, nd> &box, const boost::true_type &) { if (box.getNumChildren() > 0) { std::cerr << "Box has children\n"; addDetectors(peak, box, boost::true_type()); } MDBox<MDE, nd> *mdBox = dynamic_cast<MDBox<MDE, nd> *>(&box); if (!mdBox) { throw std::invalid_argument("FindPeaksMD::addDetectors - Unexpected Box " "type, cannot retrieve events"); } const auto &events = mdBox->getConstEvents(); auto itend = events.end(); for (auto it = events.begin(); it != itend; ++it) { peak.addContributingDetID(it->getDetectorID()); } }
void SliceMD::slice(typename MDEventWorkspace<MDE, nd>::sptr ws) { // Create the ouput workspace typename MDEventWorkspace<OMDE, ond>::sptr outWS( new MDEventWorkspace<OMDE, ond>()); for (size_t od = 0; od < m_binDimensions.size(); od++) { outWS->addDimension(m_binDimensions[od]); } outWS->setCoordinateSystem(ws->getSpecialCoordinateSystem()); outWS->initialize(); // Copy settings from the original box controller BoxController_sptr bc = ws->getBoxController(); // store wrute buffer size for the future // uint64_t writeBufSize = // bc->getFileIO()getDiskBuffer().getWriteBufferSize(); // and disable write buffer (if any) for input MD Events for this algorithm // purposes; // bc->setCacheParameters(1,0); BoxController_sptr obc = outWS->getBoxController(); // Use the "number of bins" as the "split into" parameter for (size_t od = 0; od < m_binDimensions.size(); od++) obc->setSplitInto(od, m_binDimensions[od]->getNBins()); obc->setSplitThreshold(bc->getSplitThreshold()); bool bTakeDepthFromInputWorkspace = getProperty("TakeMaxRecursionDepthFromInput"); int tempDepth = getProperty("MaxRecursionDepth"); size_t maxDepth = bTakeDepthFromInputWorkspace ? bc->getMaxDepth() : size_t(tempDepth); obc->setMaxDepth(maxDepth); // size_t outputSize = writeBufSize; // obc->setCacheParameters(sizeof(OMDE),outputSize); obc->resetNumBoxes(); // Perform the first box splitting outWS->splitBox(); size_t lastNumBoxes = obc->getTotalNumMDBoxes(); // --- File back end ? ---------------- std::string filename = getProperty("OutputFilename"); if (!filename.empty()) { // First save to the NXS file g_log.notice() << "Running SaveMD to create file back-end" << std::endl; IAlgorithm_sptr alg = createChildAlgorithm("SaveMD"); alg->setPropertyValue("Filename", filename); alg->setProperty("InputWorkspace", outWS); alg->setProperty("MakeFileBacked", true); alg->executeAsChildAlg(); if (!obc->isFileBacked()) throw std::runtime_error("SliceMD with file-backed output: Can not set " "up file-backed output workspace "); auto IOptr = obc->getFileIO(); size_t outBufSize = IOptr->getWriteBufferSize(); // the buffer size for resulting workspace; reasonable size is at least 10 // data chunk sizes (nice to verify) if (outBufSize < 10 * IOptr->getDataChunk()) { outBufSize = 10 * IOptr->getDataChunk(); IOptr->setWriteBufferSize(outBufSize); } } // Function defining which events (in the input dimensions) to place in the // output MDImplicitFunction *function = this->getImplicitFunctionForChunk(NULL, NULL); std::vector<API::IMDNode *> boxes; // Leaf-only; no depth limit; with the implicit function passed to it. ws->getBox()->getBoxes(boxes, 1000, true, function); // Sort boxes by file position IF file backed. This reduces seeking time, // hopefully. bool fileBackedWS = bc->isFileBacked(); if (fileBackedWS) API::IMDNode::sortObjByID(boxes); Progress *prog = new Progress(this, 0.0, 1.0, boxes.size()); // The root of the output workspace MDBoxBase<OMDE, ond> *outRootBox = outWS->getBox(); // if target workspace has events, we should count them as added uint64_t totalAdded = outWS->getNEvents(); uint64_t numSinceSplit = 0; // Go through every box for this chunk. // PARALLEL_FOR_IF( !bc->isFileBacked() ) for (int i = 0; i < int(boxes.size()); i++) { MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(boxes[i]); // Perform the binning in this separate method. if (box) { // An array to hold the rotated/transformed coordinates coord_t outCenter[ond]; const std::vector<MDE> &events = box->getConstEvents(); typename std::vector<MDE>::const_iterator it = events.begin(); typename std::vector<MDE>::const_iterator it_end = events.end(); for (; it != it_end; it++) { // Cache the center of the event (again for speed) const coord_t *inCenter = it->getCenter(); if (function->isPointContained(inCenter)) { // Now transform to the output dimensions m_transformFromOriginal->apply(inCenter, outCenter); // Create the event OMDE newEvent(it->getSignal(), it->getErrorSquared(), outCenter); // Copy extra data, if any copyEvent(*it, newEvent); // Add it to the workspace outRootBox->addEvent(newEvent); numSinceSplit++; } } box->releaseEvents(); // Ask BC if one needs to split boxes if (obc->shouldSplitBoxes(totalAdded, numSinceSplit, lastNumBoxes)) // if (numSinceSplit > 20000000 || (i == int(boxes.size()-1))) { // This splits up all the boxes according to split thresholds and sizes. Kernel::ThreadScheduler *ts = new ThreadSchedulerFIFO(); ThreadPool tp(ts); outWS->splitAllIfNeeded(ts); tp.joinAll(); // Accumulate stats totalAdded += numSinceSplit; numSinceSplit = 0; lastNumBoxes = obc->getTotalNumMDBoxes(); // Progress reporting if (!fileBackedWS) prog->report(i); } if (fileBackedWS) { if (!(i % 10)) prog->report(i); } } // is box } // for each box in the vector prog->report(); outWS->splitAllIfNeeded(NULL); // Refresh all cache. outWS->refreshCache(); g_log.notice() << totalAdded << " " << OMDE::getTypeName() << "'s added to the output workspace." << std::endl; if (outWS->isFileBacked()) { // Update the file-back-end g_log.notice() << "Running SaveMD" << std::endl; IAlgorithm_sptr alg = createChildAlgorithm("SaveMD"); alg->setProperty("UpdateFileBackEnd", true); alg->setProperty("InputWorkspace", outWS); alg->executeAsChildAlg(); } // return the size of the input workspace write buffer to its initial value // bc->setCacheParameters(sizeof(MDE),writeBufSize); this->setProperty("OutputWorkspace", boost::dynamic_pointer_cast<IMDEventWorkspace>(outWS)); delete prog; }
void BinMD::binByIterating(typename MDEventWorkspace<MDE, nd>::sptr ws) { BoxController_sptr bc = ws->getBoxController(); // store exisiting write buffer size for the future // uint64_t writeBufSize =bc->getDiskBuffer().getWriteBufferSize(); // and disable write buffer (if any) for input MD Events for this algorithm // purposes; // bc->setCacheParameters(1,0); // Cache some data to speed up accessing them a bit indexMultiplier = new size_t[m_outD]; for (size_t d = 0; d < m_outD; d++) { if (d > 0) indexMultiplier[d] = outWS->getIndexMultiplier()[d - 1]; else indexMultiplier[d] = 1; } signals = outWS->getSignalArray(); errors = outWS->getErrorSquaredArray(); numEvents = outWS->getNumEventsArray(); // Start with signal/error/numEvents at 0.0 outWS->setTo(0.0, 0.0, 0.0); // The dimension (in the output workspace) along which we chunk for parallel // processing // TODO: Find the smartest dimension to chunk against size_t chunkDimension = 0; // How many bins (in that dimension) per chunk. // Try to split it so each core will get 2 tasks: int chunkNumBins = int(m_binDimensions[chunkDimension]->getNBins() / (PARALLEL_GET_MAX_THREADS * 2)); if (chunkNumBins < 1) chunkNumBins = 1; // Do we actually do it in parallel? bool doParallel = getProperty("Parallel"); // Not if file-backed! if (bc->isFileBacked()) doParallel = false; if (!doParallel) chunkNumBins = int(m_binDimensions[chunkDimension]->getNBins()); // Total number of steps size_t progNumSteps = 0; if (prog) prog->setNotifyStep(0.1); if (prog) prog->resetNumSteps(100, 0.00, 1.0); // Run the chunks in parallel. There is no overlap in the output workspace so // it is thread safe to write to it.. // cppcheck-suppress syntaxError PRAGMA_OMP( parallel for schedule(dynamic,1) if (doParallel) ) for (int chunk = 0; chunk < int(m_binDimensions[chunkDimension]->getNBins()); chunk += chunkNumBins) { PARALLEL_START_INTERUPT_REGION // Region of interest for this chunk. std::vector<size_t> chunkMin(m_outD); std::vector<size_t> chunkMax(m_outD); for (size_t bd = 0; bd < m_outD; bd++) { // Same limits in the other dimensions chunkMin[bd] = 0; chunkMax[bd] = m_binDimensions[bd]->getNBins(); } // Parcel out a chunk in that single dimension dimension chunkMin[chunkDimension] = size_t(chunk); if (size_t(chunk + chunkNumBins) > m_binDimensions[chunkDimension]->getNBins()) chunkMax[chunkDimension] = m_binDimensions[chunkDimension]->getNBins(); else chunkMax[chunkDimension] = size_t(chunk + chunkNumBins); // Build an implicit function (it needs to be in the space of the // MDEventWorkspace) MDImplicitFunction *function = this->getImplicitFunctionForChunk(chunkMin.data(), chunkMax.data()); // Use getBoxes() to get an array with a pointer to each box std::vector<API::IMDNode *> boxes; // Leaf-only; no depth limit; with the implicit function passed to it. ws->getBox()->getBoxes(boxes, 1000, true, function); // Sort boxes by file position IF file backed. This reduces seeking time, // hopefully. if (bc->isFileBacked()) API::IMDNode::sortObjByID(boxes); // For progress reporting, the # of boxes if (prog) { PARALLEL_CRITICAL(BinMD_progress) { g_log.debug() << "Chunk " << chunk << ": found " << boxes.size() << " boxes within the implicit function.\n"; progNumSteps += boxes.size(); prog->setNumSteps(progNumSteps); } } // Go through every box for this chunk. for (auto &boxe : boxes) { MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(boxe); // Perform the binning in this separate method. if (box && !box->getIsMasked()) this->binMDBox(box, chunkMin.data(), chunkMax.data()); // Progress reporting if (prog) prog->report(); // For early cancelling of the loop if (this->m_cancel) break; } // for each box in the vector PARALLEL_END_INTERUPT_REGION } // for each chunk in parallel PARALLEL_CHECK_INTERUPT_REGION // Now the implicit function if (implicitFunction) { if (prog) prog->report("Applying implicit function."); signal_t nan = std::numeric_limits<signal_t>::quiet_NaN(); outWS->applyImplicitFunction(implicitFunction, nan, nan); } // return the size of the input workspace write buffer to its initial value // bc->setCacheParameters(sizeof(MDE),writeBufSize); }
void PlusMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws) { typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws; typename MDEventWorkspace<MDE, nd>::sptr ws2 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(m_operand_event); if (!ws1 || !ws2) throw std::runtime_error("Incompatible workspace types passed to PlusMD."); MDBoxBase<MDE, nd> *box1 = ws1->getBox(); MDBoxBase<MDE, nd> *box2 = ws2->getBox(); Progress prog(this, 0.0, 0.4, box2->getBoxController()->getTotalNumMDBoxes()); // How many events you started with size_t initial_numEvents = ws1->getNPoints(); // Make a leaf-only iterator through all boxes with events in the RHS // workspace // TODO: OMP MDBoxIterator<MDE, nd> it2(box2, 1000, true); do { MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(it2.getBox()); if (box) { // Copy the events from WS2 and add them into WS1 const std::vector<MDE> &events = box->getConstEvents(); // Add events, with bounds checking box1->addEvents(events); box->releaseEvents(); } prog.report("Adding Events"); } while (it2.next()); this->progress(0.41, "Splitting Boxes"); Progress *prog2 = new Progress(this, 0.4, 0.9, 100); ThreadScheduler *ts = new ThreadSchedulerFIFO(); ThreadPool tp(ts, 0, prog2); ws1->splitAllIfNeeded(ts); prog2->resetNumSteps(ts->size(), 0.4, 0.6); tp.joinAll(); //// Now we need to save all the data that was not saved before. // if (ws1->isFileBacked()) //{ // // flusush disk kernel buffer and save all still in memory // ws1->getBoxController()->getFileIO()->flushCache(); // // Flush the data writes to disk from nexus IO buffer // ws1->getBoxController()->getFileIO()->flushData(); //} // if(ws2->isFileBacked()) //{ // // flusush disk kernel buffer and save all still in memory // ws2->getBoxController()->getFileIO()->flushCache(); // // Flush the data writes to disk from nexus IO buffer // ws2->getBoxController()->getFileIO()->flushData(); // //// Flush anything else in the to-write buffer // //BoxController_sptr bc = ws1->getBoxController(); // //prog.resetNumSteps(bc->getTotalNumMDBoxes(), 0.6, 1.0); // //MDBoxIterator<MDE,nd> it1(box1, 1000, true); // //while (true) // //{ // // MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(it1.getBox()); // // if (box) // // { // // // Something was maybe added to this box // // if (box->getEventVectorSize() > 0) // // { // // // By getting the events, this will merge the newly added and the // cached events. // // box->getEvents(); // // // The MRU to-write cache will optimize writes by reducing seek // times // // box->releaseEvents(); // // } // // } // // prog.report("Saving"); // // if (!it1.next()) break; // //} // //bc->getDiskBuffer().flushCache(); //} this->progress(0.95, "Refreshing cache"); ws1->refreshCache(); // Set a marker that the file-back-end needs updating if the # of events // changed. if (ws1->getNPoints() != initial_numEvents) ws1->setFileNeedsUpdating(true); }
/** Add MDEvents to MDEventWorkspace from data set in the experiment * Run number is determined by the row of the file in the input table workspace * @brief ConvertCWSDExpToMomentum::addMDEvents * @param usevirtual :: flag to use virtual instrument */ void ConvertCWSDExpToMomentum::addMDEvents(bool usevirtual) { MatrixWorkspace_sptr spicews; // Check whether to add / or \ to m_dataDir std::string sep(""); if (m_dataDir.size() > 0) { // Determine system #if _WIN64 const bool isWindows = true; #elif _WIN32 const bool isWindows = true; #else const bool isWindows = false; #endif if (isWindows && *m_dataDir.rbegin() != '\\') { sep = "\\"; } else if (!isWindows && *m_dataDir.rbegin() != '/') sep = "/"; } // Init some variables size_t numrows = m_expDataTableWS->rowCount(); if (numrows > 1 && !usevirtual) { g_log.warning("There are more than 1 experiment to import. " "Make sure that all of them have the same instrument."); } size_t numFileNotLoaded(0); // Loop through all data files in the experiment for (size_t ir = 0; ir < numrows; ++ir) { std::string rawfilename = m_expDataTableWS->cell<std::string>(ir, m_iColFilename); detid_t start_detid = 0; if (usevirtual) start_detid = m_expDataTableWS->cell<detid_t>(ir, m_iColStartDetID); // Load data bool loaded; std::string errmsg; std::stringstream filess; if (m_isBaseName) { filess << m_dataDir << sep; } filess << rawfilename; std::string filename(filess.str()); spicews = loadSpiceData(filename, loaded, errmsg); if (!loaded) { g_log.error(errmsg); ++numFileNotLoaded; continue; } // Convert from MatrixWorkspace to MDEvents and add events to int runid = static_cast<int>(ir) + 1; if (!usevirtual) start_detid = 0; convertSpiceMatrixToMomentumMDEvents(spicews, usevirtual, start_detid, runid); } // Set box extentes // typename std::vector<API::IMDNode *> boxes; std::vector<API::IMDNode *> boxes; // Set extents for all MDBoxes progress(0.90, "Set up MDBoxes' dimensions. "); m_outputWS->getBoxes(boxes, 1000, true); auto it1 = boxes.begin(); auto it1_end = boxes.end(); for (; it1 != it1_end; it1++) { auto box = *it1; for (size_t dim = 0; dim < 3; ++dim) { MDBox<MDEvent<3>, 3> *mdbox = dynamic_cast<DataObjects::MDBox<MDEvent<3>, 3> *>(box); if (!mdbox) throw std::runtime_error("Unable to cast to MDBox"); mdbox->setExtents(dim, -10, 10); mdbox->calcVolume(); mdbox->refreshCache(nullptr); } } return; }
void vtkSplatterPlotFactory::doCreate(typename MDEventWorkspace<MDE, nd>::sptr ws) const { bool VERBOSE = true; CPUTimer tim; // Acquire a scoped read-only lock to the workspace (prevent segfault // from algos modifying ws) ReadLock lock(*ws); // Find out how many events to plot, and the percentage of the largest // boxes to use. size_t totalPoints = ws->getNPoints(); size_t numPoints = m_numPoints; if (numPoints > totalPoints) { numPoints = totalPoints; } double percent_to_use = m_percentToUse; // Fail safe limits on fraction of boxes to use if (percent_to_use <= 0) { percent_to_use = 5; } if (percent_to_use > 100) { percent_to_use = 100; } // First we get all the boxes, up to the given depth; with or wo the // slice function std::vector<API::IMDNode *> boxes; if (this->slice) { ws->getBox()->getBoxes(boxes, 1000, true, this->sliceImplicitFunction); } else { ws->getBox()->getBoxes(boxes, 1000, true); } if (VERBOSE) { std::cout << tim << " to retrieve the "<< boxes.size() << " boxes down."<< std::endl; } std::string new_name = ws->getName(); if (new_name != m_wsName || m_buildSortedList) { m_wsName = new_name; m_buildSortedList = false; m_sortedBoxes.clear(); // get list of boxes with signal > 0 and sort // the list in order of decreasing signal for (size_t i = 0; i < boxes.size(); i++) { MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(boxes[i]); if (box) { size_t newPoints = box->getNPoints(); if (newPoints > 0) { m_sortedBoxes.push_back(box); } } } if (VERBOSE) { std::cout << "START SORTING" << std::endl; } std::sort(m_sortedBoxes.begin(), m_sortedBoxes.end(), CompareNormalizedSignal); if (VERBOSE) { std::cout << "DONE SORTING" << std::endl; } } size_t num_boxes_to_use = static_cast<size_t>(percent_to_use * static_cast<double>(m_sortedBoxes.size()) / 100.0); if (num_boxes_to_use >= m_sortedBoxes.size()) { num_boxes_to_use = m_sortedBoxes.size()-1; } // restrict the number of points to the // number of points in boxes being used size_t total_points_available = 0; for (size_t i = 0; i < num_boxes_to_use; i++) { size_t newPoints = m_sortedBoxes[i]->getNPoints(); total_points_available += newPoints; } if (numPoints > total_points_available) { numPoints = total_points_available; } size_t points_per_box = 0; // calculate the average number of points to use per box if (num_boxes_to_use > 0) { points_per_box = numPoints / num_boxes_to_use; } if (points_per_box < 1) { points_per_box = 1; } if (VERBOSE) { std::cout << "numPoints = " << numPoints << std::endl; std::cout << "num boxes in all = " << boxes.size() << std::endl; std::cout << "num boxes above zero = " << m_sortedBoxes.size() << std::endl; std::cout << "num boxes to use = " << num_boxes_to_use << std::endl; std::cout << "total_points_available = " << total_points_available << std::endl; std::cout << "points needed per box = " << points_per_box << std::endl; } // First save the events and signals that we actually use. // For each box, get up to the average number of points // we want from each box, limited by the number of points // in the box. NOTE: since boxes have different numbers // of events, we will not get all the events requested. // Also, if we are using a smaller number of points, we // won't get points from some of the boxes with lower signal. std::vector<float> saved_signals; std::vector<const coord_t*> saved_centers; std::vector<size_t> saved_n_points_in_cell; saved_signals.reserve(numPoints); saved_centers.reserve(numPoints); saved_n_points_in_cell.reserve(numPoints); size_t pointIndex = 0; size_t box_index = 0; bool done = false; while (box_index < num_boxes_to_use && !done) { MDBox<MDE,nd> *box = dynamic_cast<MDBox<MDE,nd> *>(m_sortedBoxes[box_index]); box_index++; if (NULL == box) { continue; } float signal_normalized = static_cast<float>(box->getSignalNormalized()); size_t newPoints = box->getNPoints(); size_t num_from_this_box = points_per_box; if (num_from_this_box > newPoints) { num_from_this_box = newPoints; } const std::vector<MDE> & events = box->getConstEvents(); size_t startPointIndex = pointIndex; size_t event_index = 0; while (event_index < num_from_this_box && !done) { const MDE & ev = events[event_index]; event_index++; const coord_t * center = ev.getCenter(); // Save location saved_centers.push_back(center); pointIndex++; if (pointIndex >= numPoints) { done = true; } } box->releaseEvents(); // Save signal saved_signals.push_back(signal_normalized); // Save cell size saved_n_points_in_cell.push_back(pointIndex-startPointIndex); } numPoints = saved_centers.size(); size_t numCells = saved_signals.size(); if (VERBOSE) { std::cout << "Recorded data for all points" << std::endl; std::cout << "numPoints = " << numPoints << std::endl; std::cout << "numCells = " << numCells << std::endl; } // Create the point list, one position for each point actually used vtkPoints *points = vtkPoints::New(); points->Allocate(numPoints); points->SetNumberOfPoints(numPoints); // The list of IDs of points used, one ID per point, since points // are not reused to form polygon facets, etc. vtkIdType *ids = new vtkIdType[numPoints]; // Only one scalar for each cell, NOT one per point vtkFloatArray *signal = vtkFloatArray::New(); signal->Allocate(numCells); signal->SetName(m_scalarName.c_str()); // Create the data set. Need space for each cell, not for each point vtkUnstructuredGrid *visualDataSet = vtkUnstructuredGrid::New(); this->dataSet = visualDataSet; visualDataSet->Allocate(numCells); // Now copy the saved point, cell and signal info into vtk data structures pointIndex = 0; for (size_t cell_i = 0; cell_i < numCells; cell_i++) { size_t startPointIndex = pointIndex; for (size_t point_i = 0; point_i < saved_n_points_in_cell[cell_i]; point_i++) { points->SetPoint(pointIndex, saved_centers[pointIndex]); ids[pointIndex] = pointIndex; pointIndex++; } signal->InsertNextTuple1(saved_signals[cell_i]); visualDataSet->InsertNextCell(VTK_POLY_VERTEX, saved_n_points_in_cell[cell_i], ids+startPointIndex); } if (VERBOSE) { std::cout << tim << " to create " << pointIndex << " points." << std::endl; } // Shrink to fit //points->Squeeze(); signal->Squeeze(); visualDataSet->Squeeze(); // Add points and scalars visualDataSet->SetPoints(points); visualDataSet->GetCellData()->SetScalars(signal); delete [] ids; }