Commit dc574a3e authored by T.J. Corona's avatar T.J. Corona

Refactor operators.

This commit contains many changes made by Haocheng, David and myself.
It performs the following:

a) move operators out of model and have them operate indpendently from
   model sessions
b) operators now each have their own attribute collection, rather than being
   represented as single attributes from an attribute collection
c) Separate XML descriptions from the base operator, loosening the requirement
   on operators to simply have a descriptive attribute (XML descriptions are
   now supported as a subclass of the base operator). This facilitates the
   construction of python operators without requiring an XML string describing
   their inputs
c) introduce an operation manager that tracks the availability of operators.
   It has the following properties:
   i.   Registration of operators via a unique name (usually the c++ name of
        the operator)
   ii.  Provide a connection to a resource manager so that operations that
        construct resources will automatically register the new resources to
        the manager
   iii. Provide a list of available operators given an input selection (i.e.
        show which operators accept a given input)
d) allow read/write locks on operations' input resources and add tests for
   asynchronous operations
e) break static registration of operations and resources into a set of
   libraries that accompany the libraries in which they are defined. A library
   that provides static registration of a resource and associated operations
   for library smtkFoo is called smtkFooEnvironment, and the registration
   occurs in the foo::environment namespace
f) deprecate the exodus session
g) convert smtk::model and polygon, mesh and discrete sessions to use
   nlohmann::json instead of cJSON. With this change, we can hopefully remove
   cJSON from smtk
h) provide operations for creating, loading and saving smtk resources
i) update tests to use the new operation framework

This merge is a work in progress, but has become too large to avoid merging
into the msater branch. The outstanding issues are

a) remove smtk::model::Operation from smtk (it is still required for the qt
   bindings)
b) rename smtk::operation::NewOp smtk::operation::Operator
c) fix Qt bindings to use the new operation infrastructure
d) fix the infrastructure for meshing interop with remus to avoid using json
   fragments
e) remove cJSON from smtk
f) switch resources' read/write/create methods from bare functors to smtk
   operators. This is more in keeping with the pattern of using operators to
   affect resources
g) enable CGM session
h) enable matplotlib extension
parent b143ed2f
function(encodeStringAsPyVariable rawString encodedVarName stringOut)
string(CONFIGURE "\ndescription = '''\n${${rawString}}\n'''\n" pyString)
set(${stringOut} "${pyString}" PARENT_SCOPE)
endfunction()
function(configureStringAsPyVariable rawString dstFileName encodedVarName)
encodeStringAsPyVariable(${rawString} ${encodedVarName} encodedContents)
if (EXISTS ${dstFileName})
file(READ ${dstFileName} already)
endif()
#message("Writing ${dstFileName}")
if (NOT "${encodedContents}" STREQUAL "${already}")
file(WRITE ${dstFileName} "${encodedContents}")
endif()
endfunction()
function(configureFileAsPyVariable srcFileName dstFileName encodedVarName)
if (EXISTS ${srcFileName})
file(READ ${srcFileName} fileContents)
configureStringAsPyVariable(fileContents ${dstFileName} ${encodedVarName})
else()
file(REMOVE ${dstFileName})
endif()
endfunction()
# Example:
# configureFileAsPyVariable("foo.xml" "bar.py" "operatorSpec")
# would read "foo.xml" and write the assigment:
# operatorSpec = '''
# ...
# '''
# into bar.py (where "..." is the encoded contents of "foo.xml").
#
# When srcFileName does not exist, then dstFileName will be
# removed so that missing files are more easily spotted.
# Note that since this configuration is done when CMake runs
# you must re-run CMake in order to regenerate the file.
#
# The dstFileName file will not be overwritten unless the encoded
# string or variable name differs, in order to avoid recompiling
# dependent files unneccessarily.
# Given a string representing an XML file, extract all of the include items and
# replace them with the contents of the file being included.
function(expandXMLString rawString expandedString includedFiles)
# First, grab all of the xml elements describing included files
string(REGEX MATCHALL "<include[^/]* href=\"[^\"]+\"[^/]*/>" includes ${${rawString}})
# For each xml element...
foreach (include IN LISTS includes)
# ...extract the attribute with the include file name...
string(REGEX MATCH "href=\"[^\"]+\"" tmp ${include})
# ...and extract the substring that contains the bare file name.
string(LENGTH ${tmp} len)
math(EXPR newlen "${len} - 7")
string(SUBSTRING ${tmp} 6 ${newlen} incFileName)
string(CONCAT incFileName ${PROJECT_SOURCE_DIR} "/" ${incFileName})
list(FIND includedFiles ${incFileName} index)
if (NOT ${index} EQUAL -1)
message(WARNING "File \"${incFileName}\" has cyclic dependencies.")
continue()
endif ()
# If we cannot locate the include file, leave the include directive in the
# xml description.
if (NOT EXISTS ${incFileName})
message(WARNING "Cannot locate file \"${incFileName}\".")
continue()
endif()
# Read the dependency file
file(READ ${incFileName} incFileContents)
# Add the file name to the list of included files
list(APPEND includedFiles ${incFileName})
# Recursively expand the dependency xml string
expandXMLString(incFileContents expandedIncFileContents includedFiles)
# Pop the file name
list(REMOVE_ITEM includedFiles ${incFileName})
# Replace the include element with the contents of the included file.
string(REPLACE ${include} ${expandedIncFileContents} ${rawString} "${${rawString}}")
endforeach()
set(${expandedString} "${${rawString}}" PARENT_SCOPE)
endfunction()
function(encodeStringAsCVariable rawString encodedVarName stringOut)
string(REPLACE "\\" "\\\\" str1 "${${rawString}}")
set(includedFiles)
expandXMLString(${rawString} expandedString includedFiles)
string(REPLACE "\\" "\\\\" str1 "${expandedString}")
string(REPLACE "\"" "\\\"" str2 "${str1}")
string(REPLACE "\n" "\\n" str3 "${str2}")
string(CONFIGURE
......@@ -16,7 +73,6 @@ function(configureStringAsCVariable rawString dstFileName encodedVarName)
if (EXISTS ${dstFileName})
file(READ ${dstFileName} already)
endif()
#message("Writing ${dstFileName}")
if (NOT "${encodedContents}" STREQUAL "${already}")
file(WRITE ${dstFileName} "${encodedContents}")
endif()
......@@ -49,3 +105,53 @@ endfunction()
# The dstFileName file will not be overwritten unless the encoded
# string or variable name differs, in order to avoid recompiling
# dependent files unneccessarily.
function(encodeStringAsPyVariable rawString encodedVarName stringOut)
set(includedFiles)
expandXMLString(${rawString} expandedString includedFiles)
string(CONFIGURE "\ndescription = '''\n${expandedString}\n'''\n" pyString)
set(${stringOut} "${pyString}" PARENT_SCOPE)
endfunction()
function(configureStringAsPyVariable rawString dstFileName encodedVarName)
encodeStringAsPyVariable(${rawString} ${encodedVarName} encodedContents)
if (EXISTS ${dstFileName})
file(READ ${dstFileName} already)
endif()
if (NOT "${encodedContents}" STREQUAL "${already}")
file(WRITE ${dstFileName} "${encodedContents}")
endif()
endfunction()
function(configureFileAsPyVariable srcFileName dstFileName encodedVarName)
if (EXISTS ${srcFileName})
file(READ ${srcFileName} fileContents)
configureStringAsPyVariable(fileContents ${dstFileName} ${encodedVarName})
else()
file(REMOVE ${dstFileName})
endif()
endfunction()
# Example:
# configureFileAsPyVariable("foo.xml" "bar.py" "operatorSpec")
# would read "foo.xml" and write the assigment:
# operatorSpec = '''
# ...
# '''
# into bar.py (where "..." is the encoded contents of "foo.xml").
#
# When srcFileName does not exist, then dstFileName will be
# removed so that missing files are more easily spotted.
# Note that since this configuration is done when CMake runs
# you must re-run CMake in order to regenerate the file.
#
# The dstFileName file will not be overwritten unless the encoded
# string or variable name differs, in order to avoid recompiling
# dependent files unneccessarily.
......@@ -22,10 +22,6 @@
// and vtkSMTKDiscreteModel library will exist.
#cmakedefine SMTK_ENABLE_DISCRETE_SESSION
// Was SMTK built with exodus-II reader? If true,
// the SMTKExodusSession library will exist.
#cmakedefine SMTK_ENABLE_EXODUS_SESSION
// Was SMTK built with mesh session? If true,
// the SMTKMeshSession library will exist.
#cmakedefine SMTK_ENABLE_MESH_SESSION
......
include("${CMAKE_CURRENT_LIST_DIR}/EncodeStringFunctions.cmake")
# Given a list of filenames (opSpecs) containing XML descriptions of
# operators, configure C++ source that encodes the XML as a string.
# The resulting files are placed in the current binary directory and
# appended to genFiles.
include("${CMAKE_CURRENT_LIST_DIR}/EncodeCStringFunctions.cmake")
function(smtk_operator_xml opSpecs genFiles)
foreach (opSpec ${opSpecs})
get_filename_component(genFileBase "${opSpec}" NAME_WE)
......@@ -17,7 +18,6 @@ endfunction()
# operators, configure Python source that encodes the XML as a string.
# The resulting files are placed in the current binary directory and
# appended to genFiles.
include("${CMAKE_CURRENT_LIST_DIR}/EncodePyStringFunctions.cmake")
function(smtk_pyoperator_xml opSpecs genFiles)
foreach (opSpec ${opSpecs})
get_filename_component(genFileBase "${opSpec}" NAME_WE)
......
include("${CMAKE_CURRENT_LIST_DIR}/EncodeStringFunctions.cmake")
# Given a list of filenames (opSpecs) containing JSON descriptions of
# a session, configure C++ source that encodes the JSON as a string.
# The resulting files are placed in the current binary directory and
# appended to genFiles.
include("${CMAKE_CURRENT_LIST_DIR}/EncodeCStringFunctions.cmake")
function(smtk_session_json opSpecs genFiles)
foreach (opSpec ${opSpecs})
get_filename_component(genFileBase "${opSpec}" NAME_WE)
......
......@@ -11,6 +11,9 @@ endif()
if (POLICY CMP0046)
cmake_policy(SET CMP0046 NEW)
endif()
if (POLICY CMP0071)
cmake_policy(SET CMP0071 NEW)
endif()
#If the user/superbuild hasn't explicitly stated what c++ standard to use
#require C++11
......@@ -114,10 +117,6 @@ cmake_dependent_option(SMTK_ENABLE_MOAB_DISCRETE_READER "Build moab reader for d
"SMTK_ENABLE_DISCRETE_SESSION" OFF)
cmake_dependent_option(SMTK_ENABLE_POLYGON_SESSION "Build Boost.polygon model session." ON
SMTK_ENABLE_VTK_SUPPORT OFF)
cmake_dependent_option(SMTK_ENABLE_EXODUS_SESSION "Build a session to Exodus-II side sets" ON
SMTK_ENABLE_VTK_SUPPORT OFF)
cmake_dependent_option(SMTK_ENABLE_REMOTE_SESSION "Build a session that allows modeling in a remote process" ON
SMTK_ENABLE_REMUS_SUPPORT OFF)
option(SMTK_ENABLE_MESH_SESSION
"Build a session that uses smtk::mesh as its backing" ON)
cmake_dependent_option(SMTK_ENABLE_MULTISCALE_SESSION "Build a session to Multiscale data" OFF
......@@ -590,8 +589,7 @@ install (FILES ${PROJECT_BINARY_DIR}/smtk/Options.h
# Install rules for SMTK macros usable by external packages:
install(
FILES
${PROJECT_SOURCE_DIR}/CMake/EncodeCStringFunctions.cmake
${PROJECT_SOURCE_DIR}/CMake/EncodePyStringFunctions.cmake
${PROJECT_SOURCE_DIR}/CMake/EncodeStringFunctions.cmake
${PROJECT_SOURCE_DIR}/CMake/SMTKOperatorXML.cmake
${PROJECT_SOURCE_DIR}/CMake/SMTKSessionJSON.cmake
DESTINATION
......
This source diff could not be displayed because it is stored in LFS. You can view the blob instead.
......@@ -167,6 +167,13 @@ if (SMTK_ENABLE_PYTHON_WRAPPING)
set(VTK_INSTALL_PYTHON_MODULES_DIR ${SMTK_PYTHON_MODULEDIR})
endif()
################################################################################
# Build smtk environment
# Construct an interface for applications that require a singleton
# representation of SMTK that uses auto-registration.
################################################################################
add_subdirectory(environment)
################################################################################
# Build smtk extensions
# Add libraries that extend other projects to have support for SMTK.
......
......@@ -49,6 +49,8 @@ class ComponentItem;
class ComponentItemDefinition;
class RefItem;
class RefItemDefinition;
class ResourceItem;
class ResourceItemDefinition;
class DateTimeItem;
class DateTimeItemDefinition;
class Definition;
......@@ -176,7 +178,6 @@ class ShellEntity;
typedef std::vector<smtk::model::ShellEntity> ShellEntities;
class Manager;
class SimpleModelSubphrases;
class StoredResource;
class SubphraseGenerator;
class Tessellation;
class UseEntity;
......@@ -316,8 +317,6 @@ typedef smtk::shared_ptr<smtk::model::RemoteOperator> RemoteOperatorPtr;
typedef std::function<smtk::model::OperatorPtr()> OperatorConstructor;
typedef std::pair<std::string, OperatorConstructor> StaticOperatorInfo;
typedef std::map<std::string, StaticOperatorInfo> OperatorConstructors;
typedef smtk::shared_ptr<smtk::model::StoredResource> StoredResourcePtr;
typedef smtk::shared_ptr<const smtk::model::StoredResource> ConstStoredResourcePtr;
typedef smtk::shared_ptr<smtk::model::Entity> EntityPtr;
typedef smtk::weak_ptr<smtk::model::Entity> WeakEntityPtr;
typedef std::vector<smtk::model::EntityPtr> EntityArray;
......@@ -387,6 +386,8 @@ typedef smtk::shared_ptr<const smtk::attribute::ModelEntityItemDefinition>
typedef smtk::shared_ptr<smtk::attribute::ModelEntityItemDefinition> ModelEntityItemDefinitionPtr;
typedef smtk::shared_ptr<smtk::attribute::VoidItem> VoidItemPtr;
typedef smtk::shared_ptr<smtk::attribute::VoidItemDefinition> VoidItemDefinitionPtr;
typedef smtk::shared_ptr<smtk::attribute::ResourceItem> ResourceItemPtr;
typedef smtk::shared_ptr<smtk::attribute::ResourceItemDefinition> ResourceItemDefinitionPtr;
typedef smtk::shared_ptr<smtk::attribute::ComponentItem> ComponentItemPtr;
typedef smtk::shared_ptr<smtk::attribute::ComponentItemDefinition> ComponentItemDefinitionPtr;
......@@ -417,6 +418,9 @@ typedef smtk::shared_ptr<const smtk::attribute::MeshSelectionItemDefinition>
typedef smtk::shared_ptr<const smtk::attribute::ModelEntityItem> ConstModelEntityItemPtr;
typedef smtk::shared_ptr<const smtk::attribute::ModelEntityItemDefinition>
ConstModelEntityItemDefinitionPtr;
typedef smtk::shared_ptr<const smtk::attribute::ResourceItem> ConstResourceItemPtr;
typedef smtk::shared_ptr<const smtk::attribute::ResourceItemDefinition>
ConstResourceItemDefinitionPtr;
typedef smtk::shared_ptr<const smtk::attribute::ComponentItem> ConstComponentItemPtr;
typedef smtk::shared_ptr<const smtk::attribute::ComponentItemDefinition>
ConstComponentItemDefinitionPtr;
......
......@@ -23,6 +23,7 @@
#include "smtk/attribute/ModelEntityItem.h"
#include "smtk/attribute/ModelEntityItemDefinition.h"
#include "smtk/attribute/RefItem.h"
#include "smtk/attribute/ResourceItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/attribute/ValueItem.h"
#include "smtk/attribute/VoidItem.h"
......@@ -666,6 +667,15 @@ smtk::attribute::ConstDateTimeItemPtr Attribute::findDateTime(const std::string&
return smtk::dynamic_pointer_cast<const DateTimeItem>(this->find(nameStr));
}
smtk::attribute::ResourceItemPtr Attribute::findResource(const std::string& nameStr)
{
return smtk::dynamic_pointer_cast<ResourceItem>(this->find(nameStr));
}
smtk::attribute::ConstResourceItemPtr Attribute::findResource(const std::string& nameStr) const
{
return smtk::dynamic_pointer_cast<const ResourceItem>(this->find(nameStr));
}
smtk::attribute::ComponentItemPtr Attribute::findComponent(const std::string& nameStr)
{
return smtk::dynamic_pointer_cast<ComponentItem>(this->find(nameStr));
......
......@@ -123,7 +123,7 @@ public:
* @param values a container which holds items
* @param test a lambda function which would be applied on children items
* Example filter double and int items
* [](Item::Ptr item) { return item->type() == DOUBLE || item->type() == INT; }
* [](Item::Ptr item) { return item->type() == DoubleType || item->type() == IntType; }
* Example filter modelEntity items
* [](ModelEntity::Ptr item) { return true; }
* @param activeChildren a flag indicates whether it should be applied to active children only or not
......@@ -164,6 +164,9 @@ public:
DateTimeItemPtr findDateTime(const std::string& name);
ConstDateTimeItemPtr findDateTime(const std::string& name) const;
ResourceItemPtr findResource(const std::string& name);
ConstResourceItemPtr findResource(const std::string& name) const;
ComponentItemPtr findComponent(const std::string& name);
ConstComponentItemPtr findComponent(const std::string& name) const;
......
......@@ -101,6 +101,10 @@ set(attributeHeaders
ModelEntityItemDefinition.h
RefItem.h
RefItemDefinition.h
RegisterOperations.h
RegisterResources.h
ResourceItem.h
ResourceItemDefinition.h
SearchStyle.h
StringItem.h
StringItemDefinition.h
......@@ -144,6 +148,10 @@ set(attributeSrcs
ModelEntityItemDefinition.cxx
RefItem.cxx
RefItemDefinition.cxx
RegisterOperations.cxx
RegisterResources.cxx
ResourceItem.cxx
ResourceItemDefinition.cxx
StringItem.cxx
StringItemDefinition.cxx
ValueItem.cxx
......@@ -155,6 +163,8 @@ set(attributeSrcs
#install the headers
smtk_public_headers(${attributeHeaders})
add_subdirectory(environment)
if (SMTK_ENABLE_PYTHON_WRAPPING)
add_subdirectory(pybind11)
endif()
......
......@@ -27,27 +27,20 @@
#include "smtk/common/UUID.h"
#include <iostream>
#include <numeric>
#include <queue>
#include <sstream>
using namespace smtk::attribute;
static void registerAttributeResource()
{
smtk::attribute::Collection::Metadata metadata("attribute");
smtk::resource::Manager::registerResource<smtk::attribute::Collection>(metadata);
}
Collection::Collection(const smtk::common::UUID& myID, smtk::resource::ManagerPtr manager)
: Resource(myID, manager)
{
registerAttributeResource();
}
Collection::Collection(smtk::resource::ManagerPtr manager)
: Resource(manager)
{
registerAttributeResource();
}
Collection::~Collection()
......@@ -870,3 +863,21 @@ smtk::resource::ComponentPtr Collection::find(const smtk::common::UUID& attId) c
{
return this->findAttribute(attId);
}
std::function<bool(const smtk::resource::ComponentPtr&)> Collection::queryOperation(
const std::string&) const
{
// TODO: fill me in!
return [](const smtk::resource::ComponentPtr&) { return true; };
}
// visit all components in the resource.
void Collection::visit(smtk::resource::Component::Visitor& visitor) const
{
auto convertedVisitor = [&](const std::pair<std::string, const AttributePtr>& attributePair) {
const smtk::resource::ComponentPtr resource =
std::static_pointer_cast<smtk::resource::Component>(attributePair.second);
visitor(resource);
};
std::for_each(m_attributes.begin(), m_attributes.end(), convertedVisitor);
}
......@@ -16,6 +16,7 @@
#include "smtk/common/UUID.h"
#include "smtk/resource/Component.h"
#include "smtk/resource/Resource.h" // base class
#include "smtk/CoreExports.h"
......@@ -42,6 +43,10 @@ public:
smtkTypeMacro(smtk::attribute::Collection);
smtkCreateMacro(smtk::attribute::Collection);
smtkSharedFromThisMacro(smtk::resource::Resource);
smtkResourceTypeNameMacro("attribute");
// typedef referring to the parent resource.