# Read reactions for restrained nodes only

Common after an analysis: you only care about reactions at supports,
not internal nodes. Two-step: filter nodes to `NodeType=Restrained`
to get the support node Ids, then pass them as the `Nodes` filter on
the reactions endpoint.

`Nodes` accepts SG list format — comma-separated Ids and dash ranges
(`"1,3-7,10"`). Build it with `string.Join(",", ids)` (C#) or `",".join(...)` (Python).

The snippet below opens the `Portal Frame.SG` sample, runs a linear
static analysis to populate reactions, queries restrained nodes, then
prints their reactions. `try / finally` closes the job even if a step
in the middle throws.

<CodeTabs>
```csharp title="C#"
using SpaceGassApi;
using SpaceGassApi.Models;

var client = SpaceGassApiClient.CreateClient("http://localhost:34560");

try
{
    await client.Job.OpenSample.PostAsync(
        new OpenSampleRequest { FileName = "Portal Frame.SG" });

    // Run analysis so reactions are available.
    var run = await client.Job.Analysis.Static.RunLinear.PostAsync(
        new StaticSettingsUpdate());

    while (true)
    {
        await Task.Delay(500);
        var s = await client.Job.Analysis.Runs[run!.RunId!.Value].GetAsync();
        if (s!.Status is AnalysisRunStatus.Completed
                      or AnalysisRunStatus.Failed
                      or AnalysisRunStatus.Cancelled) break;
    }

    // 1. Get the restrained nodes
    var restrained = await client.Job.Structure.Nodes.GetAsync(
        config => config.QueryParameters.NodeType = NodeTypeFilter.Restrained);

    var nodeFilter = string.Join(",",
        restrained!.Where(n => n.Id != null).Select(n => n.Id!.Value));

    // 2. Read reactions filtered to those nodes
    var result = await client.Job.Query.Analysis.Static.NodeReactions.GetAsync(
        config => config.QueryParameters.Nodes = nodeFilter);

    foreach (var r in result!.Results!)
    {
        Console.WriteLine(
            $"Node {r.Node}, Case {r.LoadCase}: " +
            $"Fx={r.Fx:F2}, Fy={r.Fy:F2}, Fz={r.Fz:F2}");
    }
}
finally
{
    await client.Job.Close.PostAsync();
}
```

```python title="Python"
import asyncio
from space_gass_api import SpaceGassApiClient
import space_gass_api.models as models

client = SpaceGassApiClient.create_client("http://localhost:34560")

try:
    await client.job.open_sample.post(
        models.OpenSampleRequest(file_name="Portal Frame.SG"))

    # Run analysis so reactions are available.
    run = await client.job.analysis.static.run_linear.post(
        models.StaticSettingsUpdate())

    while True:
        await asyncio.sleep(0.5)
        s = await client.job.analysis.runs.by_run_id(str(run.run_id)).get()
        if s.status in (
            models.AnalysisRunStatus.Completed,
            models.AnalysisRunStatus.Failed,
            models.AnalysisRunStatus.Cancelled,
        ):
            break

    # 1. Get the restrained nodes
    restrained = await client.job.structure.nodes.get(
        node_type=models.NodeTypeFilter.Restrained)

    node_filter = ",".join(str(n.id) for n in restrained if n.id is not None)

    # 2. Read reactions filtered to those nodes
    result = await client.job.query.analysis.static.node_reactions.get(
        nodes=node_filter)

    for r in result.results:
        print(f"Node {r.node}, Case {r.load_case}: "
              f"Fx={r.fx:.2f}, Fy={r.fy:.2f}, Fz={r.fz:.2f}")
finally:
    await client.job.close.post()
```

```bash title="curl"
# 1. Restrained nodes
curl "http://localhost:34560/api/v1/job/structure/nodes?nodeType=Restrained"

# 2. Reactions for the returned Ids (substitute below)
curl "http://localhost:34560/api/v1/job/query/analysis/static/node-reactions?nodes=1,2,3"
```
</CodeTabs>

## Run this example locally

The same code (against your own .sg file rather than the sample) is
in the repo as
[`Example.QueryRestrainedNodes`](https://github.com/SpaceGass/space-gass-api/tree/main/sdks/csharp/examples/Example.QueryRestrainedNodes) (C#) and
[`query_restrained_nodes`](https://github.com/SpaceGass/space-gass-api/tree/main/sdks/python/examples/query_restrained_nodes) (Python).
Clone and run:

<CodeTabs>
```bash title="C#"
git clone https://github.com/SpaceGass/space-gass-api.git
cd space-gass-api/sdks/csharp/examples/Example.QueryRestrainedNodes
dotnet run
```

```bash title="Python"
git clone https://github.com/SpaceGass/space-gass-api.git
cd space-gass-api/sdks/python/examples/query_restrained_nodes
pip install space-gass-api    # once per environment
python query_restrained_nodes.py
```
</CodeTabs>

Edit the example's `PROJECT_FILE_PATH` constant first to point at an
analysed `.sg` file.

## See also

- [Filtering & Querying](/guides/filtering-and-querying) — full SG-list
  filter syntax and pagination.
