Curve Sets

Sina CurveSet objects act as a way to group related independent and dependent Curve objects. Each Curve is a 1-dimensional list of numbers along with optional units and tags.

A common example of a CurveSet could be time series data. Here the independent curve would be time and the dependent curve(s) would be the data you’re measuring over time.

We will demonstrate the creation of a CurveSet using a simple experiment that measures the 2D position and velocity of a ball while it bounces. In the below script We will create one function to generate the data for the ball bounce experiment and another function to assemble the CurveSet object and add it to our Record:

// Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and
// other Axom Project Developers. See the top-level LICENSE file for details.
//
// SPDX-License-Identifier: (BSD-3-Clause)

#include "axom/sina.hpp"

#include <iostream>
#include <cmath>
#include <vector>

struct BounceData
{
  std::vector<double> time;
  std::vector<double> xPosition;
  std::vector<double> yPosition;
  std::vector<double> xVelocity;
  std::vector<double> yVelocity;
};

BounceData generateBounceData(double initialY,
                              double initialXVelocity,
                              double coefficientOfRestitution,
                              double timeStep,
                              double simulationTime,
                              double airResistanceCoefficient)
{
  BounceData data;
  double time = 0.0;
  double yPosition = initialY;
  double xPosition = 0.0;
  double xVelocity = initialXVelocity;
  double yVelocity = 0.0;

  while(time < simulationTime)
  {
    // Update position and velocity based on time step
    xPosition += xVelocity * timeStep;
    yVelocity += -9.81 * timeStep;  // Acceleration due to gravity

    // Apply air resistance on x-velocity
    xVelocity -= airResistanceCoefficient * xVelocity * timeStep;

    // Update height (y position)
    yPosition += yVelocity * timeStep;

    // Check for bounce (when y position becomes negative)
    if(yPosition < 0)
    {
      yPosition = 0;                           // Set y position to 0 at the ground
      yVelocity *= -coefficientOfRestitution;  // Reverse y velocity with energy loss
    }

    // Add data points for this time step
    data.time.push_back(time);
    data.xPosition.push_back(xPosition);
    data.yPosition.push_back(yPosition);
    data.xVelocity.push_back(xVelocity);
    data.yVelocity.push_back(yVelocity);

    time += timeStep;
  }

  return data;
}

void addCurveSet(axom::sina::Record &record, BounceData bounceData, std::string curveName)
{
  // Create the curve set object
  axom::sina::CurveSet bounceCurveSet {curveName};

  // Add the independent variable
  axom::sina::Curve timeCurve {"time", bounceData.time};
  timeCurve.setUnits("seconds");
  bounceCurveSet.addIndependentCurve(timeCurve);

  // Add the dependent variables
  bounceCurveSet.addDependentCurve(axom::sina::Curve {"x_position", bounceData.xPosition});
  bounceCurveSet.addDependentCurve(axom::sina::Curve {"y_position", bounceData.yPosition});
  axom::sina::Curve xVelCurve {"x_velocity", bounceData.xVelocity};
  xVelCurve.setUnits("m/s");
  bounceCurveSet.addDependentCurve(xVelCurve);
  axom::sina::Curve yVelCurve {"y_velocity", bounceData.yVelocity};
  yVelCurve.setUnits("m/s");
  bounceCurveSet.addDependentCurve(yVelCurve);

  // Add the curve set to the record
  record.add(bounceCurveSet);
}

int main()
{
  double initialY = 10.0;
  double initialXVelocity = 2.0;
  double coefficientOfRestitution = 0.7;
  double timeStep = 0.2;
  double simulationTime = 5.0;
  double airResistanceCoefficient = 0.01;

  BounceData bounceData = generateBounceData(initialY,
                                             initialXVelocity,
                                             coefficientOfRestitution,
                                             timeStep,
                                             simulationTime,
                                             airResistanceCoefficient);

  axom::sina::Document doc;

  axom::sina::ID id {"ball_bounce_run", axom::sina::IDType::Global};
  std::unique_ptr<axom::sina::Record> study {new axom::sina::Record {id, "ball bounce study"}};

  addCurveSet(*study, bounceData, "ball_bounce");
  doc.add(std::move(study));
  axom::sina::saveDocument(doc, "ball_bounce.json");

  return 0;
}

Once this code is compiled and executed a json file will be created. Here, we’ll use PyDV to ingest the Sina json file in order to view the position and velocity of the ball along the y-axis over time.

The position and velocity of the ball over time along the y-axis