Data Model

FleCSI provides a data model that integrates with the task and kernel abstractions to provide easy registration and access to various data types with automatic dependency tracking.

Example 1: Global data

Global fields are used to store global variables/objects that can be accessed by any task. Since there is only one value for each field, it is natural to use the data::single layout.

template<typename T>
using single = field<T, data::single>;
const single<double>::definition<global> lue;

Writing to a global field requires a single task launch.

void
init(double v, single<double>::accessor<wo> gv) {
  gv = v;
}

void
print(single<double>::accessor<ro> gv) {
  flog(trace) << "global value: " << gv << std::endl;
}

int
advance() {

  const auto v = lue(global_topology);
  execute<init>(42.0, v);
  execute<print>(v);

  return 0;
}

Example 2: Index data

Index field is a field that is local to a color or process (MPI rank or Legion shard). It is defined as a filed on an index topology.

using namespace flecsi;

template<typename T>
using single = field<T, data::single>;
const single<std::size_t>::definition<topo::index> lue;

inline topo::index::slot custom_topology;

void
init(single<std::size_t>::accessor<wo> iv) {
  flog(trace) << "initializing value on color " << color() << " of " << colors()
              << std::endl;
  iv = color();
}

void
print(single<std::size_t>::accessor<ro> iv) {
  flog(trace) << "index value: " << iv << " (color " << color() << " of "
              << colors() << ")" << std::endl;
}

int
advance() {

  custom_topology.allocate(4);

  execute<init>(lue(process_topology));
  execute<print>(lue(process_topology));

  execute<init>(lue(custom_topology));
  execute<print>(lue(custom_topology));

  return 0;
}

Example 3: Dense data

Dense field is a field defined on a dense topology index space. In this example we allocate pressure field on the cells index space of canonical topology.

const field<double>::definition<canon, canon::cells> pressure;

One can access the field inside of the FLeCSI task through passing topology and field accessors with access permissions (wo/rw/ro).

void
init(canon::accessor<wo> t, field<double>::accessor<wo> p) {
  std::size_t off{0};
  for(const auto c : t.entities<canon::cells>()) {
    p[c] = (off++) * 2.0;
  } // for
} // init

void
print(canon::accessor<ro> t, field<double>::accessor<ro> p) {
  std::size_t off{0};
  for(auto c : t.entities<canon::cells>()) {
    flog(info) << "cell " << off++ << " has pressure " << p[c] << std::endl;
  } // for
} // print

int
advance() {
  coloring.allocate("test.txt");
  canonical.allocate(coloring.get());

  auto pf = pressure(canonical);

  execute<init>(canonical, pf);
  execute<print>(canonical, pf);

  return 0;
}