Reading JSON in C++

In my previous post on reading XML input files, I discussed how input files can be made more human friendly with XML markup. In some situations, it may be preferable to have JSON format files instead.

JSON is particularly useful when the Javascript is used during reading and writing. Though Javascript is not the ideal platform for computational engineering, it has some potential is used for user interface development.

Note: It remains to be seen how useful Javascript user interfaces are when used for engineering applications, though cross-platform tools such as Electron has potential. User interfaces designed with wxWidgets or Qt still dominate the landscape for engineering software.

The JSON input file

In JSON format, our Boundary input file can be expressed as:

  {"Boundary": {
    "containerMin":  "[0.0,  -1.0,  0.0]",
    "containerMax":  "[100.0, 1.0, 50.0]",
    "boundary": [
      {
       "type": "plane", "id": 1,
       "direction": "[-1.0, 0.0, 0.0]",
       "position": "[100.0, 0.0, 25.0]",
      },
      {
       "type": "plane", "id": 2,
       "direction": "[1.0, 0.0, 0.0]",
       "position": "[100.0, 0.0, 25.0]"
      }
    ]
  }}

Recall that the equivalent XML input file has the form

  <?xml version='1.0' encoding='ISO-8859-1' ?>
  <Boundary>
    <!-- Container limits -->
    <containerMin>  [0.0,  -1.0,  0.0] </containerMin>
    <containerMax>  [100.0, 1.0, 50.0] </containerMax>
    <!-- Internal boundaries -->
    <boundary type="plane" id="1">
      <direction> [-1.0, 0.0, 0.0] </direction>
      <position> [100.0, 0.0, 25.0] </position>
    </boundary>
    <boundary type="plane" id="2">
      <direction> [1.0, 0.0, 0.0] </direction>
      <position> [100.0, 0.0, 25.0] </position>
    </boundary>
  </Boundary>

I prefer the XML version, but most new students will be familiar with JSON and may prefer that format, particularly as that format appears to be preferred in IoT applications.

Reading JSON

A large list of JSON readers for C++ can be found in the JSON webdocs. A reasonably good header-only library is JSON for Modern C++. I have chosen to use that library because its constructs are similar to those of ZenXml.

We add a new method, readJSON, to the class BoundaryReader and implement it as follows.

#include <BoundaryReader.h>
#include <json.hpp>
using json = nlohmann::json;
bool
BoundaryReader::readXML(const std::string& inputFileName) const 
{
  // Create an input filestream
  std::ifstream ifs(inputFileName);
  if (!ifs) {
    std::cout << "*ERROR** Could not read input file " << inputFileName << "\n";
    return false;
  }
  // Read the file stream into a string stream
  std::stringstream iss;
  iss << ifs.rdbuf();
  ifs.close();
  // Parse the input stream
  json docs;
  try {
    docs << iss;
  } catch (std::invalid_argument e) {
    std::cout << "*ERROR** Could not parse input file " << inputFileName
              << "\n";
    std::cout << "Please check for correctness using a linter.\n";
    return false;
  }
  // Read the boundary information
  json boundary_ps;
  try {
    boundary_ps = ps["Boundary"];
  } catch (std::exception e) {
    std::cout << "**ERROR** \"Boundary\" key not found. \n";
    return false;
  }
  // Read the container dimensions
  std::string vecStr;
  try {
    vecStr = boundary_ps["containerMin"].get<std::string>();
  } catch (std::exception e) {
    std::cout
      << "**ERROR** Container min. position not found in boundary geometry\n";
    std::cout << "  Add the containerMin: [x, y, z]  tag.";
    return false;
  }
  Vec boxMin = Vec::fromString(vecStr);
  try {
    vecStr = boundary_ps["containerMax"].get<std::string>();
  } catch (std::exception e) {
    .....
    return false;
  }
  Vec boxMax = Vec::fromString(vecStr);
  
  try {
    auto bound_ps = boundary_ps["boundary"];
    for (auto object : bound_ps) {
      std::string boundaryType = object["type"].get<std::string>();
      BoundaryId id = object["id"].get<BoundaryId>();
      vecStr = ps["direction"].get<std::string>();
      Vec direc = Vec::fromString(vecStr);
      vecStr = ps["position"].get<std::string>();
      Vec point = Vec::fromString(vecStr);
    }
  } catch (std::exception e) {
    std::cout << "**ERROR** Boundaries not found in boundary geometry\n";
    std::cout << "  Add the boundary key: value array tags etc.";
    return false;
  }
  return true;
}

I’m not really a fan of try-catch blocks, but that’s the easiest way of dealing cleanly with read/parse failures when using JSON for Modern C++. For research codes, this approach will suffice. An alternative is to use a check of the form

{
  auto ps_iter = ps.find("key_name");
  if (ps_iter == ps.end()) {
    // Error
  }
}

Remarks

Sometimes input/output files for engineering simulations can be quite large. In those situations I would suggest XML with binary data. In future post I’ll show you how to create a VTK XML format output file with binary data.

If you have questions/comments/corrections, please contact banerjee at parresianz dot com dot json (without the dot json).

2022

Back to top ↑

2021

Back to top ↑

2017

Creating an animation with d3.js

20 minute read

Introduction In Part 8 of the series on return algorithms for plasticity we animated the closest-point return algorithm as shown below.

Geometric closest point return algorithm

21 minute read

Introduction In Part 7, we saw that for isotropic elastic materials and perfect associated plasticity, the trial stress and the actual stress are at the shor...

Exploring closest point return plasticity

16 minute read

Introduction In Part 6, I explained why a backward Euler stress update and a closest point return from the trial stress to the yield surface are closely rela...

The plane stress return algorithm

15 minute read

Introduction In the previous part of this discussion, I derived plane stress expressions for linear elasticity, the Drucker-Prager yield function, and the as...

XML format for particle input files

15 minute read

Introduction Let us now change tack slightly and return to an issue I had talked about earlier in Input files: reading XML. Typical input files in research ...

Plotting particles with vtk.js

22 minute read

Introduction In the previous articles in this series we talked about: Part 1: Reading VTK format particles with Javascript in a browser Part 2: Saving ...

Setting up the Three.js scene and camera

14 minute read

Introduction In the previous articles in this series we talked about: Part 1: Reading VTK format particles with Javascript in a browser Part 2: Saving ...

Setting up the Three.js renderer

12 minute read

Introduction The previous articles in this series were about: Part 1: Reading VTK format particles with Javascript in a browser Part 2: Saving the read...

Plotting VTK particles with Three.js

11 minute read

Introduction In Part 2 of this series, we showed how the particle data are saved into a Vuex store. Now we are ready to visualize the data. In this article...

Saving particle data in a Vuex store

15 minute read

Introduction In the first part of this series on scientific visualization in Javascript, we saw how data in VTK unstructured grid format produced by C++ simu...

Reading VTK particles in Javascript

16 minute read

In our previous article we discussed the process of calling XML functions in C++ to write data produced by particle simulations in XML format files. These o...

Particle data in VTK XML

12 minute read

In my previous post on writing VTK output files I described how mesh data can be output in VTK XML format. In this article I will talk about how I output par...

Writing VTK XML files in C++

16 minute read

I visualize the output of my simulations using either LLNL’s Visit or Kitware’s ParaView. These tools are wonderful for dealing with large datasets and can ...

Reading JSON in C++

11 minute read

In my previous post on reading XML input files, I discussed how input files can be made more human friendly with XML markup. In some situations, it may be p...

Input files: Reading XML

14 minute read

Mechanics research codes are typically written by graduate students who aim to get their work done as quickly as possible. These codes are not meant to las...

Command pattern for regression testing

8 minute read

A few days ago I had to refactor a 20,000 line class that was being used as a regression tester for discrete element and peridynamics simulations. After som...

Formatting C++ code

3 minute read

Every once in a while I need to recall how clang-format is set up and run on my Ubuntu 16.04 machine. This post is meant to act as a reminder.

Back to top ↑

2014

Sampling large data sets (Part 2)

6 minute read

Recall that we had found a set of points that samples a cylindrical domain uniformly. However, these points do not match the locations of our sensors and we...

Sampling large data sets (Part 1)

4 minute read

The amount of data is large. Before we analyze the whole set of data, we can find trends by examining a smaller set of sensors. A smaller set is also usef...

Back to top ↑