...
 
Commits (7)
......@@ -285,12 +285,13 @@ Download and build Intel OSPRay
cd $HOME/progs/
git clone https://github.com/ospray/ospray.git
cd ospray
git checkout v1.6.1
mkdir build
cd build
$HOME/progs/cmake-3.6.3-Linux-x86_64/bin/cmake \
-DCMAKE_INSTALL_PREFIX=$HOME/progs/ospray_install \
-DISPC_EXECUTABLE=$HOME/progs/ispc-v1.9.2-linux/ispc \
-Dembree_DIR=$HOME/progs/embree_install/lib/cmake/embree-2.17.0 \
-Dembree_DIR=$HOME/progs/embree_install/lib/cmake/embree-3.2.0 \
-DOSPRAY_APPS_BENCHMARK=OFF \
-DOSPRAY_APPS_EXAMPLEVIEWER=OFF \
-DOSPRAY_APPS_UTILITIES=OFF \
......@@ -345,8 +346,8 @@ $HOME/progs/cmake-3.6.3-Linux-x86_64/bin/cmake \
-DLIBAV_INCLUDE_DIR=$HOME/progs/libav/include \
-DLIBAV_LIBRARY_DIR=$HOME/progs/libav/lib \
-DOVITO_BUILD_PLUGIN_OSPRAY=ON \
-Dospray_DIR=$HOME/progs/ospray_install/lib/cmake/ospray-1.5.0 \
-Dembree_DIR=$HOME/progs/embree_install/lib/cmake/embree-2.17.0 \
-Dospray_DIR=$HOME/progs/ospray_install/lib/cmake/ospray-1.6.1 \
-Dembree_DIR=$HOME/progs/embree_install/lib/cmake/embree-3.2.0 \
-DISPC_EXECUTABLE=$HOME/progs/ispc-v1.9.2-linux/ispc \
-DTBB_INCLUDE_DIR=$HOME/progs/tbb2018_20170919oss/include/ \
-DTBB_LIBRARY=$HOME/progs/tbb2018_20170919oss/lib/intel64/gcc4.7/libtbb.so \
......
......@@ -52,21 +52,26 @@
<title>Role of the cutoff radius</title>
<para>
The <emphasis>cutoff radius</emphasis> is a parameter controlling the range of neighbors taken
into account when computing the atomic deformation gradient tensor of one particle. In other words in determines
the size of the spherical volume around the particle over which the relative motion of neighboring particles is averaged to obtain
the continuum deformation measure. As a rule of thumb: Use a small cutoff radius parameter to resolve all local details of the deformation field.
into account when computing the atomic deformation gradient tensor for a particle. In other words this parameter determines
the size of a spherical volume around the particle over which the relative motion of neighboring particles is averaged to obtain
the continuum deformation measure. As a rule of thumb: Use a smaller cutoff radius parameter to resolve all local details of the deformation field.
On the other hand, a large cutoff radius will yield slowly varying (smooth) deformation values at the atomic sites.
</para>
<para>
A typical choice for the cutoff radius parameter is to use the first minimum of the pair distribution function, i.e. placing
the cutoff halfway between the first and the second shell of neighbors in the system at hand. You can calculate the pair distribution
function for the current system using OVITO's <link linkend="particles.modifiers.coordination_analysis">Coordination Analysis</link> modifier.
</para>
<para>
Since the deformation gradient at each site is calculated from the relative motion of neighboring particles, it is important to ensure that sufficient
neighbors are within the given cutoff range (in the undeformed configuration). This puts a lower limit on the
cutoff radius that you can safely use. For three-dimensional systems, OVITO requires at a minimum three neighbor particles within
cutoff radius that you can safely use. For three-dimensional systems, OVITO requires at a minimum three neighbors within
the cutoff range of the central particle in order to calculate a deformation gradient tensor. Furthermore, these three neighbors must not be co-planar.
If the cutoff radius has been chosen too small and there are only less than three neighbors within range of the central particle,
the deformation gradient calculation and all subsequent calculations will fail for this particle. The modifier will notify you about this situation
in the status field and will, for diagnostic purposes, select all "undercoordinated" particles for which the calculation failed.
Depending on the situation, you may react to this kind of condition by bumping up the cutoff radius parameter such that more neighbors become within range
and the calculation succeeds.
If the cutoff radius has been chosen too small and there are less than three neighbors within range of the central particle,
the deformation gradient calculation and all subsequent calculations will fail for the particle. The modifier will notify you about this situation
in the status field and will, for diagnostic purposes, select all such "undercoordinated" particles for which the calculation failed.
Depending on the situation, you may react to this kind of condition by bumping up the cutoff radius parameter in order for more neighbors
to be included in the cutoff sphere.
</para>
</simplesect>
......@@ -90,6 +95,14 @@
is basically the <link xlink:href="http://li.mit.edu/A/Graphics/A/annotate_atomic_strain/Doc/main.pdf">residual of the least-squares fit</link> through which the deformation gradient is calculated.
It may be used as a diagnostic for identifying local irreversible shear transformations in amorphous solids, for example.
</para>
<para>
When calculating <inlineequation><mathphrase>D<superscript>2</superscript><subscript>min</subscript></mathphrase></inlineequation>, OVITO follows the original formulation given by
Falk and Langer, which consists of summing up the squared differences between the actual displacements of neighbors and
the computed affine approximation. In the current implementation, this sum does <emphasis>not</emphasis> get divided by the
number of neighbors within the cutoff range. Thus, the calculated <inlineequation><mathphrase>D<superscript>2</superscript><subscript>min</subscript></mathphrase></inlineequation>
value for a particle will depend on the number of neighbors that are included in the selected cutoff volume and will naturally rise
if you increase the cutoff radius.
</para>
<para>The atomic deformation gradient <inlineequation><mathphrase>F</mathphrase></inlineequation> can be decomposed into the product
<inlineequation><mathphrase>F=RU</mathphrase></inlineequation>
......
......@@ -16,16 +16,17 @@ def render(args):
xy = args.project_point(positions[pindex])
if xy is None: return
# Determine display radius of particle.
# Determine display radius of the particle.
radius = 0.0
if 'Radius' in data.particles:
radius = data.particles['Radius'][pindex]
elif 'Particle Type' in data.particles:
if radius <= 0 and 'Particle Type' in data.particles:
particle_type = data.particles['Particle Type'][pindex]
radius = data.particles['Particle Type'].type_by_id(particle_type).radius
else:
if radius <= 0:
radius = node.get_vis(ParticlesVis).radius
# Calculate screen-space size of particle in pixels.
# Calculate screen-space size of the particle in pixels.
screen_radius = args.project_size(positions[pindex], radius)
# Draw a dashed circle around the particle.
......
......@@ -249,7 +249,7 @@ The following script demonstrates how to use the `Matplotlib <http://matplotlib.
on top the three-dimensional visualization. The histogram data is dynamically computed by a :py:class:`~ovito.modifiers.HistogramModifier`
in the data pipeline in this example.
.. image:: /../manual/images/viewport_overlays/python_script_scale_bar_example.png
.. image:: /../manual/images/viewport_overlays/python_script_plot_example.png
.. literalinclude:: ../example_snippets/overlay_data_plot.py
:lines: 4-42
......
......@@ -30,6 +30,10 @@ aux_source_directories(SOURCES "Source Files\\api" api)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..)
ADD_LIBRARY(geogram STATIC ${SOURCES})
# Set visibility of symbols in this shared library to hidden by default, except those exported in the source code.
SET_TARGET_PROPERTIES(geogram PROPERTIES CXX_VISIBILITY_PRESET "hidden")
SET_TARGET_PROPERTIES(geogram PROPERTIES VISIBILITY_INLINES_HIDDEN ON)
# Make header files of this library available to dependent targets.
TARGET_INCLUDE_DIRECTORIES(geogram INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/..")
SET_PROPERTY(TARGET geogram PROPERTY POSITION_INDEPENDENT_CODE ON)
......
......@@ -50,7 +50,7 @@ ELSE()
# Since we will link this into the Particles plugin, we need to use the same setting for the fPIC flag.
SET_PROPERTY(TARGET muParser PROPERTY POSITION_INDEPENDENT_CODE ON)
# Export this target.
INSTALL(TARGETS muParser EXPORT OVITO
RUNTIME DESTINATION "${OVITO_RELATIVE_LIBRARY_DIRECTORY}" COMPONENT "runtime"
......
......@@ -123,7 +123,7 @@ private:
Part of the math parser package.
*/
class ParserError
class ParserError : public std::exception
{
private:
......@@ -159,6 +159,10 @@ public:
const string_type& GetToken() const;
EErrorCodes GetCode() const;
virtual const char* what() const noexcept override {
return GetMsg().c_str();
}
private:
string_type m_strMsg; ///< The message string
string_type m_strFormula; ///< Formula string
......
......@@ -105,7 +105,9 @@ void PromiseState::setFinishedNoSelfLock()
_state = State(_state | Finished);
// Make sure that a result has been set (if not in canceled or error state).
OVITO_ASSERT_MSG(_exceptionStore || isCanceled() || _resultSet.load() || !_resultsTuple, "PromiseState::setFinishedNoSelfLock()", "Result has not been set for this promise state.");
OVITO_ASSERT_MSG(_exceptionStore || isCanceled() || _resultSet.load() || !_resultsTuple,
"PromiseState::setFinishedNoSelfLock()",
qPrintable(QStringLiteral("Result has not been set for the promise state. Please check program code setting the promise state. Progress text: %1").arg(progressText())));
// Run the continuation functions.
for(auto& cont : _continuations)
......
......@@ -114,8 +114,10 @@ void ConstructSurfaceModifier::ConstructSurfaceEngine::perform()
size_t numInputParticles = positions()->size();
if(selection())
numInputParticles = positions()->size() - std::count(selection()->constDataInt(), selection()->constDataInt() + selection()->size(), 0);
if(numInputParticles <= 3)
if(numInputParticles <= 3) {
setResult(std::move(_results));
return;
}
// Algorithm is divided into several sub-steps.
// Assign weights to sub-steps according to estimated runtime.
......
......@@ -90,7 +90,7 @@ void CoordinationNumberModifierEditor::createUI(const RolloutInsertionParameters
******************************************************************************/
bool CoordinationNumberModifierEditor::referenceEvent(RefTarget* source, const ReferenceEvent& event)
{
if(event.sender() == editObject() && event.type() == ReferenceEvent::ObjectStatusChanged) {
if(event.sender() == editObject() && (event.type() == ReferenceEvent::ObjectStatusChanged || event.type() == ReferenceEvent::TargetChanged)) {
plotRDFLater(this);
}
return ModifierPropertiesEditor::referenceEvent(source, event);
......
......@@ -98,7 +98,7 @@ Future<AsynchronousModifier::ComputeEnginePtr> AtomicStrainModifier::createEngin
return std::make_shared<AtomicStrainEngine>(validityInterval, posProperty->storage(), inputCell->data(), refPosProperty->storage(), refCell->data(),
identifierProperty ? identifierProperty->storage() : nullptr, refIdentifierProperty ? refIdentifierProperty->storage() : nullptr,
cutoff(), affineMapping(), useMinimumImageConvention(), calculateDeformationGradients(), calculateStrainTensors(),
calculateNonaffineSquaredDisplacements(), calculateRotations(), calculateStretchTensors());
calculateNonaffineSquaredDisplacements(), calculateRotations(), calculateStretchTensors(), selectInvalidParticles());
}
/******************************************************************************
......@@ -208,7 +208,8 @@ void AtomicStrainModifier::AtomicStrainEngine::computeStrain(size_t particleInde
Matrix_3<double> inverseV;
double detThreshold = (double)sumSquaredDistance * 1e-12;
if(numNeighbors < 2 || (!cell().is2D() && numNeighbors < 3) || !V.inverse(inverseV, detThreshold) || std::abs(W.determinant()) <= detThreshold) {
_results->invalidParticles()->setInt(particleIndex, 1);
if(_results->invalidParticles())
_results->invalidParticles()->setInt(particleIndex, 1);
if(_results->deformationGradients()) {
for(Matrix_3<double>::size_type col = 0; col < 3; col++) {
for(Matrix_3<double>::size_type row = 0; row < 3; row++) {
......@@ -299,7 +300,8 @@ void AtomicStrainModifier::AtomicStrainEngine::computeStrain(size_t particleInde
OVITO_ASSERT(std::isfinite(volumetricStrain));
_results->volumetricStrains()->setFloat(particleIndex, (FloatType)volumetricStrain);
_results->invalidParticles()->setInt(particleIndex, 0);
if(_results->invalidParticles())
_results->invalidParticles()->setInt(particleIndex, 0);
}
/******************************************************************************
......@@ -310,7 +312,8 @@ PipelineFlowState AtomicStrainModifier::AtomicStrainResults::apply(TimePoint tim
PipelineFlowState output = input;
ParticleOutputHelper poh(modApp->dataset(), output);
if(invalidParticles()->size() != poh.outputParticleCount())
OVITO_ASSERT(shearStrains());
if(shearStrains()->size() != poh.outputParticleCount())
modApp->throwException(tr("Cached modifier results are obsolete, because the number of input particles has changed."));
if(invalidParticles())
......
......@@ -63,14 +63,15 @@ private:
bool calculateStrainTensors,
bool calculateNonaffineSquaredDisplacements,
bool calculateRotations,
bool calculateStretchTensors) :
bool calculateStretchTensors,
bool selectInvalidParticles) :
ComputeEngineResults(validityInterval),
_shearStrains(std::make_shared<PropertyStorage>(particleCount, PropertyStorage::Float, 1, 0, tr("Shear Strain"), false)),
_volumetricStrains(std::make_shared<PropertyStorage>(particleCount, PropertyStorage::Float, 1, 0, tr("Volumetric Strain"), false)),
_strainTensors(calculateStrainTensors ? ParticleProperty::createStandardStorage(particleCount, ParticleProperty::StrainTensorProperty, false) : nullptr),
_deformationGradients(calculateDeformationGradients ? ParticleProperty::createStandardStorage(particleCount, ParticleProperty::DeformationGradientProperty, false) : nullptr),
_nonaffineSquaredDisplacements(calculateNonaffineSquaredDisplacements ? std::make_shared<PropertyStorage>(particleCount, PropertyStorage::Float, 1, 0, tr("Nonaffine Squared Displacement"), false) : nullptr),
_invalidParticles(ParticleProperty::createStandardStorage(particleCount, ParticleProperty::SelectionProperty, false)),
_invalidParticles(selectInvalidParticles ? ParticleProperty::createStandardStorage(particleCount, ParticleProperty::SelectionProperty, false) : nullptr),
_rotations(calculateRotations ? ParticleProperty::createStandardStorage(particleCount, ParticleProperty::RotationProperty, false) : nullptr),
_stretchTensors(calculateStretchTensors ? ParticleProperty::createStandardStorage(particleCount, ParticleProperty::StretchTensorProperty, false) : nullptr) {}
......@@ -131,7 +132,8 @@ private:
ConstPropertyPtr identifiers, ConstPropertyPtr refIdentifiers,
FloatType cutoff, AffineMappingType affineMapping, bool useMinimumImageConvention,
bool calculateDeformationGradients, bool calculateStrainTensors,
bool calculateNonaffineSquaredDisplacements, bool calculateRotations, bool calculateStretchTensors) :
bool calculateNonaffineSquaredDisplacements, bool calculateRotations, bool calculateStretchTensors,
bool selectInvalidParticles) :
RefConfigEngineBase(positions, simCell, refPositions, simCellRef,
std::move(identifiers), std::move(refIdentifiers), affineMapping, useMinimumImageConvention),
_cutoff(cutoff),
......@@ -141,7 +143,8 @@ private:
calculateStrainTensors,
calculateNonaffineSquaredDisplacements,
calculateRotations,
calculateStretchTensors)) {}
calculateStretchTensors,
selectInvalidParticles)) {}
/// Computes the modifier's results.
virtual void perform() override;
......
......@@ -215,10 +215,14 @@ Future<AsynchronousModifier::ComputeEnginePtr> ComputePropertyModifier::createEn
}
// Create engine object. Pass all relevant modifier parameters to the engine as well as the input data.
return std::make_shared<PropertyComputeEngine>(validityInterval, time, std::move(outp), posProperty->storage(),
std::shared_ptr<PropertyComputeEngine> engine = std::make_shared<PropertyComputeEngine>(validityInterval, time, std::move(outp), posProperty->storage(),
std::move(selProperty), inputCell->data(), neighborModeEnabled() ? cutoff() : 0,
expressions(), neighborExpressions(),
std::move(inputProperties), currentFrame, input.attributes());
setVariablesInfo(engine->inputVariableNames(), engine->inputVariableTable());
return engine;
}
/******************************************************************************
......
......@@ -122,6 +122,15 @@ public:
/// \brief Returns a human-readable text listing the input variables.
const QString& inputVariableTable() const { return _inputVariableTable; }
/// \brief Stores the given information about the available input variables in the modifier.
void setVariablesInfo(QStringList variableNames, QString variableTable) {
if(variableNames != _inputVariableNames || variableTable != _inputVariableTable) {
_inputVariableNames = std::move(variableNames);
_inputVariableTable = std::move(variableTable);
notifyDependents(ReferenceEvent::ObjectStatusChanged);
}
}
protected:
/// \brief Is called when the value of a property of this object has changed.
......
......@@ -297,6 +297,7 @@ PipelineFlowState HistogramModifier::evaluatePreliminary(TimePoint time, Modifie
// Store results in the ModifierApplication.
static_object_cast<HistogramModifierApplication>(modApp)->setBinCounts(ycoords);
static_object_cast<HistogramModifierApplication>(modApp)->setHistogramInterval({intervalStart, intervalEnd});
notifyDependents(ReferenceEvent::ObjectStatusChanged);
QString statusMessage;
if(outputSelection) {
......