From Text File to Force Diagram

In the previous article we showed how the text files used by CSI software (SAP2000's .s2k) make it possible to automate model creation: groups, section cuts, all generated by routines written with the help of AI. Today we close the loop from the opposite end: querying results.

The starting observation is simple and, for many users, surprising: when you export a solved model to .s2k with the results tables included, that text file contains everything: the geometry, the section cuts, the forces for every combination, station by station. No API required, no intermediate Excel, no need to even open SAP2000. It is a file that any program (or any AI) can read.

 
And here is an advantage of CSI software worth underlining. The .s2k, like ETABS' .e2k or SAFE's .f2k, is not a partial export or a read-only report: it is the complete model, with geometry, assignments, load cases, combinations and every results table, in readable, documented text that the program itself reads back in. Few analysis packages offer this two-way street: the norm is a model locked away in a binary format, with results leaving only through partial exports, reports, or an API. In CSI software, the model and its results are always within reach of anyone who wants to automate them: no extra licenses, no middlemen, just a plain text file.

 

The scope of the tool

What we asked the AI for was a results-browsing routine with one clear interaction rule: first you pick the structural element, and only then is the force view generated. The result is a single HTML file that opens in the browser, with the building's floor plan drawn automatically from the geometry in the .s2k itself: slab outline, beams, columns, and walls, each identified by the type of finite element that models it.

Better than describing it is letting you test it: the actual tool is embedded right below.

 

The floor plan is rebuilt from the geometry tables in the .s2k — walls = vertical area elements, columns = vertical frames, beams and slab outline in gray. Click the orange circle (core) or one of the squares (columns) and pick the load case. (The charts load from the Plotly CDN; an internet connection is required.)

 

From there, every click generates the corresponding view, with two distinct and deliberate behaviors:

Core and walls: forces come from the section cuts defined in the model (the naming convention from the previous article: PAR_P3_inf, and so on). These are the six integrated forces F1, F2, F3, M1, M2, M3 over the height, with the Max/Min envelope of the combinations.

Columns: here we do not use section cuts. Each column is individually clickable and its diagram (P, V2, V3, T, M2, M3) comes straight from the frame element forces, station by station. Interestingly, the routine detected that the "columns" section cut in the original model was cutting all the columns at once, which is useful as a global story cut but redundant once each column has its own diagram, so it is hidden automatically (with an option to keep it).

 

How simple it is, in practice

Here is the point we want to drive home: we did not write a single line of code. The "source code" of this tool was a set of requests like these:

 
"Create a routine where you can pick the structural element, and only then is the force view generated."

"I need the floor plan to be displayed so you can see and select the element."

"For the columns, don't use the section cut: show an isolated diagram for each column."

 

Three iterations in plain language, each one refining the previous. The AI took care of reading the tables, rebuilding the floor plan, handling sign conventions, and generating the interface. Our test file was 374 MB; the routine processes it in about 1.5 seconds, with nothing to install beyond Python.

 

The anatomy of the .s2k file

To understand how the algorithm fetches the results, it helps to look inside the file. An .s2k exported from a solved model is simply a sequence of tables, the same ones you see in SAP2000 under Display > Show Tables, written as text, with key=value records. The model definition comes first, the results at the end:

 
TABLE: "PROGRAM CONTROL" ProgramName=SAP2000 Version=27.1.0 CurrUnits="KN, m, C" ... ← units
TABLE: "JOINT COORDINATES" ← geometry: joints…
   Joint=1 GlobalX=-15 GlobalY=-6 GlobalZ=0 ...
TABLE: "CONNECTIVITY - FRAME" ← …columns and beams…
TABLE: "CONNECTIVITY - AREA" ← …walls and slabs (the floor plan!)
TABLE: "SECTION CUTS 1 - GENERAL" ← section cut definitions
   CutName=PAR_P1_inf DefinedBy=Group Group=SC_PAR_P1_inf ...
        
TABLE: "ELEMENT FORCES - FRAMES" ← column results
   Frame=1 Station=0 OutputCase=DEAD P=-905.89 V2=-5.15 ...
TABLE: "SECTION CUT FORCES - ANALYSIS" ← section cut results
   SectionCut=PAR_P1_inf OutputCase=COMB1 StepType=Max
        F1=3390.04 F2=2777.05 F3=12594.85 M1=25015.55 M2=39173.12 M3=9316.00 GlobalZ=0

 

Everything is in plain sight: the geometry tables give you the floor plan, the naming convention (PAR_P1_inf = wall, story 1, bottom cut) gives you the organization over the height, and the two results tables give you the numbers. That is why validation is so direct: what the tool draws is literally what sits in these lines.

 

A taste of the algorithm

With the structure in front of us, the heart of the extraction, exactly as the AI wrote it, fits in half a dozen lines: stream through the file (which is why 374 MB is no trouble) and catch the right table:

 
# read only the results table, line by line (streaming)
inside = False
for line in open("Model.s2k", errors="ignore"):
    if line.startswith("TABLE:"):
        inside = 'SECTION CUT FORCES - ANALYSIS' in line
        continue
    if inside and "SectionCut=" in line:
        # each line is a list of key=value pairs; the expression
        # (w+)=(S+) grabs every pair; w+ is the field name (letters/
        # digits) and S+ the value (up to the space); dict() then
        # turns them into a dictionary:
        r = dict(re.findall(r'(w+)=(S+)', line))
        # r["SectionCut"] -> "PAR_P1_inf"
        # r["OutputCase"] -> "COMB1"
        # r["M2"] -> "39173.12"
        # r["M3"] -> "9316.00" (and so on)

 

The rest follows exactly the same logic, and was all written by the AI from the requests above: joining continuation lines (ending in _), rebuilding the floor plan from the geometry tables, reading the frame forces for the columns, and generating the interactive HTML. There is no magic: there is a well-documented text format and a patient machine reading it.

The usefulness is immediate: quick force lookups without opening the model, shareable views for colleagues or reviewers (it's an HTML file, so it opens on any machine), and a foundation that adapts to any model following the same section cut naming convention.

 

The risks and why they are traceable here

It would be irresponsible to present this without the other half of the story. A routine written by AI can be wrong, and in structural results a silent error is dangerous. While developing this tool we ran into concrete examples: the "sup" cuts return forces with the sign flipped (they are the equilibrium of the opposite side of the cut), and in envelopes that flip swaps Max with Min, a subtlety a naive implementation would get wrong without anyone noticing.

 
The essential safeguard: in this kind of tool, everything the routine displays exists, number by number, in SAP2000's own tables. Validation is trivial: open the tables (Display > Show Tables), compare a handful of values at strategic points (base of the core, base of a column, one Max/Min envelope) and confirm the diagram. That is exactly how we validated every version: direct sampling against the source.

 

This is the boundary we recommend: use AI to automate the reading, organization, and visualization of results, where every number is traceable back to its origin and verification costs minutes, and keep the engineer responsible for validation and interpretation. The tool decides nothing; it shows, faster and better, what the model has already calculated. Design responsibility is not something you delegate.