Single-profile workflow (GQ/H example)#
Extended variant: build a five-layer dry sand profile, Darendeli reference curves, MRDF curve fitting, and ChiChi motion selection.
1"""
2GQ/H nonlinear analysis — 5-layer dry sand profile, Darendeli curves, MRDF fitting, ChiChi motion.
3All property name strings verified against DeepSoilFile/SoilLayer.cs and ProjectSettings.cs.
4"""
5
6from __future__ import annotations
7import math, os
8from rsseismic import RSSeismicApplication, logger
9from rsseismic.enums import FittingProcedureModel
10
11# ── Configuration ──────────────────────────────────────────────────────────
12OUTPUT_PROJECT = r"C:\Users\DylanCentella\source\repos\RSSeismicScripting\tests\resources\test_profile.rsseismicfile"
13SCRIPTING_PORT = 60058
14CHICHI_MOTION_DIR = r"C:\Program Files\Rocscience\RSSeismic\Resources\InputMotions"
15CHICHI_MOTION_NAME = "ChiChi" # verify with model.Motions.listMotions() if unsure
16PROFILE_NAME = "Profile 1"
17
18# Layer properties (metric: m, kN/m³, kPa)
19N_LAYERS = 5
20THICKNESS = 5.0 # m
21UNIT_WEIGHT = 20.0 # kN/m³
22VS = 250.0 # m/s — set via "ShearWaveVelocity"; Gmax computed automatically
23K0 = 0.46 # lateral earth pressure coefficient — key is "Ko" (letter o, not zero)
24PI = 0.0 # plasticity index
25PHI_DEG = 35.0 # friction angle (degrees) — used to compute ShearStrength per layer
26
27def shear_strength_kPa(layer_index_0: int) -> float:
28 """τ_max = σ'v_mid · tan(φ') [dry profile, c'=0, σ'v = total stress]"""
29 z_mid = layer_index_0 * THICKNESS + THICKNESS / 2.0
30 sigma_v_eff = UNIT_WEIGHT * z_mid # kPa
31 return sigma_v_eff * math.tan(math.radians(PHI_DEG))
32
33# ── Main ───────────────────────────────────────────────────────────────────
34def main() -> None:
35 app = RSSeismicApplication(port=SCRIPTING_PORT)
36 app.ping()
37 model = app.newProject()
38
39 try:
40 # 1. Analysis mode — confirmed enum value: "Nonlinear" (not "NonLinear")
41 model.ProjectSettings.Data.setEnumValue("analysisMode", "Nonlinear")
42 model.ProjectSettings.Data.setEnumValue("hystereticFormulation", "NonMasing")
43
44 # 2. Activate target profile
45 model.Profiles.setActiveProfile(PROFILE_NAME)
46
47 # 3. Remove any existing layers, add 5 fresh ones
48 # Get the existing layers BEFORE adding new ones
49 existing = model.Profiles.listActiveSoilLayers()
50
51 # Add the 5 new layers first (now there's always more than one layer)
52 result = model.SoilLayers.appendLayers(N_LAYERS)
53 layer_ids = list(result.layerIDs)
54
55 # Now it's safe to delete the originals
56 for s in existing:
57 model.SoilLayers.deleteLayer(s.layerID)
58
59 # 4. Configure each layer
60 for i, lid in enumerate(layer_ids):
61 layer = model.Profiles.getSoilLayer(lid)
62 tau_max = shear_strength_kPa(i)
63
64 # Basic properties — all confirmed names from SoilLayer.cs
65 layer.setThickness(THICKNESS)
66 layer.setUnitWeight(UNIT_WEIGHT)
67 layer.setSoilModel("GQ_H") # eSoilModel.GQ_H
68 layer.Data.setDoubleProperty("ShearWaveVelocity", VS) # Gmax computed automatically
69 layer.Data.setDoubleProperty("ShearStrength", tau_max) # τ_max in kPa
70
71 # 5. Darendeli reference curve
72 ref = layer.ReferenceCurve
73 ref.setSoilType("Sand") # eSoilType.Sand (PI=0 → sandy)
74 ref.setCurveModel("Darendeli_2001") # eCurveModel.Darendeli_2001
75 ref.Data.setDoubleProperty("Ko", K0) # "Ko" — letter 'o', NOT the number '0'
76 ref.Data.setDoubleProperty("PI", PI) # "PI" confirmed in ReferenceCurve.cs
77 # OCR, N, Frequency, etc. left at their project defaults
78
79 n_pts = ref.generateReferenceCurve()
80 logger.info("Layer %d (z_mid=%.1f m): %d ref curve pts, τ_max=%.1f kPa",
81 i + 1, i * THICKNESS + THICKNESS / 2, n_pts, tau_max)
82
83 # 6. MRDF curve fit
84 fitted = layer.Curve.runCurveFit(FittingProcedureModel.MRDF_UIUC)
85 logger.info("Layer %d: MRDF fit → %d points.", i + 1, fitted)
86
87 # 7. Add ChiChi motion directory and select it
88 model.Motions.addMotionDirectory(CHICHI_MOTION_DIR)
89 model.Motions.refreshMotionsList()
90 available = [m.name for m in model.Motions.listMotions()]
91 logger.info("Available motions: %s", available)
92 model.Motions.setMotionSelection([CHICHI_MOTION_NAME], selectOnlyListed=True)
93
94 # 8. Save and compute
95 model.saveAs(OUTPUT_PROJECT)
96 compute_result = model.runCompute(timeout=3600)
97 if not compute_result.success:
98 raise RuntimeError(f"RunCompute failed: {compute_result.errorMessage}")
99 if compute_result.partialSuccess:
100 logger.warning("Partial success: %s", compute_result.errorMessage)
101
102 # 9. Result path
103 entry = model.Results.getResultDatabasePath(PROFILE_NAME, CHICHI_MOTION_NAME)
104 print(f"\nResult database: {entry.resultDatabasePath}")
105 print(f"Exists on disk: {entry.resultDatabaseExists}")
106
107 finally:
108 model.close(saveProject=False)
109 app.close()
110
111if __name__ == "__main__":
112 main()