You can still define resolveVar() and resolveFunc() methods in your custom expression classes, but you now also have the option to use variable blocks instead. These are useful for re-using variables and managing thread evaluation. Within your custom expression class, you would skip the usual resolveVar() and resolveFunc() implementations:
class MyExpr:public KSeExpr::Expression {
// These are now optional:
// resolveVar()
// resolveFunc()
};
Here's how you might write an example function to run an expression that uses variable blocks. This example assumes you have a particle data struct p, with numParticles, numAttributes. A variable block contains variable names and types, but doesn't care what the values are.
void f(const std::string& s, MyParticleData* p, int outputDim=3){
// set up the bindings for each of the particle attributes
KSeExpr::VarBlockCreator blockCreator;
std::vector variableHandles;
std::vector attrs;
for(int i=0; inumAttrs(); i++) {
MyParticleAttr attr;
p->getAttrInfo(i,attr);
attrs.push_back(attr);
int handle = blockCreator.registerVariable(attr.name,
TypeVec(attr.dim));
variableHandles.push_back(handle);
}
// set up binding for the output
int outputVariableHandle=blockCreator.registerVariable("__output",
TypeVec(outputDim));
// make an expression with the appropriate bindings
MyExpr e(s);
e.setDesiredType(TypeVec(outputDim));
e.setVarBlockCreator(&blockCreator);
if(!e.isValid()) throw std::runtime_error(e.parseError()):
// create the variable block, set up pointers to data
KSeExpr::VarBlock block = blockCreator.create();
for(int i=0; inumAttrs(); i++) {
block.Pointer(variableHandles[i]) = p->data(attrs[i]);
}
std::vector outputData(p->numParticles()*outputDim);
block.Pointer(outputVariableHandle)=outputData.data();
// evaluate multiple expressions at once; inlines expressions
e.evalMultiple(&block, outputVariableHandle, 0, p->numParticles());
}
To parallelize evaluation per particle, a simple parallel_for can be used:
// evaluate multiple expressions at once, inlines expressions
tbb::parallel_for(blocked_range(0,p->numParticles()),[](blocked_range r)) {
VarBlock myBlock=block.clone(); //should be cheap
e.evalMultiple(&myblock, outputVariableHandle, r.start, r.end);
}