# rom.js

[![npm version](https://badge.fury.io/js/@simzero%2From.svg)](https://badge.fury.io/js/@simzero%2From)
[![Docker](https://badgen.net/badge/icon/docker?icon=docker&label)](https://github.com/orgs/simzero-oss/packages/container/package/rom-js)
[![stability-beta](https://img.shields.io/badge/stability-beta-33bbff.svg)]()
[![Join Slack](https://img.shields.io/badge/Join%20us%20on-Slack-e01563.svg)](https://join.slack.com/t/cfd-xyz/shared_invite/zt-12uquswo6-FFVy95vRjfMF~~t8j~UBHA)
[![License: LGPL v3](https://img.shields.io/badge/License-LGPL_v3-blue.svg)](https://github.com/simzero-oss/rom-js/blob/main/LICENSE)
[![PayPal donate button](https://img.shields.io/badge/paypal-donate-red.svg)](https://www.paypal.com/donate/?hosted_button_id=KKB4LH96E59A4)

`rom.js` is a JavaScript port for solving the online stage of reduced-order model (ROM) and visualizing the outputs on the web. The current version uses [OpenFOAM](https://www.openfoam.com) and [ITHACA-FV](https://github.com/mathLab/ITHACA-FV) for generating the CFD snapshots and the ROM.


`rom.js` is used in [http://cfd.xyz](http://cfd.xyz), check the website and the code at [cfd.xyz GitHub](https://github.com/simzero-oss/cfd-xyz).


This is a beta version, please handle it with care. Further features, optimizations and fixes are expected.

## Usage

This module can be directly installed with:

```console
npm install --save @simzero/rom
```

Alternatively, the module can be built and tested following the instructions described in [Option 1](#option-1-building-and-testing-with-docker-as-the-only-requirement) and [Option 2](#option-2-building-and-testing-by-compiling-the-third-party-libraries).

A minimal usage example can be found in `tests/pitzDaily` using node. This uses data generated by the `steady` application. The `offline` folder contains examples for generating this data.

```javascript
import rom from '@simzero/rom'
import Papa from 'papaparse'
import fs from 'fs'

const rootPath = "../../surrogates/OF/incompressible/simpleFoam/pitzDaily/";
const outputFile = 'U_' + U + '_nu_' + nu + '.vtu';

const loadData = async (dataPath) => {
  const data = await readFile(rootPath + dataPath)
  const vector = dataToVector(data);
  return vector;
}

const readFile = async (filePath) => {
  const csvFile = fs.readFileSync(filePath)
  const csvData = csvFile.toString()
  return new Promise(resolve => {
    Papa.parse(csvData, {
      delimiter: " ",
      dynamicTyping: true,
      skipEmptyLines: true,
      header: false,
      complete: results => {
        resolve(results.data);
      }
    });
  });
};

const dataToVector = (data) => {
  const vecVec = new rom.VectorVector();
  let rows = 0;
  let cols = 0;
  data.forEach(row => {
    var vec = new rom.Vector();
    row.forEach(value => {
      vec.push_back(value)
      if (rows === 0)
        cols++;
    });
    vecVec.push_back(vec)
    rows++;
  })
  return [vecVec, rows, cols];
}

(async () => {

  await rom.ready

  // - Velocity and viscosity values for the online solution
  const U = 3.0; // - m/s
  const nu = 1e-05; // - m2/s

  // - Number of patches with non-homogeneous BCs
  const N_BC = 1;

  // - Loading ROM data (e.g. generated with the steady app)
  const P =loadData('matrices/P_mat.txt');
  const M = loadData('matrices/M_mat.txt');
  const K = loadData('matrices/K_mat.txt');
  const B = loadData('matrices/B_mat.txt');
  const modes = loadData('EigenModes_U_mat.txt');
  const coeffL2 = loadData('matrices/coeffL2_mat.txt');
  const mu = loadData('par.txt');
  const grid_data = fs.readFileSync('pitzDaily.vtu')

  // - Defining variables sizes
  const Nphi_u = B[1];
  const Nphi_p = K[2];
  const Nphi_nut = coeffL2[1];

  // - Defining reducedSteady
  const reduced = new rom.reducedSteady(Nphi_u + Nphi_p, Nphi_u + Nphi_p);


  // - Setting up grid and ROM data
  reduced.readUnstructuredGrid(grid_data);
  reduced.Nphi_u(Nphi_u);
  reduced.Nphi_p(Nphi_p);
  reduced.Nphi_nut(Nphi_nut);
  reduced.N_BC(N_BC);
  reduced.addMatrices(P, M, K, B);
  reduced.addModes(modes);
  reduced.setRBF(mu, coeffL2);

  // - Loading turbulent related matrices
  for (var i = 0; i < Nphi_u; i ++ ){
    const C = loadData("matrices/C" + i + "_mat.txt");
    const Ct1 = loadData("matrices/ct1_" + i + "_mat.txt");
    const Ct2 = loadData("matrices/ct2_" + i + "_mat.txt");

    reduced.addCMatrix(C, i);
    reduced.addCt1Matrix(Ct1, i);
    reduced.addCt2Matrix(Ct2, i);
  }

  reduced.preprocess();

  // - Defining viscosity and solving for the given velocity
  reduced.nu(nu*1e-05);
  reduced.solveOnline(U);

  // - Reconstructing data from Eigen to VTK and exporting the grid
  reduced.reconstruct();
  const dataString = reduced.exportUnstructuredGrid();

  // - Saving the VTK file
  const outputFile = 'U_' + U + '_nu_' + nu + '.vtu';
  fs.writeFileSync(outputFile, dataString)

  reduced.delete();

})();
```

## Option 1 Building and testing with Docker as the only requirement 

This is the preferred and easiest method for working with this repository.

The [rom-js](https://github.com/orgs/simzero-oss/packages/container/package/rom-js) Docker image contains all the configuration and required third-party libraries for: 1) building the JavaScript module, 2) running OpenFOAM and 3) generating the ROM data using ITHACA-FV. The following versions are included in the image:

* [Emscripten](https://github.com/emscripten-core/emscripten) 3.1.1
* [npm](https://github.com/npm/cli) 8.5.3
* [node](https://github.com/nodejs/node) v14.18.2
* [Splinter](https://github.com/bgrimstad/splinter) v3.0 (compiled with emcc)
* [Eigen](https://gitlab.com/libeigen/eigen) v3.4.0 (compiled with emcc)
* [VTK](https://gitlab.kitware.com/vtk/vtk) v9.1 (compiled with emcc)
* [OpenFOAM](https://develop.openfoam.com/Development/openfoam) v2106
* [ITHACA-FV](https://github.com/mathLab/ITHACA-FV) 3.0 ([@carpemonf fork](https://github.com/carpemonf/ITHACA-FV))

### Requirements

* [Docker](https://www.docker.com/get-started) 20.10.12

### Building

The node version of the module can be executed outside a web browser with a back-end JavaScript runtime environment (Node.js). The following command builds the node version of the module:

```console
TARGET=node make all
```

This repository includes examples for solving the ROM online stage with the node version. A web version of the module can be also built and used in a web environment (check [cfd.xyz](http://cfd.xyz)). The following command builds the web version of the module:

```console
TARGET=web make all
```

### Generating the ROM data

The CFD snapshots are generated directly with OpenFOAM and later used in ITHACA-FV for generating the ROM. The `pitzDaily` tutorial executes 800 simulations for different parameters of viscosity and inlet velocity. You can skip this step by downloading and extracting the `surrogates` folder with:

```console
make data
```

You can also create the content of the `surrogates` folder. Single core simulations are run in parallel for the given number of processors set with the `CORES` variable:


```console
CORES=8 make rom
```


The snasphots can be found at `ITHACAoutput/Offline` for every case, and `ITHACAoutput/Parameters` the coressponding parameters for every folder in `ITHACAoutput/Offline`. The `ITHACAoutput/Reconstruction` contains folders for the online stage for the selected parameters.

The required data from `rom.js` is automatically linked to the tutorials in the `tests` folder for completing the next step.

### Testing

Using the ROM data the `tests/pitzDaily` generates outputs for a given inlet velocity and viscosity set.

The following command returns  `*.vtu` files for the chosen velocity and viscosity sets:

```console
make test
```

## Option 2 Building and testing by compiling the third-party libraries

This option compiles Emscripten versions of Splinter, Eigen and VTK. OpenFOAM and ITHACA-FV are also compiled.

### Requirements

* [Docker](https://www.docker.com/get-started) 20.10.12
* npm 6.14.11
* node v14.15.5

### Building

Initialize the third-party submodules with:

```console
git submodule update --init --recursive
```

A local installation of ITHACA-FV ([@carpemonf fork](https://github.com/carpemonf/ITHACA-FV)) and OpenFOAM (v2106) is needed. You can use your local versions and skip this step.

Check system [requirements](https://www.openfoam.com/documentation/system-requirements) for OpenFOAM and ITHACA-FV and run:


```console
make compiled-non-emcc
```

For building the node version of the `rom.js` module run:

```console
TARGET=node make compiled-emcc
```

For building the web version of the `rom.js` module run:

```console
TARGET=web make compiled-emcc
```

### Generating the ROM data


The following command will run OpenFOAM with 8 cores for generating the CFD data and later the ROM:

```console
CORES=8 make compiled-rom
```

### Testing

```console
make compiled-test
```

## Contributing

Everyone is welcome to contribute to this project. See [CONTRIBUTING.md](https://github.com/simzero-oss/rom-js/blob/main/CONTRIBUTING.md) for further details.

Your donations encourage future developments and help with server costs for providing a better service. If you like the tool you can [:heart: donate](https://www.paypal.com/donate/?hosted_button_id=KKB4LH96E59A4).

## License

[GNU Lesser General Public License v3.0](https://github.com/simzero-oss/rom-js/blob/main/LICENSE)
