Getting Started with easi

easi is a header-only library written in C++11. Hence, one simply needs (Only unit tests must be compiled with CMake.)

Dependencies

Easi depends on the following two projects:

Make sure to link against these libraries when using easi.

Usage example

easi is configured via YAML configuration files. For example, such a configuration file could look like the following:

!Any
components:
  - !AxisAlignedCuboidalDomainFilter
    limits:
      x: [-100000, 100000]
      y: [-5000, 5000]
      z: [-100000, 10000]
    components:
      - !ConstantMap
        map:
          lambda: 1e10
          mu: 2e10
          rho: 5000
  - !LayeredModel
    map: !AffineMap
      matrix:
        z: [0, 0, 1]
      translation:
        z: 0
    interpolation: linear
    parameters: [rho, mu, lambda]
    nodes:
      -100.0:   [2300.0, 0.1766e10, 0.4999e10]
      -300.0:   [2300.0, 0.6936e10, 1.3872e10]
      -1000.0:  [2600.0, 1.3717e10, 1.8962e10]
      -3000.0:  [2700.0, 2.1168e10, 2.7891e10]
      -6000.0:  [2870.0, 3.1041e10, 3.8591e10]
      -31000.0: [3500.0, 3.9847e10, 4.3525e10]
      -50000.0: [3200.0, 6.4800e10, 6.5088e10]

Here, all points with y-coordinate inbetween -5 km and +5 km would be assigned constant model parameters. For all other points, a linear interpolation, depending on the z-coordinate is used.

Application example

The first step is always to create a model. Here, we may use the YAMLParser class which creates models from YAML configuration files.

1
2
easi::YAMLParser parser(3);
easi::Component* model = parser.parse("test.yaml");

The argument in YAMLParser’s constructor is the dimension of the input vectors. Here, we take 3 as we want to query our model in a 3-dimensional space.

As a next step, we need to define a query, which defines the input vectors for which we want to evaluate our model. In the following example we add the points (1,2,3) and (2,3,4). Each point may have an additional group parameter, which may be used to distinguish points in an easi file.

easi::Query query(2,3);
query.x(0,0) = 1.0;
query.x(0,1) = 2.0;
query.x(0,2) = 3.0;
query.group(0) = 1;
query.x(1,0) = 2.0;
query.x(1,1) = 3.0;
query.x(1,2) = -4.0;
query.group(1) = 1;

We need to store the output vectors somewhere. For this purpose, we always need to supply an adapter, which connects the output vector with locations in memory. In our sample application, the output vector shall be stored as array of structs, and hence we use an ArrayOfStructsAdapter. (Note that additional adapters can be implemented by overriding the class ResultAdapter.)

struct ElasticMaterial {
  double lambda, mu, rho;
};

ElasticMaterial material[2];
easi::ArrayOfStructsAdapter<ElasticMaterial> adapter(material);
adapter.addBindingPoint("lambda", &ElasticMaterial::lambda);
adapter.addBindingPoint("mu",     &ElasticMaterial::mu);
adapter.addBindingPoint("rho",    &ElasticMaterial::rho);

Finally, a simple call to evaluate is sufficient, and the model should be deleted if is not required anymore.

model->evaluate(query, adapter);
delete model;

The whole sample code is listed in the following:

#include <iostream>
#include "easi/YAMLParser.h"
#include "easi/ResultAdapter.h"

struct ElasticMaterial {
  double lambda, mu, rho;
};

int main(int argc, char** argv)
{
  easi::Query query(2,3);
  query.x(0,0) = 1.0;
  query.x(0,1) = 2.0;
  query.x(0,2) = 3.0;
  query.group(0) = 1;
  query.x(1,0) = 2.0;
  query.x(1,1) = 3.0;
  query.x(1,2) = -4.0;
  query.group(1) = 1;

  easi::YAMLParser parser(3);
  easi::Component* model = parser.parse("test.yaml");

  ElasticMaterial material[2];
  easi::ArrayOfStructsAdapter<ElasticMaterial> adapter(material);
  adapter.addBindingPoint("lambda", &ElasticMaterial::lambda);
  adapter.addBindingPoint("mu",     &ElasticMaterial::mu);
  adapter.addBindingPoint("rho",    &ElasticMaterial::rho);

  model->evaluate(query, adapter);

  delete model;

  for (unsigned j = 0; j < 2; ++j) {
    std::cout << material[j].lambda << " " << material[j].mu << " " << material[j].rho << std::endl;
  }

  return 0;
}