openFOAM-paraview-catalyst (#10129)
* paraview: adding variants to use external packages as internal do not compile * paraview: add latest paraview version * catalyst: fixed libvtkexpat undefined reference linking error in Catalyst 5.5 * catalyst: add latest catalyst version * catalyst: added ParaView_DIR env variable to catalyst module * add paraview, catalyst patches - https://gitlab.kitware.com/vtk/vtk-m/merge_requests/1166 - https://gitlab.kitware.com/paraview/paraview/merge_requests/2433 - https://gitlab.kitware.com/paraview/paraview/merge_requests/2436 * - Handle updated library paths for catalyst. Versions 5.4 and old places libraries under a paraview subdirectory. Eg, "lib/paraview-5.4", they are now placed directly under "lib" - Minor code style cleanup * Handle update library and python paths for ParaView-5.5 * catalyst: added ParaView_DIR path to spack_env * BUG: applied the patch to the extracted catalyst source files * paraview: added missing self to a member variable * paraview: added Paraview_DIR to env * catalyst: added osmesa variant * of-catalyst: added new package * add (FOAM,WM)_PROJECT_DIR also to spack_env environment * depends on first openfoam release supporting catalyst * openfoam-com: added missing env variables to module generation * openfoam: fixed flake8 errors * of-catalyst: added full variant and openfoam version dependency * paraview: adding variants to use external packages as internal do not compile * catalyst: fixed libvtkexpat undefined reference linking error in Catalyst 5.5 * catalyst: added ParaView_DIR env variable to catalyst module * add paraview, catalyst patches - https://gitlab.kitware.com/vtk/vtk-m/merge_requests/1166 - https://gitlab.kitware.com/paraview/paraview/merge_requests/2433 - https://gitlab.kitware.com/paraview/paraview/merge_requests/2436 * - Handle updated library paths for catalyst. Versions 5.4 and old places libraries under a paraview subdirectory. Eg, "lib/paraview-5.4", they are now placed directly under "lib" - Minor code style cleanup * Handle update library and python paths for ParaView-5.5 * catalyst: added ParaView_DIR path to spack_env * BUG: applied the patch to the extracted catalyst source files * of-catalyst: added new package * add (FOAM,WM)_PROJECT_DIR also to spack_env environment * depends on first openfoam release supporting catalyst * paraview: added missing self to a member variable * openfoam-com: added missing env variables to module generation * openfoam: fixed flake8 errors * paraview: added Paraview_DIR to env * catalyst: added osmesa variant * of-catalyst: added full variant and openfoam version dependency * paraview-catalyst: use always external expat and netcdf * of-catalyst: reformatted package description * paraview-catalyst: removed duplicated function * catalyst: fixed flake8 error * of-catalyst: fixed license header * of-catalyst: minor changes * of-catalyst: renamed gitrepo with git * of-catalyst: removed useless gitrepo parameter
This commit is contained in:
parent
bdc9804078
commit
e7e32cc2d6
@ -7,6 +7,7 @@
|
||||
import os
|
||||
import subprocess
|
||||
import llnl.util.tty as tty
|
||||
from spack.patch import absolute_path_for_package
|
||||
|
||||
|
||||
class Catalyst(CMakePackage):
|
||||
@ -33,17 +34,31 @@ class Catalyst(CMakePackage):
|
||||
variant('python', default=False, description='Enable Python support')
|
||||
variant('essentials', default=False, description='Enable Essentials support')
|
||||
variant('extras', default=False, description='Enable Extras support')
|
||||
variant('rendering', default=False, description='Enable Vtk Rendering support')
|
||||
variant('rendering', default=False, description='Enable VTK Rendering support')
|
||||
variant('osmesa', default=True, description='Use offscreen rendering')
|
||||
|
||||
depends_on('git')
|
||||
depends_on('git', type='build')
|
||||
depends_on('mpi')
|
||||
depends_on('python@2:2.8', when='+python', type=("build", "link", "run"))
|
||||
depends_on('python', when='~python', type=("build"))
|
||||
depends_on('mesa', when='+rendering')
|
||||
depends_on("libx11", when='+rendering')
|
||||
depends_on("libxt", when='+rendering')
|
||||
depends_on('libx11', when='+rendering')
|
||||
depends_on('libxt', when='+rendering')
|
||||
depends_on('cmake@3.3:', type='build')
|
||||
|
||||
@when('@5.5.0:5.5.2')
|
||||
def patch(self):
|
||||
"""Apply the patch (it should be fixed in Paraview 5.6)
|
||||
at the package dir to the source code in
|
||||
root_cmakelists_dir."""
|
||||
patch_name = 'vtkm-catalyst-pv551.patch'
|
||||
pkg_dir = os.path.dirname(absolute_path_for_package(self))
|
||||
patch = which("patch", required=True)
|
||||
with working_dir(self.root_cmakelists_dir):
|
||||
patch('-s', '-p', '1', '-i',
|
||||
join_path(pkg_dir, patch_name),
|
||||
"-d", '.')
|
||||
|
||||
def url_for_version(self, version):
|
||||
"""Handle ParaView version-based custom URLs."""
|
||||
if version < Version('5.1.0'):
|
||||
@ -53,6 +68,30 @@ def url_for_version(self, version):
|
||||
else:
|
||||
return self._urlfmt_xz.format(version.up_to(2), version, '')
|
||||
|
||||
@property
|
||||
def paraview_subdir(self):
|
||||
"""The paraview subdirectory name as paraview-major.minor"""
|
||||
return 'paraview-{0}'.format(self.spec.version.up_to(2))
|
||||
|
||||
@property
|
||||
def editions(self):
|
||||
"""Transcribe spack variants into names of Catalyst Editions"""
|
||||
selected = ['Base'] # Always required
|
||||
|
||||
if '+python' in self.spec:
|
||||
selected.append('Enable-Python')
|
||||
|
||||
if '+essentials' in self.spec:
|
||||
selected.append('Essentials')
|
||||
|
||||
if '+extras' in self.spec:
|
||||
selected.append('Extras')
|
||||
|
||||
if '+rendering' in self.spec:
|
||||
selected.append('Rendering-Base')
|
||||
|
||||
return selected
|
||||
|
||||
def do_stage(self, mirror_only=False):
|
||||
"""Unpacks and expands the fetched tarball.
|
||||
Then, generate the catalyst source files."""
|
||||
@ -62,38 +101,15 @@ def do_stage(self, mirror_only=False):
|
||||
paraview_dir = os.path.join(self.stage.path,
|
||||
'ParaView-v' + str(self.version))
|
||||
catalyst_script = os.path.join(paraview_dir, 'Catalyst', 'catalyze.py')
|
||||
editions_dir = os.path.join(paraview_dir, 'Catalyst', 'Editions')
|
||||
catalyst_source_dir = os.path.abspath(self.root_cmakelists_dir)
|
||||
|
||||
command = ['python', catalyst_script,
|
||||
'-r', paraview_dir]
|
||||
'-r', paraview_dir,
|
||||
'-o', catalyst_source_dir]
|
||||
|
||||
catalyst_edition = os.path.join(paraview_dir, 'Catalyst',
|
||||
'Editions', 'Base')
|
||||
command.append('-i')
|
||||
command.append(catalyst_edition)
|
||||
if '+python' in self.spec:
|
||||
catalyst_edition = os.path.join(paraview_dir, 'Catalyst',
|
||||
'Editions', 'Enable-Python')
|
||||
command.append('-i')
|
||||
command.append(catalyst_edition)
|
||||
if '+essentials' in self.spec:
|
||||
catalyst_edition = os.path.join(paraview_dir, 'Catalyst',
|
||||
'Editions', 'Essentials')
|
||||
command.append('-i')
|
||||
command.append(catalyst_edition)
|
||||
if '+extras' in self.spec:
|
||||
catalyst_edition = os.path.join(paraview_dir, 'Catalyst',
|
||||
'Editions', 'Extras')
|
||||
command.append('-i')
|
||||
command.append(catalyst_edition)
|
||||
if '+rendering' in self.spec:
|
||||
catalyst_edition = os.path.join(paraview_dir, 'Catalyst',
|
||||
'Editions', 'Rendering-Base')
|
||||
command.append('-i')
|
||||
command.append(catalyst_edition)
|
||||
|
||||
command.append('-o')
|
||||
command.append(catalyst_source_dir)
|
||||
for edition in self.editions:
|
||||
command.extend(['-i', os.path.join(editions_dir, edition)])
|
||||
|
||||
if not os.path.isdir(catalyst_source_dir):
|
||||
os.mkdir(catalyst_source_dir)
|
||||
@ -104,15 +120,29 @@ def do_stage(self, mirror_only=False):
|
||||
self.stage.path))
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
# paraview 5.5 and later
|
||||
# - cmake under lib/cmake/paraview-5.5
|
||||
# - libs under lib
|
||||
# - python bits under lib/python2.8/site-packages
|
||||
if os.path.isdir(self.prefix.lib64):
|
||||
lib_dir = self.prefix.lib64
|
||||
else:
|
||||
lib_dir = self.prefix.lib
|
||||
paraview_version = 'paraview-%s' % self.spec.version.up_to(2)
|
||||
run_env.prepend_path('LIBRARY_PATH', join_path(lib_dir,
|
||||
paraview_version))
|
||||
run_env.prepend_path('LD_LIBRARY_PATH', join_path(lib_dir,
|
||||
paraview_version))
|
||||
|
||||
if self.spec.version <= Version('5.4.1'):
|
||||
lib_dir = join_path(lib_dir, paraview_subdir)
|
||||
run_env.set('ParaView_DIR', self.prefix)
|
||||
run_env.prepend_path('LIBRARY_PATH', lib_dir)
|
||||
run_env.prepend_path('LD_LIBRARY_PATH', lib_dir)
|
||||
|
||||
if '+python' in self.spec:
|
||||
python_version = self.spec['python'].version.up_to(2)
|
||||
run_env.prepend_path('PYTHONPATH', join_path(lib_dir,
|
||||
'python{0}'.format(python_version),
|
||||
'site-packages'))
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
spack_env.set('ParaView_DIR', self.prefix)
|
||||
|
||||
@property
|
||||
def root_cmakelists_dir(self):
|
||||
@ -136,8 +166,24 @@ def build_directory(self):
|
||||
|
||||
def cmake_args(self):
|
||||
"""Populate cmake arguments for Catalyst."""
|
||||
spec = self.spec
|
||||
|
||||
def variant_bool(feature, on='ON', off='OFF'):
|
||||
"""Ternary for spec variant to ON/OFF string"""
|
||||
if feature in spec:
|
||||
return on
|
||||
return off
|
||||
|
||||
def nvariant_bool(feature):
|
||||
"""Negated ternary for spec variant to OFF/ON string"""
|
||||
return variant_bool(feature, on='OFF', off='ON')
|
||||
|
||||
cmake_args = [
|
||||
'-DPARAVIEW_GIT_DESCRIBE=v%s' % str(self.version)
|
||||
'-DPARAVIEW_GIT_DESCRIBE=v%s' % str(self.version),
|
||||
'-DVTK_USE_SYSTEM_EXPAT:BOOL=ON',
|
||||
'-DVTK_USE_X:BOOL=%s' % nvariant_bool('+osmesa'),
|
||||
'-DVTK_USE_OFFSCREEN:BOOL=%s' % variant_bool('+osmesa'),
|
||||
'-DVTK_OPENGL_HAS_OSMESA:BOOL=%s' % variant_bool('+osmesa')
|
||||
]
|
||||
return cmake_args
|
||||
|
||||
|
@ -0,0 +1,487 @@
|
||||
# The catalyst changes (the working directory for output) are slated for
|
||||
# paraview-5.6.
|
||||
# They are API-compatible with paraview-5.5 but not ABI compatible.
|
||||
#
|
||||
# https://gitlab.kitware.com/paraview/paraview/merge_requests/2433
|
||||
# https://gitlab.kitware.com/paraview/paraview/merge_requests/2436
|
||||
#
|
||||
--- Catalyst-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.cxx.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ Catalyst-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.cxx 2018-05-11 12:02:26.894772713 +0200
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "vtkStringArray.h"
|
||||
|
||||
#include <list>
|
||||
+#include <vtksys/SystemTools.hxx>
|
||||
|
||||
struct vtkCPProcessorInternals
|
||||
{
|
||||
@@ -47,12 +48,13 @@
|
||||
};
|
||||
|
||||
vtkStandardNewMacro(vtkCPProcessor);
|
||||
-vtkMultiProcessController* vtkCPProcessor::Controller = NULL;
|
||||
+vtkMultiProcessController* vtkCPProcessor::Controller = nullptr;
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCPProcessor::vtkCPProcessor()
|
||||
{
|
||||
this->Internal = new vtkCPProcessorInternals;
|
||||
- this->InitializationHelper = NULL;
|
||||
+ this->InitializationHelper = nullptr;
|
||||
+ this->WorkingDirectory = nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -61,14 +63,15 @@
|
||||
if (this->Internal)
|
||||
{
|
||||
delete this->Internal;
|
||||
- this->Internal = NULL;
|
||||
+ this->Internal = nullptr;
|
||||
}
|
||||
|
||||
if (this->InitializationHelper)
|
||||
{
|
||||
this->InitializationHelper->Delete();
|
||||
- this->InitializationHelper = NULL;
|
||||
+ this->InitializationHelper = nullptr;
|
||||
}
|
||||
+ this->SetWorkingDirectory(nullptr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -95,7 +98,7 @@
|
||||
{
|
||||
if (which < 0 || which >= this->GetNumberOfPipelines())
|
||||
{
|
||||
- return NULL;
|
||||
+ return nullptr;
|
||||
}
|
||||
int counter = 0;
|
||||
vtkCPProcessorInternals::PipelineListIterator iter = this->Internal->Pipelines.begin();
|
||||
@@ -108,7 +111,7 @@
|
||||
counter++;
|
||||
iter++;
|
||||
}
|
||||
- return NULL;
|
||||
+ return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -130,17 +133,41 @@
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
-int vtkCPProcessor::Initialize()
|
||||
+int vtkCPProcessor::Initialize(const char* workingDirectory)
|
||||
{
|
||||
- if (this->InitializationHelper == NULL)
|
||||
+ if (this->InitializationHelper == nullptr)
|
||||
{
|
||||
this->InitializationHelper = this->NewInitializationHelper();
|
||||
}
|
||||
+ // make sure the directory exists here so that we only do it once
|
||||
+ if (workingDirectory)
|
||||
+ {
|
||||
+ vtkMultiProcessController* controller = vtkMultiProcessController::GetGlobalController();
|
||||
+ int success = 1;
|
||||
+ if (controller == nullptr || controller->GetLocalProcessId() == 0)
|
||||
+ {
|
||||
+ success = vtksys::SystemTools::MakeDirectory(workingDirectory) == true ? 1 : 0;
|
||||
+ if (success == 0)
|
||||
+ {
|
||||
+ vtkWarningMacro("Could not make "
|
||||
+ << workingDirectory << " directory. "
|
||||
+ << "Results will be generated in current working directory instead.");
|
||||
+ }
|
||||
+ }
|
||||
+ if (controller)
|
||||
+ {
|
||||
+ controller->Broadcast(&success, 1, 0);
|
||||
+ }
|
||||
+ if (success)
|
||||
+ {
|
||||
+ this->SetWorkingDirectory(workingDirectory);
|
||||
+ }
|
||||
+ }
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
-int vtkCPProcessor::Initialize(vtkMPICommunicatorOpaqueComm& comm)
|
||||
+int vtkCPProcessor::Initialize(vtkMPICommunicatorOpaqueComm& comm, const char* workingDirectory)
|
||||
{
|
||||
#ifdef PARAVIEW_USE_MPI
|
||||
if (vtkCPProcessor::Controller)
|
||||
@@ -148,7 +175,7 @@
|
||||
vtkErrorMacro("Can only initialize with a communicator once per process.");
|
||||
return 0;
|
||||
}
|
||||
- if (this->InitializationHelper == NULL)
|
||||
+ if (this->InitializationHelper == nullptr)
|
||||
{
|
||||
vtkMPICommunicator* communicator = vtkMPICommunicator::New();
|
||||
communicator->InitializeExternal(&comm);
|
||||
@@ -157,12 +184,12 @@
|
||||
this->Controller = controller;
|
||||
this->Controller->SetGlobalController(controller);
|
||||
communicator->Delete();
|
||||
- return this->Initialize();
|
||||
+ return this->Initialize(workingDirectory);
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
static_cast<void>(&comm); // get rid of variable not used warning
|
||||
- return this->Initialize();
|
||||
+ return this->Initialize(workingDirectory);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -225,6 +252,13 @@
|
||||
input->GetFieldData()->AddArray(catalystChannel);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ std::string originalWorkingDirectory;
|
||||
+ if (this->WorkingDirectory)
|
||||
+ {
|
||||
+ originalWorkingDirectory = vtksys::SystemTools::GetCurrentWorkingDirectory();
|
||||
+ vtksys::SystemTools::ChangeDirectory(this->WorkingDirectory);
|
||||
+ }
|
||||
for (vtkCPProcessorInternals::PipelineListIterator iter = this->Internal->Pipelines.begin();
|
||||
iter != this->Internal->Pipelines.end(); iter++)
|
||||
{
|
||||
@@ -248,6 +282,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (originalWorkingDirectory.empty() == false)
|
||||
+ {
|
||||
+ vtksys::SystemTools::ChangeDirectory(originalWorkingDirectory);
|
||||
+ }
|
||||
// we want to reset everything here to make sure that new information
|
||||
// is properly passed in the next time.
|
||||
dataDescription->ResetAll();
|
||||
@@ -259,7 +297,7 @@
|
||||
{
|
||||
if (this->Controller)
|
||||
{
|
||||
- this->Controller->SetGlobalController(NULL);
|
||||
+ this->Controller->SetGlobalController(nullptr);
|
||||
this->Controller->Finalize(1);
|
||||
this->Controller->Delete();
|
||||
}
|
||||
--- Catalyst-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.h.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ Catalyst-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.h 2018-05-11 12:02:26.894772713 +0200
|
||||
@@ -76,14 +76,16 @@
|
||||
virtual void RemoveAllPipelines();
|
||||
|
||||
/// Initialize the co-processor. Returns 1 if successful and 0
|
||||
- /// otherwise.
|
||||
/// otherwise. If Catalyst is built with MPI then Initialize()
|
||||
/// can also be called with a specific MPI communicator if
|
||||
/// MPI_COMM_WORLD isn't the proper one. Catalyst is initialized
|
||||
- /// to use MPI_COMM_WORLD by default.
|
||||
- virtual int Initialize();
|
||||
+ /// to use MPI_COMM_WORLD by default. Both methods have an optional
|
||||
+ /// workingDirectory argument which will set *WorkingDirectory* so
|
||||
+ /// that files will be put relative to this directory.
|
||||
+ virtual int Initialize(const char* workingDirectory = nullptr);
|
||||
#ifndef __WRAP__
|
||||
- virtual int Initialize(vtkMPICommunicatorOpaqueComm& comm);
|
||||
+ virtual int Initialize(
|
||||
+ vtkMPICommunicatorOpaqueComm& comm, const char* workingDirectory = nullptr);
|
||||
#endif
|
||||
|
||||
/// The Catalyst input field data string array name. This array will
|
||||
@@ -111,6 +113,13 @@
|
||||
/// implementation an opportunity to clean up, before it is destroyed.
|
||||
virtual int Finalize();
|
||||
|
||||
+ /// Get the current working directory for outputting Catalyst files.
|
||||
+ /// If not set then Catalyst output files will be relative to the
|
||||
+ /// current working directory. This will not affect where Catalyst
|
||||
+ /// looks for Python scripts. *WorkingDirectory* gets set through
|
||||
+ /// the *Initialize()* methods.
|
||||
+ vtkGetStringMacro(WorkingDirectory);
|
||||
+
|
||||
protected:
|
||||
vtkCPProcessor();
|
||||
virtual ~vtkCPProcessor();
|
||||
@@ -118,6 +127,11 @@
|
||||
/// Create a new instance of the InitializationHelper.
|
||||
virtual vtkObject* NewInitializationHelper();
|
||||
|
||||
+ /// Set the current working directory for outputting Catalyst files.
|
||||
+ /// This is a protected method since simulation code adaptors should
|
||||
+ /// set this through the *Initialize()* methods.
|
||||
+ vtkSetStringMacro(WorkingDirectory);
|
||||
+
|
||||
private:
|
||||
vtkCPProcessor(const vtkCPProcessor&) = delete;
|
||||
void operator=(const vtkCPProcessor&) = delete;
|
||||
@@ -125,6 +139,7 @@
|
||||
vtkCPProcessorInternals* Internal;
|
||||
vtkObject* InitializationHelper;
|
||||
static vtkMultiProcessController* Controller;
|
||||
+ char* WorkingDirectory;
|
||||
};
|
||||
|
||||
#endif
|
||||
--- Catalyst-v5.5.0/CoProcessing/Catalyst/vtkCPXMLPWriterPipeline.cxx.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ Catalyst-v5.5.0/CoProcessing/Catalyst/vtkCPXMLPWriterPipeline.cxx 2018-05-11 12:02:26.894772713 +0200
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
+#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -174,7 +175,7 @@
|
||||
|
||||
for (unsigned int i = 0; i < dataDescription->GetNumberOfInputDescriptions(); i++)
|
||||
{
|
||||
- const char* inputName = dataDescription->GetInputDescriptionName(i);
|
||||
+ std::string inputName = dataDescription->GetInputDescriptionName(i);
|
||||
vtkCPInputDataDescription* idd = dataDescription->GetInputDescription(i);
|
||||
vtkDataObject* grid = idd->GetGrid();
|
||||
if (grid == nullptr)
|
||||
@@ -206,6 +207,8 @@
|
||||
vtkSMStringVectorProperty* fileName =
|
||||
vtkSMStringVectorProperty::SafeDownCast(writer->GetProperty("FileName"));
|
||||
|
||||
+ // If we have a / in the channel name we take it out of the filename we're going to write to
|
||||
+ inputName.erase(std::remove(inputName.begin(), inputName.end(), '/'), inputName.end());
|
||||
std::ostringstream o;
|
||||
if (this->Path.empty() == false)
|
||||
{
|
||||
--- Catalyst-v5.5.0/Wrapping/Python/paraview/coprocessing.py.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ Catalyst-v5.5.0/Wrapping/Python/paraview/coprocessing.py 2018-05-11 12:02:27.038772408 +0200
|
||||
@@ -11,22 +11,12 @@
|
||||
from paraview.vtk.vtkPVVTKExtensionsCore import *
|
||||
import math
|
||||
|
||||
-# -----------------------------------------------------------------------------
|
||||
-def IsInModulo(timestep, frequencyArray):
|
||||
- """
|
||||
- Return True if the given timestep is in one of the provided frequency.
|
||||
- This can be interpreted as follow::
|
||||
-
|
||||
- isFM = IsInModulo(timestep, [2,3,7])
|
||||
-
|
||||
- is similar to::
|
||||
+# If the user created a filename in a location that doesn't exist by default we'll
|
||||
+# make the directory for them. This can be changed though by setting createDirectoriesIfNeeded
|
||||
+# to False.
|
||||
+createDirectoriesIfNeeded = True
|
||||
|
||||
- isFM = (timestep % 2 == 0) or (timestep % 3 == 0) or (timestep % 7 == 0)
|
||||
- """
|
||||
- for frequency in frequencyArray:
|
||||
- if frequency > 0 and (timestep % frequency == 0):
|
||||
- return True
|
||||
- return False
|
||||
+# -----------------------------------------------------------------------------
|
||||
|
||||
class CoProcessor(object):
|
||||
"""Base class for co-processing Pipelines.
|
||||
@@ -68,6 +58,9 @@
|
||||
self.__CinemaTracks = {}
|
||||
self.__InitialFrequencies = {}
|
||||
self.__PrintEnsightFormatString = False
|
||||
+ self.__TimeStepToStartOutputAt=0
|
||||
+ self.__ForceOutputAtFirstCall=False
|
||||
+ self.__FirstTimeStepIndex = None
|
||||
|
||||
def SetPrintEnsightFormatString(self, enable):
|
||||
"""If outputting ExodusII files with the purpose of reading them into
|
||||
@@ -87,6 +80,17 @@
|
||||
"Incorrect argument type: %s, must be a dict" % type(frequencies))
|
||||
self.__InitialFrequencies = frequencies
|
||||
|
||||
+ def SetInitialOutputOptions(self, timeStepToStartOutputAt, forceOutputAtFirstCall):
|
||||
+ """Set the frequencies at which the pipeline needs to be updated.
|
||||
+ Typically, this is called by the subclass once it has determined what
|
||||
+ timesteps co-processing will be needed to be done.
|
||||
+ frequencies is a map, with key->string name of for the simulation
|
||||
+ input, and value is a list of frequencies.
|
||||
+ """
|
||||
+
|
||||
+ self.__TimeStepToStartOutputAt=timeStepToStartOutputAt
|
||||
+ self.__ForceOutputAtFirstCall=forceOutputAtFirstCall
|
||||
+
|
||||
def EnableLiveVisualization(self, enable, frequency = 1):
|
||||
"""Call this method to enable live-visualization. When enabled,
|
||||
DoLiveVisualization() will communicate with ParaView server if possible
|
||||
@@ -115,7 +119,7 @@
|
||||
# if this is a time step to do live then all of the inputs
|
||||
# must be made available. note that we want the pipeline built
|
||||
# before we do the actual first live connection.
|
||||
- if self.__EnableLiveVisualization and timestep % self.__LiveVisualizationFrequency == 0 \
|
||||
+ if self.__EnableLiveVisualization and self.NeedToOutput(timestep, self.__LiveVisualizationFrequency) \
|
||||
and self.__LiveVisualizationLink:
|
||||
if self.__LiveVisualizationLink.Initialize(servermanager.ActiveConnection.Session.GetSessionProxyManager()):
|
||||
num_inputs = datadescription.GetNumberOfInputDescriptions()
|
||||
@@ -132,13 +136,13 @@
|
||||
# hasn't been set up yet). If we don't have live enabled
|
||||
# we know that the output frequencies aren't changed and can
|
||||
# just use the initial frequencies.
|
||||
- if self.__InitialFrequencies or not self.__EnableLiveVisualization:
|
||||
+ if self.__ForceOutputAtFirstCall or self.__InitialFrequencies or not self.__EnableLiveVisualization:
|
||||
num_inputs = datadescription.GetNumberOfInputDescriptions()
|
||||
for cc in range(num_inputs):
|
||||
input_name = datadescription.GetInputDescriptionName(cc)
|
||||
|
||||
freqs = self.__InitialFrequencies.get(input_name, [])
|
||||
- if self.__EnableLiveVisualization or ( self and IsInModulo(timestep, freqs) ):
|
||||
+ if self.__EnableLiveVisualization or ( self and self.IsInModulo(timestep, freqs) ):
|
||||
datadescription.GetInputDescription(cc).AllFieldsOn()
|
||||
datadescription.GetInputDescription(cc).GenerateMeshOn()
|
||||
else:
|
||||
@@ -149,15 +153,14 @@
|
||||
for writer in self.__WritersList:
|
||||
frequency = writer.parameters.GetProperty(
|
||||
"WriteFrequency").GetElement(0)
|
||||
- if (timestep % frequency) == 0 or \
|
||||
- datadescription.GetForceOutput() == True:
|
||||
+ if self.NeedToOutput(timestep, frequency) or datadescription.GetForceOutput() == True:
|
||||
writerinputs = cpstate.locate_simulation_inputs(writer)
|
||||
for writerinput in writerinputs:
|
||||
datadescription.GetInputDescriptionByName(writerinput).AllFieldsOn()
|
||||
datadescription.GetInputDescriptionByName(writerinput).GenerateMeshOn()
|
||||
|
||||
for view in self.__ViewsList:
|
||||
- if (view.cpFrequency and timestep % view.cpFrequency == 0) or \
|
||||
+ if (view.cpFrequency and self.NeedToOutput(timestep, view.cpFrequency)) or \
|
||||
datadescription.GetForceOutput() == True:
|
||||
viewinputs = cpstate.locate_simulation_inputs_for_view(view)
|
||||
for viewinput in viewinputs:
|
||||
@@ -192,8 +195,7 @@
|
||||
for writer in self.__WritersList:
|
||||
frequency = writer.parameters.GetProperty(
|
||||
"WriteFrequency").GetElement(0)
|
||||
- if (timestep % frequency) == 0 or \
|
||||
- datadescription.GetForceOutput() == True:
|
||||
+ if self.NeedToOutput(timestep, frequency) or datadescription.GetForceOutput() == True:
|
||||
fileName = writer.parameters.GetProperty("FileName").GetElement(0)
|
||||
paddingamount = writer.parameters.GetProperty("PaddingAmount").GetElement(0)
|
||||
helperName = writer.GetXMLName()
|
||||
@@ -203,6 +205,23 @@
|
||||
else:
|
||||
ts = str(timestep).rjust(paddingamount, '0')
|
||||
writer.FileName = fileName.replace("%t", ts)
|
||||
+ if '/' in writer.FileName and createDirectoriesIfNeeded:
|
||||
+ oktowrite = [1.]
|
||||
+ import vtk
|
||||
+ comm = vtk.vtkMultiProcessController.GetGlobalController()
|
||||
+ if comm.GetLocalProcessId() == 0:
|
||||
+ import os
|
||||
+ newDir = writer.FileName[0:writer.FileName.rfind('/')]
|
||||
+ try:
|
||||
+ os.makedirs(newDir)
|
||||
+ except OSError:
|
||||
+ if not os.path.isdir(newDir):
|
||||
+ print ("ERROR: Cannot make directory for", writer.FileName, ". No data will be written.")
|
||||
+ oktowrite[0] = 0.
|
||||
+ comm.Broadcast(oktowrite, 1, 0)
|
||||
+ if oktowrite[0] == 0:
|
||||
+ # we can't make the directory so no reason to update the pipeline
|
||||
+ return
|
||||
writer.UpdatePipeline(datadescription.GetTime())
|
||||
|
||||
def WriteImages(self, datadescription, rescale_lookuptable=False,
|
||||
@@ -240,7 +259,7 @@
|
||||
|
||||
cinema_dirs = []
|
||||
for view in self.__ViewsList:
|
||||
- if (view.cpFrequency and timestep % view.cpFrequency == 0) or \
|
||||
+ if (view.cpFrequency and self.NeedToOutput(timestep, view.cpFrequency)) or \
|
||||
datadescription.GetForceOutput() == True:
|
||||
fname = view.cpFileName
|
||||
ts = str(timestep).rjust(padding_amount, '0')
|
||||
@@ -267,6 +286,24 @@
|
||||
if dirname:
|
||||
cinema_dirs.append(dirname)
|
||||
else:
|
||||
+ if '/' in fname and createDirectoriesIfNeeded:
|
||||
+ oktowrite = [1.]
|
||||
+ import vtk
|
||||
+ comm = vtk.vtkMultiProcessController.GetGlobalController()
|
||||
+ if comm.GetLocalProcessId() == 0:
|
||||
+ import os
|
||||
+ newDir = fname[0:fname.rfind('/')]
|
||||
+ try:
|
||||
+ os.makedirs(newDir)
|
||||
+ except OSError:
|
||||
+ if not os.path.isdir(newDir):
|
||||
+ print ("ERROR: Cannot make directory for", fname, ". No image will be output.")
|
||||
+ oktowrite[0] = 0.
|
||||
+ comm.Broadcast(oktowrite, 1, 0)
|
||||
+ if oktowrite[0] == 0:
|
||||
+ # we can't make the directory so no reason to update the pipeline
|
||||
+ return
|
||||
+
|
||||
if image_quality is None and fname.endswith('png'):
|
||||
# for png quality = 0 means no compression. compression can be a potentially
|
||||
# very costly serial operation on process 0
|
||||
@@ -307,7 +344,7 @@
|
||||
|
||||
|
||||
timeStep = datadescription.GetTimeStep()
|
||||
- if self.__EnableLiveVisualization and timeStep % self.__LiveVisualizationFrequency == 0:
|
||||
+ if self.__EnableLiveVisualization and self.NeedToOutput(timeStep, self.__LiveVisualizationFrequency):
|
||||
if not self.__LiveVisualizationLink.Initialize(servermanager.ActiveConnection.Session.GetSessionProxyManager()):
|
||||
return
|
||||
|
||||
@@ -412,7 +449,7 @@
|
||||
"""
|
||||
controller = servermanager.ParaViewPipelineController()
|
||||
# assume that a client only proxy with the same name as a writer
|
||||
- # is available in "insitu_writer_paramters"
|
||||
+ # is available in "insitu_writer_parameters"
|
||||
|
||||
# Since coprocessor sometimes pass writer as a custom object and not
|
||||
# a proxy, we need to handle that. Just creating any arbitrary writer
|
||||
@@ -666,3 +703,42 @@
|
||||
#restore what we showed
|
||||
pv_introspect.restore_visibility(pxystate)
|
||||
return os.path.basename(vfname)
|
||||
+
|
||||
+ def IsInModulo(self, timestep, frequencies):
|
||||
+ """
|
||||
+ Return True if the given timestep is in one of the provided frequency.
|
||||
+ This can be interpreted as follow::
|
||||
+
|
||||
+ isFM = IsInModulo(timestep-timeStepToStartOutputAt, [2,3,7])
|
||||
+
|
||||
+ is similar to::
|
||||
+
|
||||
+ isFM = (timestep-timeStepToStartOutputAt % 2 == 0) or (timestep-timeStepToStartOutputAt % 3 == 0) or (timestep-timeStepToStartOutputAt % 7 == 0)
|
||||
+
|
||||
+ The timeStepToStartOutputAt is the first timestep that will potentially be output.
|
||||
+ """
|
||||
+ if timestep < self.__TimeStepToStartOutputAt and not self.__ForceOutputAtFirstCall:
|
||||
+ return False
|
||||
+ for frequency in frequencies:
|
||||
+ if frequency > 0 and self.NeedToOutput(timestep, frequency):
|
||||
+ return True
|
||||
+
|
||||
+ return False
|
||||
+
|
||||
+
|
||||
+ def NeedToOutput(self, timestep, frequency):
|
||||
+ """
|
||||
+ Return True if we need to output based on the input timestep and frequency. Checks based
|
||||
+ __FirstTimeStepIndex, __FirstTimeStepIndex, __ForceOutputAtFirstCall and __TimeStepToStartOutputAt
|
||||
+ member variables.
|
||||
+ """
|
||||
+ if self.__FirstTimeStepIndex == None:
|
||||
+ self.__FirstTimeStepIndex = timestep
|
||||
+
|
||||
+ if self.__ForceOutputAtFirstCall and self.__FirstTimeStepIndex == timestep:
|
||||
+ return True
|
||||
+
|
||||
+ if self.__TimeStepToStartOutputAt <= timestep and (timestep-self.__TimeStepToStartOutputAt) % frequency == 0:
|
||||
+ return True
|
||||
+
|
||||
+ return False
|
48
var/spack/repos/builtin/packages/of-catalyst/package.py
Normal file
48
var/spack/repos/builtin/packages/of-catalyst/package.py
Normal file
@ -0,0 +1,48 @@
|
||||
# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
from spack import *
|
||||
|
||||
|
||||
class OfCatalyst(CMakePackage):
|
||||
"""Of-catalyst is a library for OpenFOAM that provides a runtime-selectable
|
||||
function object for embedding ParaView Catalyst in-situ visualization
|
||||
into arbitrary OpenFOAM simulations.
|
||||
Supports in-situ conversion of the following types:
|
||||
1) finite volume meshes and fields, single or multi-region;
|
||||
2) finite area meshes and fields, single region;
|
||||
3) lagrangian (clouds), single or multiple clouds.
|
||||
This offering is part of the community repository supported by OpenCFD Ltd,
|
||||
producer and distributor of the OpenFOAM software via www.openfoam.com,
|
||||
and owner of the OPENFOAM trademark.
|
||||
OpenCFD Ltd has been developing and releasing OpenFOAM since its debut
|
||||
in 2004.
|
||||
"""
|
||||
|
||||
# Currently only via git
|
||||
homepage = "https://develop.openfoam.com/Community/catalyst"
|
||||
git = "https://develop.openfoam.com/Community/catalyst.git"
|
||||
|
||||
version('develop', branch='develop')
|
||||
version('1806', tag='v1806')
|
||||
|
||||
variant('full', default=False, description='Build against paraview (full) or catalyst (light)')
|
||||
|
||||
depends_on('openfoam-com@1806', when='@1806', type=('build', 'link', 'run'))
|
||||
depends_on('openfoam-com@develop', when='@develop', type=('build', 'link', 'run'))
|
||||
depends_on('catalyst@5.5:', when='~full')
|
||||
depends_on('paraview@5.5:+osmesa~qt', when='+full')
|
||||
|
||||
root_cmakelists_dir = 'src/catalyst'
|
||||
|
||||
def cmake_args(self):
|
||||
"""Populate cmake arguments for ParaView."""
|
||||
cmake_args = [
|
||||
'-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=%s' % join_path(
|
||||
self.stage.source_path,
|
||||
'spack-build')
|
||||
]
|
||||
|
||||
return cmake_args
|
@ -405,16 +405,16 @@ def setup_environment(self, spack_env, run_env):
|
||||
|
||||
# Unneeded bits
|
||||
# -------------
|
||||
'FOAM_SETTINGS', # Do not use with modules
|
||||
'FOAM_INST_DIR', # Old
|
||||
'FOAM_(APP|ETC|SRC|SOLVERS|UTILITIES)',
|
||||
# 'FOAM_SETTINGS', # Do not use with modules
|
||||
# 'FOAM_INST_DIR', # Old
|
||||
# 'FOAM_(APP|ETC|SRC|SOLVERS|UTILITIES)',
|
||||
# 'FOAM_TUTORIALS', # can be useful
|
||||
'WM_OSTYPE', # Purely optional value
|
||||
# 'WM_OSTYPE', # Purely optional value
|
||||
|
||||
# Third-party cruft - only used for orig compilation
|
||||
# -----------------
|
||||
'[A-Z].*_ARCH_PATH',
|
||||
'(KAHIP|METIS|SCOTCH)_VERSION',
|
||||
# '(KAHIP|METIS|SCOTCH)_VERSION',
|
||||
|
||||
# User-specific
|
||||
# -------------
|
||||
@ -426,6 +426,7 @@ def setup_environment(self, spack_env, run_env):
|
||||
])
|
||||
|
||||
run_env.extend(mods)
|
||||
spack_env.extend(mods)
|
||||
minimal = False
|
||||
tty.info('OpenFOAM bashrc env: {0}'.format(bashrc))
|
||||
except Exception:
|
||||
@ -436,8 +437,11 @@ def setup_environment(self, spack_env, run_env):
|
||||
tty.info('OpenFOAM minimal env {0}'.format(self.prefix))
|
||||
run_env.set('FOAM_PROJECT_DIR', self.projectdir)
|
||||
run_env.set('WM_PROJECT_DIR', self.projectdir)
|
||||
spack_env.set('FOAM_PROJECT_DIR', self.projectdir)
|
||||
spack_env.set('WM_PROJECT_DIR', self.projectdir)
|
||||
for d in ['wmake', self.archbin]: # bin added automatically
|
||||
run_env.prepend_path('PATH', join_path(self.projectdir, d))
|
||||
spack_env.prepend_path('PATH', join_path(self.projectdir, d))
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
"""Location of the OpenFOAM project directory.
|
||||
@ -445,7 +449,7 @@ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
variable since it would mask the normal OpenFOAM cleanup of
|
||||
previous versions.
|
||||
"""
|
||||
spack_env.set('FOAM_PROJECT_DIR', self.projectdir)
|
||||
self.setup_environment(spack_env, run_env)
|
||||
|
||||
@property
|
||||
def projectdir(self):
|
||||
|
@ -59,7 +59,8 @@ class Paraview(CMakePackage):
|
||||
depends_on('libpng')
|
||||
depends_on('libtiff')
|
||||
depends_on('libxml2')
|
||||
# depends_on('netcdf')
|
||||
depends_on('netcdf')
|
||||
depends_on('expat')
|
||||
# depends_on('netcdf-cxx')
|
||||
# depends_on('protobuf') # version mismatches?
|
||||
# depends_on('sqlite') # external version not supported
|
||||
@ -74,6 +75,9 @@ class Paraview(CMakePackage):
|
||||
# Broken installation (ui_pqExportStateWizard.h) - fixed in 5.2.0
|
||||
patch('ui_pqExportStateWizard.patch', when='@:5.1.2')
|
||||
|
||||
# Broken vtk-m config. Upstream catalyst changes
|
||||
patch('vtkm-catalyst-pv551.patch', when='@5.5.0:5.5.2')
|
||||
|
||||
def url_for_version(self, version):
|
||||
"""Handle ParaView version-based custom URLs."""
|
||||
if version < Version('5.1.0'):
|
||||
@ -81,34 +85,50 @@ def url_for_version(self, version):
|
||||
else:
|
||||
return self._urlfmt.format(version.up_to(2), version, '')
|
||||
|
||||
@property
|
||||
def paraview_subdir(self):
|
||||
"""The paraview subdirectory name as paraview-major.minor"""
|
||||
return 'paraview-{0}'.format(self.spec.version.up_to(2))
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
if os.path.isdir(self.prefix.lib64):
|
||||
lib_dir = self.prefix.lib64
|
||||
else:
|
||||
lib_dir = self.prefix.lib
|
||||
paraview_version = 'paraview-%s' % self.spec.version.up_to(2)
|
||||
spack_env.set('ParaView_DIR', self.prefix)
|
||||
spack_env.set('PARAVIEW_VTK_DIR',
|
||||
join_path(lib_dir, 'cmake', paraview_version))
|
||||
join_path(lib_dir, 'cmake', self.paraview_subdir))
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
# paraview 5.5 and later
|
||||
# - cmake under lib/cmake/paraview-5.5
|
||||
# - libs under lib
|
||||
# - python bits under lib/python2.8/site-packages
|
||||
if os.path.isdir(self.prefix.lib64):
|
||||
lib_dir = self.prefix.lib64
|
||||
else:
|
||||
lib_dir = self.prefix.lib
|
||||
paraview_version = 'paraview-%s' % self.spec.version.up_to(2)
|
||||
run_env.prepend_path('LIBRARY_PATH', join_path(lib_dir,
|
||||
paraview_version))
|
||||
run_env.prepend_path('LD_LIBRARY_PATH', join_path(lib_dir,
|
||||
paraview_version))
|
||||
|
||||
run_env.set('ParaView_DIR', self.prefix)
|
||||
run_env.set('PARAVIEW_VTK_DIR',
|
||||
join_path(lib_dir, 'cmake', paraview_version))
|
||||
join_path(lib_dir, 'cmake', self.paraview_subdir))
|
||||
|
||||
if self.spec.version <= Version('5.4.1'):
|
||||
lib_dir = join_path(lib_dir, self.paraview_subdir)
|
||||
|
||||
run_env.prepend_path('LIBRARY_PATH', lib_dir)
|
||||
run_env.prepend_path('LD_LIBRARY_PATH', lib_dir)
|
||||
|
||||
if '+python' in self.spec:
|
||||
run_env.prepend_path('PYTHONPATH', join_path(lib_dir,
|
||||
paraview_version))
|
||||
run_env.prepend_path('PYTHONPATH', join_path(lib_dir,
|
||||
paraview_version, 'site-packages'))
|
||||
run_env.prepend_path('PYTHONPATH', join_path(lib_dir,
|
||||
paraview_version, 'site-packages', 'vtk'))
|
||||
if self.spec.version <= Version('5.4.1'):
|
||||
pv_pydir = join_path(lib_dir, 'site-packages')
|
||||
run_env.prepend_path('PYTHONPATH', pv_pydir)
|
||||
run_env.prepend_path('PYTHONPATH', join_path(pv_pydir, 'vtk'))
|
||||
else:
|
||||
python_version = self.spec['python'].version.up_to(2)
|
||||
run_env.prepend_path('PYTHONPATH', join_path(lib_dir,
|
||||
'python{0}'.format(python_version),
|
||||
'site-packages'))
|
||||
|
||||
def cmake_args(self):
|
||||
"""Populate cmake arguments for ParaView."""
|
||||
@ -139,7 +159,8 @@ def nvariant_bool(feature):
|
||||
'-DVTK_USE_SYSTEM_HDF5:BOOL=%s' % variant_bool('+hdf5'),
|
||||
'-DVTK_USE_SYSTEM_JPEG:BOOL=ON',
|
||||
'-DVTK_USE_SYSTEM_LIBXML2:BOOL=ON',
|
||||
'-DVTK_USE_SYSTEM_NETCDF:BOOL=OFF',
|
||||
'-DVTK_USE_SYSTEM_NETCDF:BOOL=ON',
|
||||
'-DVTK_USE_SYSTEM_EXPAT:BOOL=ON',
|
||||
'-DVTK_USE_SYSTEM_TIFF:BOOL=ON',
|
||||
'-DVTK_USE_SYSTEM_ZLIB:BOOL=ON',
|
||||
]
|
||||
|
@ -0,0 +1,510 @@
|
||||
# The VTK-m changes are slated for paraview-5.5.x
|
||||
#
|
||||
# The catalyst changes (the working directory for output) are slated for
|
||||
# paraview-5.6.
|
||||
# They are API-compatible with paraview-5.5 but not ABI compatible.
|
||||
#
|
||||
# https://gitlab.kitware.com/vtk/vtk-m/merge_requests/1166
|
||||
# https://gitlab.kitware.com/paraview/paraview/merge_requests/2433
|
||||
# https://gitlab.kitware.com/paraview/paraview/merge_requests/2436
|
||||
#
|
||||
--- ParaView-v5.5.0/VTK/ThirdParty/vtkm/vtk-m/CMake/VTKmDetermineVersion.cmake.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ ParaView-v5.5.0/VTK/ThirdParty/vtkm/vtk-m/CMake/VTKmDetermineVersion.cmake 2018-04-23 12:00:23.708544206 +0200
|
||||
@@ -51,6 +51,8 @@
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE)
|
||||
+ else()
|
||||
+ set(output)
|
||||
endif()
|
||||
else()
|
||||
set(result 0)
|
||||
@@ -75,7 +77,7 @@
|
||||
|
||||
# Extracts components from a version string. See determine_version() for usage.
|
||||
function(extract_version_components version_string var_prefix)
|
||||
- string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)[-]*(.*)"
|
||||
+ string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)[-]*(.*)$"
|
||||
version_matches "${version_string}")
|
||||
if(CMAKE_MATCH_0)
|
||||
set(full ${CMAKE_MATCH_0})
|
||||
--- ParaView-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.cxx.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ ParaView-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.cxx 2018-05-11 12:02:26.894772713 +0200
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "vtkStringArray.h"
|
||||
|
||||
#include <list>
|
||||
+#include <vtksys/SystemTools.hxx>
|
||||
|
||||
struct vtkCPProcessorInternals
|
||||
{
|
||||
@@ -47,12 +48,13 @@
|
||||
};
|
||||
|
||||
vtkStandardNewMacro(vtkCPProcessor);
|
||||
-vtkMultiProcessController* vtkCPProcessor::Controller = NULL;
|
||||
+vtkMultiProcessController* vtkCPProcessor::Controller = nullptr;
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCPProcessor::vtkCPProcessor()
|
||||
{
|
||||
this->Internal = new vtkCPProcessorInternals;
|
||||
- this->InitializationHelper = NULL;
|
||||
+ this->InitializationHelper = nullptr;
|
||||
+ this->WorkingDirectory = nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -61,14 +63,15 @@
|
||||
if (this->Internal)
|
||||
{
|
||||
delete this->Internal;
|
||||
- this->Internal = NULL;
|
||||
+ this->Internal = nullptr;
|
||||
}
|
||||
|
||||
if (this->InitializationHelper)
|
||||
{
|
||||
this->InitializationHelper->Delete();
|
||||
- this->InitializationHelper = NULL;
|
||||
+ this->InitializationHelper = nullptr;
|
||||
}
|
||||
+ this->SetWorkingDirectory(nullptr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -95,7 +98,7 @@
|
||||
{
|
||||
if (which < 0 || which >= this->GetNumberOfPipelines())
|
||||
{
|
||||
- return NULL;
|
||||
+ return nullptr;
|
||||
}
|
||||
int counter = 0;
|
||||
vtkCPProcessorInternals::PipelineListIterator iter = this->Internal->Pipelines.begin();
|
||||
@@ -108,7 +111,7 @@
|
||||
counter++;
|
||||
iter++;
|
||||
}
|
||||
- return NULL;
|
||||
+ return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -130,17 +133,41 @@
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
-int vtkCPProcessor::Initialize()
|
||||
+int vtkCPProcessor::Initialize(const char* workingDirectory)
|
||||
{
|
||||
- if (this->InitializationHelper == NULL)
|
||||
+ if (this->InitializationHelper == nullptr)
|
||||
{
|
||||
this->InitializationHelper = this->NewInitializationHelper();
|
||||
}
|
||||
+ // make sure the directory exists here so that we only do it once
|
||||
+ if (workingDirectory)
|
||||
+ {
|
||||
+ vtkMultiProcessController* controller = vtkMultiProcessController::GetGlobalController();
|
||||
+ int success = 1;
|
||||
+ if (controller == nullptr || controller->GetLocalProcessId() == 0)
|
||||
+ {
|
||||
+ success = vtksys::SystemTools::MakeDirectory(workingDirectory) == true ? 1 : 0;
|
||||
+ if (success == 0)
|
||||
+ {
|
||||
+ vtkWarningMacro("Could not make "
|
||||
+ << workingDirectory << " directory. "
|
||||
+ << "Results will be generated in current working directory instead.");
|
||||
+ }
|
||||
+ }
|
||||
+ if (controller)
|
||||
+ {
|
||||
+ controller->Broadcast(&success, 1, 0);
|
||||
+ }
|
||||
+ if (success)
|
||||
+ {
|
||||
+ this->SetWorkingDirectory(workingDirectory);
|
||||
+ }
|
||||
+ }
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
-int vtkCPProcessor::Initialize(vtkMPICommunicatorOpaqueComm& comm)
|
||||
+int vtkCPProcessor::Initialize(vtkMPICommunicatorOpaqueComm& comm, const char* workingDirectory)
|
||||
{
|
||||
#ifdef PARAVIEW_USE_MPI
|
||||
if (vtkCPProcessor::Controller)
|
||||
@@ -148,7 +175,7 @@
|
||||
vtkErrorMacro("Can only initialize with a communicator once per process.");
|
||||
return 0;
|
||||
}
|
||||
- if (this->InitializationHelper == NULL)
|
||||
+ if (this->InitializationHelper == nullptr)
|
||||
{
|
||||
vtkMPICommunicator* communicator = vtkMPICommunicator::New();
|
||||
communicator->InitializeExternal(&comm);
|
||||
@@ -157,12 +184,12 @@
|
||||
this->Controller = controller;
|
||||
this->Controller->SetGlobalController(controller);
|
||||
communicator->Delete();
|
||||
- return this->Initialize();
|
||||
+ return this->Initialize(workingDirectory);
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
static_cast<void>(&comm); // get rid of variable not used warning
|
||||
- return this->Initialize();
|
||||
+ return this->Initialize(workingDirectory);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -225,6 +252,13 @@
|
||||
input->GetFieldData()->AddArray(catalystChannel);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ std::string originalWorkingDirectory;
|
||||
+ if (this->WorkingDirectory)
|
||||
+ {
|
||||
+ originalWorkingDirectory = vtksys::SystemTools::GetCurrentWorkingDirectory();
|
||||
+ vtksys::SystemTools::ChangeDirectory(this->WorkingDirectory);
|
||||
+ }
|
||||
for (vtkCPProcessorInternals::PipelineListIterator iter = this->Internal->Pipelines.begin();
|
||||
iter != this->Internal->Pipelines.end(); iter++)
|
||||
{
|
||||
@@ -248,6 +282,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (originalWorkingDirectory.empty() == false)
|
||||
+ {
|
||||
+ vtksys::SystemTools::ChangeDirectory(originalWorkingDirectory);
|
||||
+ }
|
||||
// we want to reset everything here to make sure that new information
|
||||
// is properly passed in the next time.
|
||||
dataDescription->ResetAll();
|
||||
@@ -259,7 +297,7 @@
|
||||
{
|
||||
if (this->Controller)
|
||||
{
|
||||
- this->Controller->SetGlobalController(NULL);
|
||||
+ this->Controller->SetGlobalController(nullptr);
|
||||
this->Controller->Finalize(1);
|
||||
this->Controller->Delete();
|
||||
}
|
||||
--- ParaView-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.h.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ ParaView-v5.5.0/CoProcessing/Catalyst/vtkCPProcessor.h 2018-05-11 12:02:26.894772713 +0200
|
||||
@@ -76,14 +76,16 @@
|
||||
virtual void RemoveAllPipelines();
|
||||
|
||||
/// Initialize the co-processor. Returns 1 if successful and 0
|
||||
- /// otherwise.
|
||||
/// otherwise. If Catalyst is built with MPI then Initialize()
|
||||
/// can also be called with a specific MPI communicator if
|
||||
/// MPI_COMM_WORLD isn't the proper one. Catalyst is initialized
|
||||
- /// to use MPI_COMM_WORLD by default.
|
||||
- virtual int Initialize();
|
||||
+ /// to use MPI_COMM_WORLD by default. Both methods have an optional
|
||||
+ /// workingDirectory argument which will set *WorkingDirectory* so
|
||||
+ /// that files will be put relative to this directory.
|
||||
+ virtual int Initialize(const char* workingDirectory = nullptr);
|
||||
#ifndef __WRAP__
|
||||
- virtual int Initialize(vtkMPICommunicatorOpaqueComm& comm);
|
||||
+ virtual int Initialize(
|
||||
+ vtkMPICommunicatorOpaqueComm& comm, const char* workingDirectory = nullptr);
|
||||
#endif
|
||||
|
||||
/// The Catalyst input field data string array name. This array will
|
||||
@@ -111,6 +113,13 @@
|
||||
/// implementation an opportunity to clean up, before it is destroyed.
|
||||
virtual int Finalize();
|
||||
|
||||
+ /// Get the current working directory for outputting Catalyst files.
|
||||
+ /// If not set then Catalyst output files will be relative to the
|
||||
+ /// current working directory. This will not affect where Catalyst
|
||||
+ /// looks for Python scripts. *WorkingDirectory* gets set through
|
||||
+ /// the *Initialize()* methods.
|
||||
+ vtkGetStringMacro(WorkingDirectory);
|
||||
+
|
||||
protected:
|
||||
vtkCPProcessor();
|
||||
virtual ~vtkCPProcessor();
|
||||
@@ -118,6 +127,11 @@
|
||||
/// Create a new instance of the InitializationHelper.
|
||||
virtual vtkObject* NewInitializationHelper();
|
||||
|
||||
+ /// Set the current working directory for outputting Catalyst files.
|
||||
+ /// This is a protected method since simulation code adaptors should
|
||||
+ /// set this through the *Initialize()* methods.
|
||||
+ vtkSetStringMacro(WorkingDirectory);
|
||||
+
|
||||
private:
|
||||
vtkCPProcessor(const vtkCPProcessor&) = delete;
|
||||
void operator=(const vtkCPProcessor&) = delete;
|
||||
@@ -125,6 +139,7 @@
|
||||
vtkCPProcessorInternals* Internal;
|
||||
vtkObject* InitializationHelper;
|
||||
static vtkMultiProcessController* Controller;
|
||||
+ char* WorkingDirectory;
|
||||
};
|
||||
|
||||
#endif
|
||||
--- ParaView-v5.5.0/CoProcessing/Catalyst/vtkCPXMLPWriterPipeline.cxx.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ ParaView-v5.5.0/CoProcessing/Catalyst/vtkCPXMLPWriterPipeline.cxx 2018-05-11 12:02:26.894772713 +0200
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
+#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -174,7 +175,7 @@
|
||||
|
||||
for (unsigned int i = 0; i < dataDescription->GetNumberOfInputDescriptions(); i++)
|
||||
{
|
||||
- const char* inputName = dataDescription->GetInputDescriptionName(i);
|
||||
+ std::string inputName = dataDescription->GetInputDescriptionName(i);
|
||||
vtkCPInputDataDescription* idd = dataDescription->GetInputDescription(i);
|
||||
vtkDataObject* grid = idd->GetGrid();
|
||||
if (grid == nullptr)
|
||||
@@ -206,6 +207,8 @@
|
||||
vtkSMStringVectorProperty* fileName =
|
||||
vtkSMStringVectorProperty::SafeDownCast(writer->GetProperty("FileName"));
|
||||
|
||||
+ // If we have a / in the channel name we take it out of the filename we're going to write to
|
||||
+ inputName.erase(std::remove(inputName.begin(), inputName.end(), '/'), inputName.end());
|
||||
std::ostringstream o;
|
||||
if (this->Path.empty() == false)
|
||||
{
|
||||
--- ParaView-v5.5.0/Wrapping/Python/paraview/coprocessing.py.orig 2018-04-06 22:03:33.000000000 +0200
|
||||
+++ ParaView-v5.5.0/Wrapping/Python/paraview/coprocessing.py 2018-05-11 12:02:27.038772408 +0200
|
||||
@@ -11,22 +11,12 @@
|
||||
from paraview.vtk.vtkPVVTKExtensionsCore import *
|
||||
import math
|
||||
|
||||
-# -----------------------------------------------------------------------------
|
||||
-def IsInModulo(timestep, frequencyArray):
|
||||
- """
|
||||
- Return True if the given timestep is in one of the provided frequency.
|
||||
- This can be interpreted as follow::
|
||||
-
|
||||
- isFM = IsInModulo(timestep, [2,3,7])
|
||||
-
|
||||
- is similar to::
|
||||
+# If the user created a filename in a location that doesn't exist by default we'll
|
||||
+# make the directory for them. This can be changed though by setting createDirectoriesIfNeeded
|
||||
+# to False.
|
||||
+createDirectoriesIfNeeded = True
|
||||
|
||||
- isFM = (timestep % 2 == 0) or (timestep % 3 == 0) or (timestep % 7 == 0)
|
||||
- """
|
||||
- for frequency in frequencyArray:
|
||||
- if frequency > 0 and (timestep % frequency == 0):
|
||||
- return True
|
||||
- return False
|
||||
+# -----------------------------------------------------------------------------
|
||||
|
||||
class CoProcessor(object):
|
||||
"""Base class for co-processing Pipelines.
|
||||
@@ -68,6 +58,9 @@
|
||||
self.__CinemaTracks = {}
|
||||
self.__InitialFrequencies = {}
|
||||
self.__PrintEnsightFormatString = False
|
||||
+ self.__TimeStepToStartOutputAt=0
|
||||
+ self.__ForceOutputAtFirstCall=False
|
||||
+ self.__FirstTimeStepIndex = None
|
||||
|
||||
def SetPrintEnsightFormatString(self, enable):
|
||||
"""If outputting ExodusII files with the purpose of reading them into
|
||||
@@ -87,6 +80,17 @@
|
||||
"Incorrect argument type: %s, must be a dict" % type(frequencies))
|
||||
self.__InitialFrequencies = frequencies
|
||||
|
||||
+ def SetInitialOutputOptions(self, timeStepToStartOutputAt, forceOutputAtFirstCall):
|
||||
+ """Set the frequencies at which the pipeline needs to be updated.
|
||||
+ Typically, this is called by the subclass once it has determined what
|
||||
+ timesteps co-processing will be needed to be done.
|
||||
+ frequencies is a map, with key->string name of for the simulation
|
||||
+ input, and value is a list of frequencies.
|
||||
+ """
|
||||
+
|
||||
+ self.__TimeStepToStartOutputAt=timeStepToStartOutputAt
|
||||
+ self.__ForceOutputAtFirstCall=forceOutputAtFirstCall
|
||||
+
|
||||
def EnableLiveVisualization(self, enable, frequency = 1):
|
||||
"""Call this method to enable live-visualization. When enabled,
|
||||
DoLiveVisualization() will communicate with ParaView server if possible
|
||||
@@ -115,7 +119,7 @@
|
||||
# if this is a time step to do live then all of the inputs
|
||||
# must be made available. note that we want the pipeline built
|
||||
# before we do the actual first live connection.
|
||||
- if self.__EnableLiveVisualization and timestep % self.__LiveVisualizationFrequency == 0 \
|
||||
+ if self.__EnableLiveVisualization and self.NeedToOutput(timestep, self.__LiveVisualizationFrequency) \
|
||||
and self.__LiveVisualizationLink:
|
||||
if self.__LiveVisualizationLink.Initialize(servermanager.ActiveConnection.Session.GetSessionProxyManager()):
|
||||
num_inputs = datadescription.GetNumberOfInputDescriptions()
|
||||
@@ -132,13 +136,13 @@
|
||||
# hasn't been set up yet). If we don't have live enabled
|
||||
# we know that the output frequencies aren't changed and can
|
||||
# just use the initial frequencies.
|
||||
- if self.__InitialFrequencies or not self.__EnableLiveVisualization:
|
||||
+ if self.__ForceOutputAtFirstCall or self.__InitialFrequencies or not self.__EnableLiveVisualization:
|
||||
num_inputs = datadescription.GetNumberOfInputDescriptions()
|
||||
for cc in range(num_inputs):
|
||||
input_name = datadescription.GetInputDescriptionName(cc)
|
||||
|
||||
freqs = self.__InitialFrequencies.get(input_name, [])
|
||||
- if self.__EnableLiveVisualization or ( self and IsInModulo(timestep, freqs) ):
|
||||
+ if self.__EnableLiveVisualization or ( self and self.IsInModulo(timestep, freqs) ):
|
||||
datadescription.GetInputDescription(cc).AllFieldsOn()
|
||||
datadescription.GetInputDescription(cc).GenerateMeshOn()
|
||||
else:
|
||||
@@ -149,15 +153,14 @@
|
||||
for writer in self.__WritersList:
|
||||
frequency = writer.parameters.GetProperty(
|
||||
"WriteFrequency").GetElement(0)
|
||||
- if (timestep % frequency) == 0 or \
|
||||
- datadescription.GetForceOutput() == True:
|
||||
+ if self.NeedToOutput(timestep, frequency) or datadescription.GetForceOutput() == True:
|
||||
writerinputs = cpstate.locate_simulation_inputs(writer)
|
||||
for writerinput in writerinputs:
|
||||
datadescription.GetInputDescriptionByName(writerinput).AllFieldsOn()
|
||||
datadescription.GetInputDescriptionByName(writerinput).GenerateMeshOn()
|
||||
|
||||
for view in self.__ViewsList:
|
||||
- if (view.cpFrequency and timestep % view.cpFrequency == 0) or \
|
||||
+ if (view.cpFrequency and self.NeedToOutput(timestep, view.cpFrequency)) or \
|
||||
datadescription.GetForceOutput() == True:
|
||||
viewinputs = cpstate.locate_simulation_inputs_for_view(view)
|
||||
for viewinput in viewinputs:
|
||||
@@ -192,8 +195,7 @@
|
||||
for writer in self.__WritersList:
|
||||
frequency = writer.parameters.GetProperty(
|
||||
"WriteFrequency").GetElement(0)
|
||||
- if (timestep % frequency) == 0 or \
|
||||
- datadescription.GetForceOutput() == True:
|
||||
+ if self.NeedToOutput(timestep, frequency) or datadescription.GetForceOutput() == True:
|
||||
fileName = writer.parameters.GetProperty("FileName").GetElement(0)
|
||||
paddingamount = writer.parameters.GetProperty("PaddingAmount").GetElement(0)
|
||||
helperName = writer.GetXMLName()
|
||||
@@ -203,6 +205,23 @@
|
||||
else:
|
||||
ts = str(timestep).rjust(paddingamount, '0')
|
||||
writer.FileName = fileName.replace("%t", ts)
|
||||
+ if '/' in writer.FileName and createDirectoriesIfNeeded:
|
||||
+ oktowrite = [1.]
|
||||
+ import vtk
|
||||
+ comm = vtk.vtkMultiProcessController.GetGlobalController()
|
||||
+ if comm.GetLocalProcessId() == 0:
|
||||
+ import os
|
||||
+ newDir = writer.FileName[0:writer.FileName.rfind('/')]
|
||||
+ try:
|
||||
+ os.makedirs(newDir)
|
||||
+ except OSError:
|
||||
+ if not os.path.isdir(newDir):
|
||||
+ print ("ERROR: Cannot make directory for", writer.FileName, ". No data will be written.")
|
||||
+ oktowrite[0] = 0.
|
||||
+ comm.Broadcast(oktowrite, 1, 0)
|
||||
+ if oktowrite[0] == 0:
|
||||
+ # we can't make the directory so no reason to update the pipeline
|
||||
+ return
|
||||
writer.UpdatePipeline(datadescription.GetTime())
|
||||
|
||||
def WriteImages(self, datadescription, rescale_lookuptable=False,
|
||||
@@ -240,7 +259,7 @@
|
||||
|
||||
cinema_dirs = []
|
||||
for view in self.__ViewsList:
|
||||
- if (view.cpFrequency and timestep % view.cpFrequency == 0) or \
|
||||
+ if (view.cpFrequency and self.NeedToOutput(timestep, view.cpFrequency)) or \
|
||||
datadescription.GetForceOutput() == True:
|
||||
fname = view.cpFileName
|
||||
ts = str(timestep).rjust(padding_amount, '0')
|
||||
@@ -267,6 +286,24 @@
|
||||
if dirname:
|
||||
cinema_dirs.append(dirname)
|
||||
else:
|
||||
+ if '/' in fname and createDirectoriesIfNeeded:
|
||||
+ oktowrite = [1.]
|
||||
+ import vtk
|
||||
+ comm = vtk.vtkMultiProcessController.GetGlobalController()
|
||||
+ if comm.GetLocalProcessId() == 0:
|
||||
+ import os
|
||||
+ newDir = fname[0:fname.rfind('/')]
|
||||
+ try:
|
||||
+ os.makedirs(newDir)
|
||||
+ except OSError:
|
||||
+ if not os.path.isdir(newDir):
|
||||
+ print ("ERROR: Cannot make directory for", fname, ". No image will be output.")
|
||||
+ oktowrite[0] = 0.
|
||||
+ comm.Broadcast(oktowrite, 1, 0)
|
||||
+ if oktowrite[0] == 0:
|
||||
+ # we can't make the directory so no reason to update the pipeline
|
||||
+ return
|
||||
+
|
||||
if image_quality is None and fname.endswith('png'):
|
||||
# for png quality = 0 means no compression. compression can be a potentially
|
||||
# very costly serial operation on process 0
|
||||
@@ -307,7 +344,7 @@
|
||||
|
||||
|
||||
timeStep = datadescription.GetTimeStep()
|
||||
- if self.__EnableLiveVisualization and timeStep % self.__LiveVisualizationFrequency == 0:
|
||||
+ if self.__EnableLiveVisualization and self.NeedToOutput(timeStep, self.__LiveVisualizationFrequency):
|
||||
if not self.__LiveVisualizationLink.Initialize(servermanager.ActiveConnection.Session.GetSessionProxyManager()):
|
||||
return
|
||||
|
||||
@@ -412,7 +449,7 @@
|
||||
"""
|
||||
controller = servermanager.ParaViewPipelineController()
|
||||
# assume that a client only proxy with the same name as a writer
|
||||
- # is available in "insitu_writer_paramters"
|
||||
+ # is available in "insitu_writer_parameters"
|
||||
|
||||
# Since coprocessor sometimes pass writer as a custom object and not
|
||||
# a proxy, we need to handle that. Just creating any arbitrary writer
|
||||
@@ -666,3 +703,42 @@
|
||||
#restore what we showed
|
||||
pv_introspect.restore_visibility(pxystate)
|
||||
return os.path.basename(vfname)
|
||||
+
|
||||
+ def IsInModulo(self, timestep, frequencies):
|
||||
+ """
|
||||
+ Return True if the given timestep is in one of the provided frequency.
|
||||
+ This can be interpreted as follow::
|
||||
+
|
||||
+ isFM = IsInModulo(timestep-timeStepToStartOutputAt, [2,3,7])
|
||||
+
|
||||
+ is similar to::
|
||||
+
|
||||
+ isFM = (timestep-timeStepToStartOutputAt % 2 == 0) or (timestep-timeStepToStartOutputAt % 3 == 0) or (timestep-timeStepToStartOutputAt % 7 == 0)
|
||||
+
|
||||
+ The timeStepToStartOutputAt is the first timestep that will potentially be output.
|
||||
+ """
|
||||
+ if timestep < self.__TimeStepToStartOutputAt and not self.__ForceOutputAtFirstCall:
|
||||
+ return False
|
||||
+ for frequency in frequencies:
|
||||
+ if frequency > 0 and self.NeedToOutput(timestep, frequency):
|
||||
+ return True
|
||||
+
|
||||
+ return False
|
||||
+
|
||||
+
|
||||
+ def NeedToOutput(self, timestep, frequency):
|
||||
+ """
|
||||
+ Return True if we need to output based on the input timestep and frequency. Checks based
|
||||
+ __FirstTimeStepIndex, __FirstTimeStepIndex, __ForceOutputAtFirstCall and __TimeStepToStartOutputAt
|
||||
+ member variables.
|
||||
+ """
|
||||
+ if self.__FirstTimeStepIndex == None:
|
||||
+ self.__FirstTimeStepIndex = timestep
|
||||
+
|
||||
+ if self.__ForceOutputAtFirstCall and self.__FirstTimeStepIndex == timestep:
|
||||
+ return True
|
||||
+
|
||||
+ if self.__TimeStepToStartOutputAt <= timestep and (timestep-self.__TimeStepToStartOutputAt) % frequency == 0:
|
||||
+ return True
|
||||
+
|
||||
+ return False
|
Loading…
Reference in New Issue
Block a user