SCI Home Software Documentation Installation User's Guide Developer's Guide

CIBC:Development:Virtual:CreateFields

From SCIRun Documentation Wiki

Jump to: navigation, search

Contents

Virtual Fields

Goals

The goal is to have virtual field calls replace dynamic compilation, so we can ship binaries and do not depend on compilers. Secondly this should reduce the instability associated with dynamic compilation as all functions are precompiled.


This documentation, documents the code currently on the virtual branch

Overview

How to create functions that do not need dynamic compilation:


Obtaining the field/mesh type information without dynamic compilation

All classes like typename(), get_type_description(), and query_scalar_interface()/query_vector_interface()/query_tensor_interface() in the old SCIRun version serve to extract the type of mesh and field one is dealing with. In the virtual branch there is one wrapper class that hides all these different function calls into one class, that also does not need any dynamic compilation.

Requestinng the type of the field or a mesh class should be done through the FieldInformation class

The FieldInformation class can be instantiated from any FieldHandle

#include <Core/Datatypes/FieldInformation.h>
FieldInformation fi(my_field_handle);

The FieldInformation class can be used to query all kinds of data e.g.:

if (fi.is_scalar())
{
  ...
}
else if (fi.is_vector())
{
  ...
}
else if (fi.is_tensor())
{
  ...
}
 

The second use of the FieldInformation class is to create new fields. Before we can derive a new field one has to specify which type of field one wants.

The most common case is the case in which an input field needs to be changed to generate a new type or mesh type. The FieldInformation class has two ways of modifying information:

FieldInformation fi(my_field_handle);
fi.make_linear();

This will generate a field that has all the same properties as the input field, but the data will be linear. Secondly one can set properties directly:

FieldInformation fi(my_field_handle);
fi.set_data_type("Vector"); 


FieldInformation not only has a database of all the properties of the field or mesh, it knowns about include files for dynamic compilation as well and hence can be used to generate the CompileInfo for the dynamic compilation code as well:

FieldInformation fi(my_field_handle);
fi.set_data_type("Vector");
CompileInfoHandle ci = scinew CompileInfo("MyAlgorithm"+fi.get_field_filename()+".",
          "MyAlgo","MyAlgoT",fi.get_field_name());
fi.fill_compile_info(ci); 

Besides generating information for dynamic compilation, it also supports to build mesh and field classes using virtual function calls.

For instance a new field can be generate like this:

FieldInformation fi(my_field_handle);
fi.make_linear();
FieldHandle my_new_field = CreateField(fi);

Creating a field/mesh without dynamic compilation:

There are couple of scenarios:

The field that needs to be created is of the same type as the input field

Using CreateField: To create a field of the same type, with a new mesh class associate with it as well:

FieldInformation fi(my_field_handle);
FieldHandle my_new_field = CreateField(fi);
 

To create a field of the same type, but sharing a mesh with the input field

FieldInformation fi(my_field_handle);
FieldHandle my_new_field = CreateField(fi,my_field_handle->mesh());

In case the creation of the mesh requires additional inputs, e.g. a LatVolMesh or ImageMesh:

FieldInformation fi(my_field_handle);
MeshHandle my_new_mesh = CreateMesh(fi,3,3,3,Point(0,0,0),Point(1,1,1));  // Assuming fi denotes a LatVolMesh 
FieldHandle my_new_field = CreateField(fi,my_new_mesh);


The field is a variation on the input field

To create a field of the same type but with Vector data, with a new mesh class associate with it as well:

FieldInformation fi(my_field_handle);
fi.set_datatype("Vector");
FieldHandle my_new_field = CreateField(fi);
 

To create a field of the same type but with Vector data and sharing a mesh with the input field

FieldInformation fi(my_field_handle);
fi.set_datatype("Vector");
FieldHandle my_new_field = CreateField(fi,my_field_handle->mesh());

In case the creation of the mesh requires additional inputs, e.g. a LatVolMesh or ImageMesh:

FieldInformation fi(my_field_handle);
fi.set_datatype("Vector");
MeshHandle my_new_mesh = CreateMesh(fi,3,3,3,Point(0,0,0),Point(1,1,1));  // Assuming fi denotes a LatVolMesh 
FieldHandle my_new_field = CreateField(fi,my_new_mesh);

Building field from scratch

In this case one should fill out the FieldInformation class and then call CreateField

FieldInformation fi("TetVolMesh","Linear","double");
FieldHandle my_new_field = CreateField(fi);

Similarly if one only wants a mesh:

FieldInformation fi("TetVolMesh","Linear","double");
MeshHandle my_new_field = CreateMesh(fi);

Building a virtual algorithm

An algorithm is normally a combination of the following:

  1. Check inputs and input types
  2. Derive the type of the output
  3. Create new fields
  4. Do algorithm on input and output field

To obtain an interface to do an operation between fields one needs to get the virtual interfaces to those fields:

template<DATATYPE>
bool MyAlgoV(FieldHandle input, FieldHandle& output)
{
  VField* ifield = input->vfield();
  VMesh*  imesh  = input->vmesh();

  VField* ofield = output->vfield();
  VMesh*  omesh  = output->vmesh();

This requests the virtual interfaces. A virtual interface can be a pointer to input field it self, in which case the input field actually contains all virtual functions or it can be pointer to a class that wraps around an existing field and it is a separate class that internally contains a handle to the field. The vfield() and vmesh() functions return return a handle to the object, a copy of this handle is maintained internally as well. Hence pointer are sufficient here. The functions return handles to in line with the other functions of Field.

Once the pointers to the virtual interfaces are secured one can do an algorithm:

  VMesh::Node::iterator it, it_end;
  imesh->begin(it);
  imesh->end(it_end);

  omesh->resize_fdata();
  DATATYPE val;
  while(it != it_end);
  {
    ifield->get_value(val,*it);
    ofield->set_value(2*val,*it);
    ++it;
  }
  return (true);
}
 

Note that the function is still templated against DATATYPE. Virtualizing the datatype calls would slow down computation drastically, as every call to a computational function would have to be a virtual function. The paradigm here is that we choose a datatype to work with, e.g. double, or Vector, or Tensor and then run the complete algorithm in that type. The functions get_value() and set_value() have internal casting, hence if the original type of the field is 'char' and the output type is 'double', we run the algorithm in double, as soon as get_value() is called on the input field the data is casted to the requested format. Casts to all available field formats have been implemented in the virtual function get_value and set_value. Functions such as interpolate and gradient are also implemented for each datatype.

To complete the algorithm as none dynamic function call one should add this to the core of the algorithm:

bool MyAlgo(FieldHandle input, FieldHandle& output)
{
  FieldInformation fi(input);

  if (fi.is_nonlinear())
  {
    error("This algorithm does not support higher order fields and meshes");
    return (false);
  }

  output = CreateField(fi);

  if (fi.is_vector()) return(MyAlgoV<Vector>(input,output));  
  if (fi.is_tensor()) return(MyAlgoV<Tensor>(input,output));
  if (fi.is_scalar()) return(MyAlgoV<double>(input,output));

  return (false);
}


Depending on the required efficiency of the algorithm one can add additional specializations:

 ...
 if (fi.is_float()) return(MyAlgoV<float>(input,output));
 if (fi.is_vector()) return(MyAlgoV<Vector>(input,output));  
 if (fi.is_tensor()) return(MyAlgoV<Tensor>(input,output));
 if (fi.is_scalar()) return(MyAlgoV<double>(input,output));
 ...

The more specifications one has the more extensive the code will be, hence only where efficiency is key, one should add more specifications.

Personal tools