Commit 7666295d authored by Alexander Stukowski's avatar Alexander Stukowski

Removed the ComputeEngineResults class from AsynchronousModifier. Compute…

Removed the ComputeEngineResults class from AsynchronousModifier. Compute results are now stored in the ComputeEngine object.
parent 44f56563
Pipeline #25794971 failed with stage
in 9 minutes and 37 seconds
......@@ -47,11 +47,11 @@ Future<PipelineFlowState> AsynchronousModifier::evaluate(TimePoint time, Modifie
{
// Check if there are existing computation results stored in the ModifierApplication that can be re-used.
if(AsynchronousModifierApplication* asyncModApp = dynamic_object_cast<AsynchronousModifierApplication>(modApp)) {
const AsynchronousModifier::ComputeEngineResultsPtr& lastResults = asyncModApp->lastComputeResults();
const AsynchronousModifier::ComputeEnginePtr& lastResults = asyncModApp->lastComputeResults();
if(lastResults && lastResults->validityInterval().contains(time)) {
// Re-use the computation results and apply them to the input data.
UndoSuspender noUndo(this);
PipelineFlowState resultState = lastResults->apply(time, modApp, input);
PipelineFlowState resultState = lastResults->emitResults(time, modApp, input);
resultState.mutableStateValidity().intersect(lastResults->validityInterval());
return resultState;
}
......@@ -59,27 +59,27 @@ Future<PipelineFlowState> AsynchronousModifier::evaluate(TimePoint time, Modifie
// Let the subclass create the computation engine based on the input data.
Future<ComputeEnginePtr> engineFuture = createEngine(time, modApp, input);
return engineFuture.then(executor(), [this, time, input = input, modApp = QPointer<ModifierApplication>(modApp)](const ComputeEnginePtr& engine) mutable {
return engineFuture.then(executor(), [this, time, input = input, modApp = QPointer<ModifierApplication>(modApp)](ComputeEnginePtr engine) mutable {
// Execute the engine in a worker thread.
// Collect results from the engine in the UI thread once it has finished running.
return dataset()->container()->taskManager().runTaskAsync(engine)
.then(executor(), [this, time, modApp, input = std::move(input)](const ComputeEngineResultsPtr& results) mutable {
return dataset()->container()->taskManager().runTaskAsync(engine->task())
.then(executor(), [this, time, modApp, input = std::move(input), engine = std::move(engine)]() mutable {
if(modApp && modApp->modifier() == this) {
// Keep a copy of the results in the ModifierApplication for later.
if(AsynchronousModifierApplication* asyncModApp = dynamic_object_cast<AsynchronousModifierApplication>(modApp.data())) {
TimeInterval iv = results->validityInterval();
TimeInterval iv = engine->validityInterval();
iv.intersect(input.stateValidity());
results->setValidityInterval(iv);
asyncModApp->setLastComputeResults(results);
engine->setValidityInterval(iv);
asyncModApp->setLastComputeResults(engine);
}
UndoSuspender noUndo(this);
// Apply the computed results to the input data.
PipelineFlowState resultState = results->apply(time, modApp, input);
resultState.mutableStateValidity().intersect(results->validityInterval());
PipelineFlowState resultState = engine->emitResults(time, modApp, input);
resultState.mutableStateValidity().intersect(engine->validityInterval());
return resultState;
}
else return std::move(input);
......@@ -94,8 +94,8 @@ PipelineFlowState AsynchronousModifier::evaluatePreliminary(TimePoint time, Modi
{
// If results are still available from the last pipeline evaluation, apply them to the input data.
if(AsynchronousModifierApplication* asyncModApp = dynamic_object_cast<AsynchronousModifierApplication>(modApp)) {
if(const AsynchronousModifier::ComputeEngineResultsPtr& lastResults = asyncModApp->lastComputeResults()) {
PipelineFlowState resultState = lastResults->apply(time, modApp, input);
if(const AsynchronousModifier::ComputeEnginePtr& lastResults = asyncModApp->lastComputeResults()) {
PipelineFlowState resultState = lastResults->emitResults(time, modApp, input);
resultState.mutableStateValidity().intersect(lastResults->validityInterval());
return resultState;
}
......@@ -124,19 +124,41 @@ void AsynchronousModifier::loadFromStream(ObjectLoadStream& stream)
stream.closeChunk();
}
#ifdef Q_OS_LINUX
/******************************************************************************
* Destructor of compute engine.
* This method is called by the system after the computation was
* successfully completed.
******************************************************************************/
AsynchronousModifier::ComputeEngine::~ComputeEngine()
void AsynchronousModifier::ComputeEngine::cleanup()
{
// Some compute engines allocate a considerable amount of memory in small chunks,
// which is sometimes not released back to the OS by the C memory allocator.
// This call to malloc_trim() will explicitly trigger an attempt to release free memory
// at the top of the heap.
::malloc_trim(0);
// The asynchronous task object is no longer needed after compute operation is complete.
_task.reset();
}
/******************************************************************************
* Is called when the asynchronous task begins to run.
******************************************************************************/
void AsynchronousModifier::ComputeEngine::ComputeEngineTask::perform()
{
// Let the compute engine do the work.
_engine->perform();
if(!isCanceled()) {
// If compute job was successfully completed, release memory and references to the input data.
_engine->cleanup();
// Make sure the cleanup() method has really cleared the reference to this task object:
OVITO_ASSERT(isCanceled() || !_engine->task());
#ifdef Q_OS_LINUX
// Some compute engines allocate a considerable amount of memory in small chunks,
// which is sometimes not released back to the OS by the C memory allocator.
// This call to malloc_trim() will explicitly trigger an attempt to release free memory
// at the top of the heap.
::malloc_trim(0);
#endif
}
}
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
......
......@@ -39,47 +39,63 @@ class OVITO_CORE_EXPORT AsynchronousModifier : public Modifier
public:
/**
* Base class for data structures holding the results of an asynchronous modifier computation.
* Abstract base class for compute engines.
*/
class OVITO_CORE_EXPORT ComputeEngineResults
class OVITO_CORE_EXPORT ComputeEngine
{
public:
/// Constructor.
ComputeEngineResults(const TimeInterval& validityInterval = TimeInterval::infinite()) : _validityInterval(validityInterval) {}
ComputeEngine(const TimeInterval& validityInterval = TimeInterval::infinite()) :
_validityInterval(validityInterval),
_task(std::make_shared<ComputeEngineTask>(this)) {}
/// Destructor.
virtual ~ComputeEngineResults() = default;
virtual ~ComputeEngine() = default;
/// This method is called by the system after the computation was successfully completed.
/// Subclasses should override this method in order to release working memory and any references to the input data.
virtual void cleanup();
/// Computes the modifier's results.
virtual void perform() = 0;
/// Injects the computed results into the data pipeline.
virtual PipelineFlowState apply(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input) = 0;
virtual PipelineFlowState emitResults(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input) = 0;
/// Returns the validity period of the stored results.
const TimeInterval& validityInterval() const { return _validityInterval; }
/// Changes the stored validity period of the results.
void setValidityInterval(const TimeInterval& iv) { _validityInterval = iv; }
/// Returns the AsynchronousTask object associated with this engine.
const std::shared_ptr<AsynchronousTask<>>& task() const { return _task; }
private:
/// The validity period of the stored results.
TimeInterval _validityInterval;
};
/// Asynchronous task class for compute engines.
class OVITO_CORE_EXPORT ComputeEngineTask : public AsynchronousTask<>
{
public:
/// A managed pointer to a ComputeEngineResults instance.
using ComputeEngineResultsPtr = std::shared_ptr<ComputeEngineResults>;
/// Constructor.
ComputeEngineTask(ComputeEngine* engine) : _engine(engine) {}
/**
* Abstract base class for compute engines of AsynchronousModifier implementaAsynchronousModifiertions.
*/
class OVITO_CORE_EXPORT ComputeEngine : public AsynchronousTask<ComputeEngineResultsPtr>
{
public:
/// Is called when the asynchronous task begins to run.
virtual void perform() override;
#ifdef Q_OS_LINUX
/// Destructor.
virtual ~ComputeEngine();
#endif
private:
/// Pointer to the compute engine that owns this task object.
ComputeEngine* _engine;
};
/// The validity period of the stored results.
TimeInterval _validityInterval;
/// The asynchronous task object associated with this engine.
std::shared_ptr<AsynchronousTask<>> _task;
};
/// A managed pointer to a ComputeEngine instance.
......@@ -96,8 +112,7 @@ public:
/// Modifies the input data in an immediate, preliminary way.
virtual PipelineFlowState evaluatePreliminary(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input) override;
/// Decides whether a preliminary viewport update is performed every time the modifier
/// itself changes. For asynchronous modifier this is disabled.
/// Suppress preliminary viewport updates when a parameter of the asynchronous modifier changes.
virtual bool performPreliminaryUpdateAfterChange() override { return false; }
/// This method indicates whether outdated computation results should be immediately discarded
......
......@@ -42,10 +42,10 @@ public:
Q_INVOKABLE AsynchronousModifierApplication(DataSet* dataset);
/// Returns the cached results of the AsynchronousModifier from the last pipeline evaluation.
const AsynchronousModifier::ComputeEngineResultsPtr& lastComputeResults() const { return _lastComputeResults; }
const AsynchronousModifier::ComputeEnginePtr& lastComputeResults() const { return _lastComputeResults; }
/// Sets the cached results of the AsynchronousModifier from the last pipeline evaluation.
void setLastComputeResults(AsynchronousModifier::ComputeEngineResultsPtr results) { _lastComputeResults = std::move(results); }
void setLastComputeResults(AsynchronousModifier::ComputeEnginePtr results) { _lastComputeResults = std::move(results); }
protected:
......@@ -58,7 +58,7 @@ protected:
private:
/// The cached results of the AsynchronousModifier from the last pipeline evaluation.
AsynchronousModifier::ComputeEngineResultsPtr _lastComputeResults;
AsynchronousModifier::ComputeEnginePtr _lastComputeResults;
};
OVITO_END_INLINE_NAMESPACE
......
......@@ -145,7 +145,7 @@ protected:
std::rethrow_exception(_exceptionStore);
}
/// Accesor function for the internal results storage.
/// Accessor function for the internal results storage.
template<typename tuple_type, typename source_tuple_type, typename = std::enable_if_t<std::tuple_size<tuple_type>::value != 0>>
void setResults(source_tuple_type&& value) {
OVITO_ASSERT(_resultsTuple != nullptr);
......@@ -156,7 +156,7 @@ protected:
*static_cast<tuple_type*>(_resultsTuple) = std::forward<source_tuple_type>(value);
}
/// Accesor function for the internal results storage.
/// Accessor function for the internal results storage.
template<typename tuple_type>
const std::enable_if_t<std::tuple_size<tuple_type>::value != 0, tuple_type>& getResults() const {
OVITO_ASSERT(_resultsTuple != nullptr);
......@@ -166,13 +166,13 @@ protected:
return *static_cast<const tuple_type*>(_resultsTuple);
}
/// Accesor function for the internal results storage.
/// Accessor function for the internal results storage.
template<typename tuple_type>
const std::enable_if_t<std::tuple_size<tuple_type>::value == 0, tuple_type>& getResults() const {
return *static_cast<const tuple_type*>(_resultsTuple);
}
/// Accesor function for the internal results storage.
/// Accessor function for the internal results storage.
template<typename tuple_type>
std::enable_if_t<std::tuple_size<tuple_type>::value != 0, tuple_type> takeResults() {
OVITO_ASSERT(_resultsTuple != nullptr);
......@@ -183,6 +183,12 @@ protected:
return std::move(*static_cast<tuple_type*>(_resultsTuple));
}
/// Accessor function for the internal results storage.
template<typename tuple_type>
std::enable_if_t<std::tuple_size<tuple_type>::value == 0, tuple_type> takeResults() {
return {};
}
template<class F>
void addContinuation(F&& cont) {
addContinuationImpl(std::function<void()>(std::forward<F>(cont)));
......
......@@ -365,8 +365,8 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeFftCorrelati
gridProperty1,
_applyWindow);
incrementProgressValue();
if (isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
mapToSpatialGrid(sourceProperty2().get(),
......@@ -383,8 +383,8 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeFftCorrelati
nX, nY, nZ,
gridDensity,
_applyWindow);
incrementProgressValue();
if (isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
// FIXME. Apply windowing function in nonperiodic directions here.
......@@ -395,22 +395,22 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeFftCorrelati
QVector<std::complex<FloatType>> ftProperty1;
r2cFFT(nX, nY, nZ, gridProperty1, ftProperty1);
incrementProgressValue();
if (isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
QVector<std::complex<FloatType>> ftProperty2;
r2cFFT(nX, nY, nZ, gridProperty2, ftProperty2);
incrementProgressValue();
if (isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
QVector<std::complex<FloatType>> ftDensity;
r2cFFT(nX, nY, nZ, gridDensity, ftDensity);
incrementProgressValue();
if (isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
// Note: Reciprocal cell vectors are in rows. Those are 4-vectors.
......@@ -504,8 +504,8 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeFftCorrelati
}
}
incrementProgressValue();
if(isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
// Compute long-ranged part of the real-space correlation function from the FFT convolution.
......@@ -513,14 +513,14 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeFftCorrelati
// Computer inverse Fourier transform of correlation function.
c2rFFT(nX, nY, nZ, ftProperty1, gridProperty1);
incrementProgressValue();
if(isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
c2rFFT(nX, nY, nZ, ftDensity, gridDensity);
incrementProgressValue();
if(isCanceled())
task()->incrementProgressValue();
if(task()->isCanceled())
return;
// Determine number of grid points for reciprocal-spacespace correlation function.
......@@ -576,7 +576,7 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeFftCorrelati
}
}
incrementProgressValue();
task()->incrementProgressValue();
}
/******************************************************************************
......@@ -610,7 +610,7 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeNeighCorrela
// Prepare the neighbor list.
CutoffNeighborFinder neighborListBuilder;
if (!neighborListBuilder.prepare(_neighCutoff, *positions(), cell(), nullptr, this))
if(!neighborListBuilder.prepare(_neighCutoff, *positions(), cell(), nullptr, task().get()))
return;
// Perform analysis on each particle in parallel.
......@@ -634,7 +634,7 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeNeighCorrela
std::vector<double> threadLocalCorrelation(neighCorrelation().size(), 0);
std::vector<int> threadLocalRDF(neighCorrelation().size(), 0);
for (size_t i = startIndex; i < endIndex;) {
for (CutoffNeighborFinder::Query neighQuery(neighborListBuilder, i); !neighQuery.atEnd(); neighQuery.next()) {
for (CutoffNeighborFinder::Query neighQuery(neighborListBuilder, i); !neighQuery.atEnd(); neighQuery.next()) {
size_t distanceBinIndex = (size_t)(sqrt(neighQuery.distanceSquared()) / gridSpacing);
distanceBinIndex = std::min(distanceBinIndex, threadLocalCorrelation.size() - 1);
FloatType data1 = 0.0, data2 = 0.0;
......@@ -649,9 +649,9 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeNeighCorrela
threadLocalCorrelation[distanceBinIndex] += data1*data2;
threadLocalRDF[distanceBinIndex] += 1;
}
i++;
// Abort loop when operation was canceled by the user.
if (isCanceled())
i++;
// Abort loop when operation was canceled by the user.
if(task()->isCanceled())
return;
}
std::lock_guard<std::mutex> lock(mutex);
......@@ -668,7 +668,7 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeNeighCorrela
for (auto& t: workers)
t.waitForFinished();
incrementProgressValue();
task()->incrementProgressValue();
// Normalize short-ranged real-space correlation function and populate x-array.
FloatType gridSpacing = (_neighCutoff + FLOATTYPE_EPSILON) / neighCorrelation().size();
......@@ -681,7 +681,7 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeNeighCorrela
neighRDF()[distanceBinIndex] *= normalizationFactor/(distance2*distance2*distance2-distance*distance*distance);
}
incrementProgressValue();
task()->incrementProgressValue();
}
/******************************************************************************
......@@ -731,9 +731,9 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeLimits()
mean1 /= sourceProperty1()->size();
mean2 /= sourceProperty2()->size();
covariance /= sourceProperty1()->size();
_results->setLimits(mean1, mean2, covariance);
setLimits(mean1, mean2, covariance);
incrementProgressValue();
task()->incrementProgressValue();
}
/******************************************************************************
......@@ -741,36 +741,33 @@ void CorrelationFunctionModifier::CorrelationAnalysisEngine::computeLimits()
******************************************************************************/
void CorrelationFunctionModifier::CorrelationAnalysisEngine::perform()
{
setProgressText(tr("Computing correlation function"));
setProgressValue(0);
task()->setProgressText(tr("Computing correlation function"));
task()->setProgressValue(0);
int range = 12;
if(!neighCorrelation().empty())
range += 2;
setProgressMaximum(range);
task()->setProgressMaximum(range);
// Compute reciprocal space correlation function and long-ranged part of
// the real-space correlation function from an FFT.
computeFftCorrelation();
if(isCanceled())
if(task()->isCanceled())
return;
// Compute short-ranged part of the real-space correlation function from a direct loop over particle neighbors.
if(!neighCorrelation().empty())
computeNeighCorrelation();
if(isCanceled())
if(task()->isCanceled())
return;
computeLimits();
// Return the results of the compute engine.
setResult(std::move(_results));
}
/******************************************************************************
* Injects the computed results of the engine into the data pipeline.
******************************************************************************/
PipelineFlowState CorrelationFunctionModifier::CorrelationAnalysisResults::apply(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input)
PipelineFlowState CorrelationFunctionModifier::CorrelationAnalysisEngine::emitResults(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input)
{
// Store the computed data in the ModifierApplication.
static_object_cast<CorrelationFunctionModifierApplication>(modApp)->setResults(
......
......@@ -91,73 +91,6 @@ protected:
private:
/// Stores the modifier's results.
class CorrelationAnalysisResults : public ComputeEngineResults
{
public:
/// Constructor.
CorrelationAnalysisResults(int numberOfNeighBins, bool doComputeNeighCorrelation) :
_neighCorrelation(doComputeNeighCorrelation ? numberOfNeighBins : 0, 0.0),
_neighCorrelationX(doComputeNeighCorrelation ? numberOfNeighBins : 0) {}
/// Injects the computed results into the data pipeline.
virtual PipelineFlowState apply(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input) override;
/// Returns the real-space correlation function.
QVector<FloatType>& realSpaceCorrelation() { return _realSpaceCorrelation; }
/// Returns the RDF evaluated from an FFT correlation.
QVector<FloatType>& realSpaceRDF() { return _realSpaceRDF; }
/// Returns the distances for which the real-space correlation function is tabulAveated.
QVector<FloatType>& realSpaceCorrelationX() { return _realSpaceCorrelationX; }
/// Returns the short-ranged real-space correlation function.
QVector<FloatType>& neighCorrelation() { return _neighCorrelation; }
/// Returns the RDF evalauted from a direct sum over neighbor shells.
QVector<FloatType>& neighRDF() { return _neighRDF; }
/// Returns the distances for which the short-ranged real-space correlation function is tabulated.
QVector<FloatType>& neighCorrelationX() { return _neighCorrelationX; }
/// Returns the reciprocal-space correlation function.
QVector<FloatType>& reciprocalSpaceCorrelation() { return _reciprocalSpaceCorrelation; }
/// Returns the wavevectors for which the reciprocal-space correlation function is tabulated.
QVector<FloatType>& reciprocalSpaceCorrelationX() { return _reciprocalSpaceCorrelationX; }
/// Returns the mean of the first property.
FloatType mean1() const { return _mean1; }
/// Returns the mean of the second property.
FloatType mean2() const { return _mean2; }
/// Returns the (co)variance.
FloatType covariance() const { return _covariance; }
void setLimits(FloatType mean1, FloatType mean2, FloatType covariance) {
_mean1 = mean1;
_mean2 = mean2;
_covariance = covariance;
}
private:
QVector<FloatType> _realSpaceCorrelation;
QVector<FloatType> _realSpaceRDF;
QVector<FloatType> _realSpaceCorrelationX;
QVector<FloatType> _neighCorrelation;
QVector<FloatType> _neighRDF;
QVector<FloatType> _neighCorrelationX;
QVector<FloatType> _reciprocalSpaceCorrelation;
QVector<FloatType> _reciprocalSpaceCorrelationX;
FloatType _mean1 = 0;
FloatType _mean2 = 0;
FloatType _covariance = 0;
};
/// Computes the modifier's results.
class CorrelationAnalysisEngine : public ComputeEngine
{
......@@ -182,7 +115,16 @@ private:
_simCell(simCell), _fftGridSpacing(fftGridSpacing),
_applyWindow(applyWindow), _neighCutoff(neighCutoff),
_averagingDirection(averagingDirection),
_results(std::make_shared<CorrelationAnalysisResults>(numberOfNeighBins, doComputeNeighCorrelation)) {}
_neighCorrelation(doComputeNeighCorrelation ? numberOfNeighBins : 0, 0.0),
_neighCorrelationX(doComputeNeighCorrelation ? numberOfNeighBins : 0) {}
/// This method is called by the system after the computation was successfully completed.
virtual void cleanup() override {
_positions.reset();
_sourceProperty1.reset();
_sourceProperty2.reset();
ComputeEngine::cleanup();
}
/// Compute real and reciprocal space correlation function via FFT.
void computeFftCorrelation();
......@@ -214,29 +156,47 @@ private:
/// Returns the neighbor cutoff radius.
FloatType neighCutoff() const { return _neighCutoff; }
/// Injects the computed results into the data pipeline.
virtual PipelineFlowState emitResults(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input) override;
/// Returns the real-space correlation function.
QVector<FloatType>& realSpaceCorrelation() { return _results->realSpaceCorrelation(); }
QVector<FloatType>& realSpaceCorrelation() { return _realSpaceCorrelation; }
/// Returns the RDF evaluated from an FFT correlation.
QVector<FloatType>& realSpaceRDF() { return _results->realSpaceRDF(); }
QVector<FloatType>& realSpaceRDF() { return _realSpaceRDF; }
/// Returns the distances for which the real-space correlation function is tabulAveated.
QVector<FloatType>& realSpaceCorrelationX() { return _results->realSpaceCorrelationX(); }
QVector<FloatType>& realSpaceCorrelationX() { return _realSpaceCorrelationX; }
/// Returns the short-ranged real-space correlation function.
QVector<FloatType>& neighCorrelation() { return _results->neighCorrelation(); }
QVector<FloatType>& neighCorrelation() { return _neighCorrelation; }
/// Returns the RDF evalauted from a direct sum over neighbor shells.
QVector<FloatType>& neighRDF() { return _results->neighRDF(); }
QVector<FloatType>& neighRDF() { return _neighRDF; }
/// Returns the distances for which the short-ranged real-space correlation function is tabulated.
QVector<FloatType>& neighCorrelationX() { return _results->neighCorrelationX(); }
QVector<FloatType>& neighCorrelationX() { return _neighCorrelationX; }
/// Returns the reciprocal-space correlation function.
QVector<FloatType>& reciprocalSpaceCorrelation() { return _results->reciprocalSpaceCorrelation(); }
QVector<FloatType>& reciprocalSpaceCorrelation() { return _reciprocalSpaceCorrelation; }
/// Returns the wavevectors for which the reciprocal-space correlation function is tabulated.
QVector<FloatType>& reciprocalSpaceCorrelationX() { return _results->reciprocalSpaceCorrelationX(); }
QVector<FloatType>& reciprocalSpaceCorrelationX() { return _reciprocalSpaceCorrelationX; }
/// Returns the mean of the first property.
FloatType mean1() const { return _mean1; }
/// Returns the mean of the second property.
FloatType mean2() const { return _mean2; }
/// Returns the (co)variance.
FloatType covariance() const { return _covariance; }
void setLimits(FloatType mean1, FloatType mean2, FloatType covariance) {
_mean1 = mean1;
_mean2 = mean2;
_covariance = covariance;
}
private:
......@@ -261,10 +221,21 @@ private:
const FloatType _neighCutoff;
const AveragingDirectionType _averagingDirection;
const SimulationCell _simCell;
const ConstPropertyPtr _positions;
const ConstPropertyPtr _sourceProperty1;
const ConstPropertyPtr _sourceProperty2;
std::shared_ptr<CorrelationAnalysisResults> _results;
ConstPropertyPtr _positions;
ConstPropertyPtr _sourceProperty1;
ConstPropertyPtr _sourceProperty2;
QVector<FloatType> _realSpaceCorrelation;
QVector<FloatType> _realSpaceRDF;
QVector<FloatType> _realSpaceCorrelationX;
QVector<FloatType> _neighCorrelation;
QVector<FloatType> _neighRDF;
QVector<FloatType> _neighCorrelationX;
QVector<FloatType> _reciprocalSpaceCorrelation;
QVector<FloatType> _reciprocalSpaceCorrelationX;
FloatType _mean1 = 0;
FloatType _mean2 = 0;
FloatType _covariance = 0;
};
private:
......
......@@ -89,7 +89,7 @@ Future<AsynchronousModifier::ComputeEnginePtr> ConstructSurfaceModifier::createE
******************************************************************************/
void ConstructSurfaceModifier::ConstructSurfaceEngine::perform()
{
setProgressText(tr("Constructing surface mesh"));
task()->setProgressText(tr("Constructing surface mesh"));
if(_radius <= 0)
throw Exception(tr("Radius parameter must be positive."));
......@@ -115,21 +115,20 @@ void ConstructSurfaceModifier::ConstructSurfaceEngine::perform()
if(selection())
numInputParticles = positions()->size() - std::count(selection()->constDataInt(), selection()->constDataInt() + selection()->size(), 0);
if(numInputParticles <= 3) {
setResult(std::move(_results));
return;
}
// Algorithm is divided into several sub-steps.
// Assign weights to sub-steps according to estimated runtime.
beginProgressSubStepsWithWeights({ 20, 1, 6, 1 });
task()->beginProgressSubStepsWithWeights({ 20, 1, 6, 1 });
// Generate Delaunay tessellation.
DelaunayTessellation tessellation;
if(!tessellation.generateTessellation(_simCell, positions()->constDataPoint3(), positions()->size(), ghostLayerSize,
selection() ? selection()->constDataInt() : nullptr, *this))
selection() ? selection()->constDataInt() : nullptr, *task()))
return;