.. _server-for-particle-models-page:

###########################################
Server for Particle Models (PtServer)
###########################################

******************************************************************************
Getting Started with ParticleModel (Particle Simulation Playback)
******************************************************************************

The prerequisites for the particle server can be found in :doc:`/start/supported-platforms`.

The PtServer is a **stateless REST** server: unlike UgServer (WebSocket-based), no sticky
sessions are required and the server can be horizontally scaled behind a load balancer. Multiple
clients can connect to the same server concurrently, sharing cached dataset readers.

1.  Download and extract |ProductName| distribution archive from the Tech Soft 3D Developer Zone:
    https://developer.techsoft3d.com/

2.  Specify your license, either by modifying server/PtServer/Main.js to specify your license code:

    ::

        ptServer.setLicenseCode(myCode);


    or by copying the hoops_license.h file downloaded from the developer zone into the server/PtServer folder,
    or by specifying the ``CEW_TECH_SOFT_LICENSE_FILE`` environment variable to point to the hoops_license.h,
    or by setting the ``CEW_TECH_SOFT_LICENSE_CODE`` environment variable directly.

3.  With a terminal prompt, go to the ``server/PtServer`` folder inside the distribution.

4.  Execute the following command to install dependencies:

    ::

        > npm install


5.  Start the server using npm:

    Start the server with the appropriate command for your platform:

    ::

        > npm run server:pt:linux
        > npm run server:pt:win
        > npm run server:pt:mac

    Node will then run Main.js, and the server will start on port 8999 by default. The port can be
    changed by setting the ``CEW_PT_PORT`` environment variable.

    You can verify that the server is running by opening http://localhost:8999 in a browser. You should
    then see a message like this:

    ::

        HOOPS Envision PtServer is alive
         Server ver: 1.0.0-abcdef12
         Node.js ver: v20.11.0 (linux|x64)

6.  We have included a simple http server for hosting the example web apps. To start the http server, go to the
    Examples/HttpServer folder and run:

    ::

        > npm install

    Then start the server by running:

    ::

        > npm start

    This will start the server on port 8000. This can be changed by the PORT environment variable or editing the
    HttpServer.js file.

    Open http://localhost:8000 in your browser and navigate to the particle example
    (e.g. Examples/MinimalPtTypeScript).

7.  Please refer to the documentation to learn more about |ProductName|. The central classes are:

    -   :js:class:`~cee.CloudSession`: Applications will typically create a single instance of
        CloudSession for managing viewers.
    -   :js:class:`~cee.Viewer`: Handles user interaction (pan/rotate/zoom), picking and other view
        related functions.
    -   :js:class:`~cee.pt.ParticleModel`: The main class for interacting with particle datasets. Handles
        model opening, frame fetching, scalar field selection, and animation. ParticleModel requires the
        presence of a running PtServer.
    -   :js:class:`~cee.pt.Animation`: Time-step animation controller with configurable frame rate,
        looping, and preloading support.

**************************
Configuring the PtServer
**************************

The PtServer is configured via environment variables. All variables use the ``CEW_PT_`` prefix.

**Server configuration:**

.. list-table::
   :header-rows: 1
   :widths: 35 15 50

   * - Environment Variable
     - Default
     - Description
   * - ``CEW_PT_PORT``
     - ``8999``
     - TCP port the server listens on.
   * - ``CEW_PT_USE_HTTPS``
     - ``false``
     - Enable HTTPS. Requires ``MyDomain_private.key`` and ``MyDomain.crt`` in the server folder.
   * - ``CEW_PT_MODEL_PATH``
     - ``./test-data/particles``
     - Directory containing particle datasets (PTFX/VTP files or subdirectories).
   * - ``CEW_PT_ENABLE_REST_API_QUERY``
     - ``true``
     - Enable the query endpoints (list models, get info, get frames, switch scalar).
   * - ``CEW_PT_ENABLE_REST_API_UPLOAD``
     - ``false``
     - Enable the upload/delete endpoints. Disabled by default for security.
   * - ``CEW_PT_ENABLE_CORS``
     - ``false``
     - Enable Cross-Origin Resource Sharing headers.
   * - ``CEW_PT_READER_PLUGIN_FOLDER``
     - (empty)
     - Path to folder containing reader plugin shared libraries (``cpt_*.dll/.so/.dylib``).
   * - ``CEW_PT_COMPRESSION_LEVEL``
     - ``6``
     - Gzip compression level for binary responses (0 = disabled, 1-9).
   * - ``CEW_PT_COMPRESSION_THRESHOLD``
     - ``1024``
     - Minimum response size in bytes before compression is applied.
   * - ``CEW_PT_MAX_UPLOAD_SIZE``
     - ``5368709120`` (5 GB)
     - Maximum upload file size in bytes.
   * - ``CEW_PT_MAX_CONCURRENT_UPLOADS``
     - ``3``
     - Maximum number of concurrent upload requests.
   * - ``CEW_PT_CACHE_MEMORY_LIMIT_MB``
     - ``0``
     - Server-side C++ frame cache memory limit in MB. 0 = use C++ default (5 GB).

.. _server-particle-model-logging:

**********************
Logging in PtServer
**********************

The PtServer supports logging to console and file in two different formats: Standard (more human
readable) and JSON (for easy processing or consumption by e.g. Logstash).

The logging output of the PtServer can be controlled via the following environment variables:

-   ``CEW_PT_LOG_CONSOLE_OUTPUT_TYPE``: Format for console log. Possible values: "standard", "json", "none".
    Default: "standard".
-   ``CEW_PT_LOG_FILE_OUTPUT_TYPE``: Format for file log. Possible values: "standard", "json", "none".
    Default: "json".
-   ``CEW_PT_LOG_FILENAME``: If file output type is not NONE, use this to specify the name of the log file.
    Default: "c3_pt_server.log".
-   ``CEW_PT_LOG_LEVEL``: Specify what to log. Possible values: 1: Error, 2: Warning, 3: Info, 4: Debug.
    A 3 will log Error, Info and Warning, but not any debug messages. This is default.
-   ``CEW_PT_LOG_HTTP``: Log every HTTP request. Default: "false".

.. note::

   Unlike UgServer, PtServer does **not** support client-side log-context key/value injection
   (i.e. there is no equivalent of :js:func:`RemoteModel.setServerLogContextKeyValueArr() <cee.ug.RemoteModel.setServerLogContextKeyValueArr()>`).
   Each REST request is independent and carries no session state.

On Linux, logging of segmentation faults is also added to help debugging situations where the server crashes.

**********************************
Session Model / Scalability
**********************************

The PtServer architecture differs fundamentally from UgServer in its session model:

- **UgServer** (WebSocket): maintains one session per socket, with a 1:1 ``VizDataExtractor`` per client.
  State is tied to the socket connection.
- **PtServer** (REST): completely stateless HTTP. No session concept. N clients share M cached dataset
  readers via a ``DatasetReaderFactory`` with ref-counting and LRU eviction.

Key implications:

- **Horizontal scaling**: PtServer instances can be placed behind a standard HTTP load balancer with
  no sticky-session requirement.
- **Multi-client**: Multiple clients requesting the same model share one reader instance (concurrent
  access serialized by a C++ mutex). Different models get separate readers from the factory cache.
- **No reconnection handling needed**: Because PtServer is stateless, there is no equivalent of
  UgServer's ``CEW_UG_MAX_DISCONNECT_DURATION_MS``. Each request is self-contained.

**********************
REST API Reference
**********************

All endpoints are prefixed with ``/api/v1``. The query endpoints require ``CEW_PT_ENABLE_REST_API_QUERY=true``
(default). The upload/delete endpoints require ``CEW_PT_ENABLE_REST_API_UPLOAD=true``.

**Query endpoints:**

.. list-table::
   :header-rows: 1
   :widths: 10 40 50

   * - Method
     - Path
     - Description
   * - GET
     - ``/api/v1/models``
     - List all available models in the configured model path. Returns a JSON array of model keys.
   * - GET
     - ``/api/v1/models/:modelKey/info``
     - Get dataset metadata: modelKey, maxParticleCount, frameCount, boundingBox, scalarFieldNames,
       activeScalarField, hasScalarData, scalarRange.
   * - GET
     - ``/api/v1/models/:modelKey/frame/:frameIndex``
     - Fetch a binary frame buffer. Optional query parameter ``decimation`` (0.0-1.0) for LOD reduction.
       Response header ``X-Particle-Count`` indicates actual particle count in the buffer.
   * - PUT
     - ``/api/v1/models/:modelKey/scalar/:fieldName``
     - Switch the active scalar field for subsequent frame requests.
   * - DELETE
     - ``/api/v1/models/:modelKey/scalar``
     - Clear the active scalar field (position-only mode).

**Upload/delete endpoints** (requires ``CEW_PT_ENABLE_REST_API_UPLOAD=true``):

.. list-table::
   :header-rows: 1
   :widths: 10 40 50

   * - Method
     - Path
     - Description
   * - POST
     - ``/api/v1/models``
     - Upload a new model (multipart form data). Subject to ``CEW_PT_MAX_UPLOAD_SIZE`` and
       ``CEW_PT_MAX_CONCURRENT_UPLOADS`` limits.
   * - DELETE
     - ``/api/v1/models/:modelKey``
     - Delete a model from the server. Symlinks are rejected for safety.

**Health endpoint:**

.. list-table::
   :header-rows: 1
   :widths: 10 40 50

   * - Method
     - Path
     - Description
   * - GET
     - ``/``
     - Returns server-alive message with version info (non-production mode).

**********************
Binary Wire Format
**********************

Frame data is transmitted in a compact binary SOA (Structure of Arrays) format optimized for bandwidth:

- **Particle count** (uint32): number of particles in this frame.
- **IDs** (int32[]): delta-encoded particle identifiers.
- **X positions** (uint16[]): quantized X coordinates.
- **Y positions** (uint16[]): quantized Y coordinates.
- **Z positions** (uint16[]): quantized Z coordinates.
- **Scalars** (uint16[], optional): quantized scalar values (only present when a scalar field is active).

Quantization formula: ``quantized = round((value - min) / (max - min) x 65535)``

Without scalars the format uses 10 bytes per particle; with scalars 12 bytes per particle. Combined with
gzip compression, this typically achieves 4x bandwidth savings compared to full-precision float transmission.

.. note::

   This is an internal wire protocol. SDK users do not need to decode it: the
   :js:class:`~cee.pt.ParticleModel` client class handles decoding and dequantization automatically.

************************************
Request Cancellation
************************************

Because PtServer uses REST (not WebSockets), there is no socket reconnection handling. However, the
client-side :js:class:`~cee.pt.ParticleModel` implements request cancellation:

Calling :js:func:`~cee.pt.ParticleModel.setFrame` automatically cancels any previous inflight frame
request using an ``AbortController`` pattern. This ensures that rapid frame seeking (e.g. during
scrubbing or animation) does not queue up stale responses, and only the most recent frame request
completes.

**********************
Particle Reader Plugins
**********************

The PtServer supports dynamic loading of reader plugins for custom particle file formats. Plugins are
discovered from the folder specified by ``CEW_PT_READER_PLUGIN_FOLDER`` and must follow the naming
convention ``cpt_{NAME}.dll`` (Windows), ``cpt_{NAME}.so`` (Linux), or ``cpt_{NAME}.dylib`` (macOS).

See :doc:`/guide/reader-plugins-particle` for full details on the plugin API and development workflow.

**********************
Examples
**********************

A minimal TypeScript example demonstrating PtServer usage is included in the distribution at
``Examples/MinimalPtTypeScript/``. See :doc:`/examples/examples` for a full list of included examples.

**********************
Cross-References
**********************

- :doc:`/start/modules`: module overview including ``cee.pt``.
- :doc:`/guide/distribution`: distribution layout including ``server/PtServer``.
- :doc:`/guide/reader-plugins-particle`: reader plugin development for PtServer.
- :doc:`/class-index`: API reference for ``cee.pt.ParticleModel``, ``cee.pt.Animation``, and other classes.
