OGR Slip2D es un programa escrito en Python y sus cálculos pueden dirigirse desde un script. Hay dos niveles: el motor, cuyos objetos (Project, las búsquedas y los métodos) dan control total y dejan las comprobaciones de tu cuenta, y la capa de operaciones ogr_api, formada por operaciones con nombre, validadas y reversibles que el servidor MCP publica como herramientas. Además, la ventana del programa incluye una consola de Python conectada al proyecto abierto. A continuación se da un breve ejemplo de cada uno, todos comprobados con la v0.1.235.
5.3.1Dos niveles#
| Motor | Capa de operaciones | |
|---|---|---|
| Paquetes | ogr_core (modelo, ajustes, archivos), ogr_slip2d (métodos, búsquedas), ogr_fem2d (filtración) | ogr_api |
| Trabajas con | objetos de Python: un Project, una búsqueda, su resultado | identificadores: project_id, job_id, result_id |
| Validación | la que hace cada objeto; un ajuste mal escrito se acepta sin dar aviso | se comprueban todos los argumentos y ajustes, y se sugieren los nombres válidos más parecidos |
| Deshacer | no | cada edición es un paso de deshacer |
| Análisis | se ejecutan en tu proceso | tareas en segundo plano, en un proceso hijo que se puede cancelar |
| Respuestas | objetos de resultado completos (cada superficie, cada dovela) | resúmenes compatibles con JSON; resultados completos si se piden |
| Cuándo usarlo | investigación, estudios paramétricos, posprocesados nuevos | scripts que deban comportarse igual que el programa; lo que hace un agente |
Ambos niveles requieren tener instalado el paquete (Sección 1.1), pero ninguno necesita la ventana. En el repositorio, examples/quick_slope.py usa el motor y examples/api_acads.py la capa de operaciones; desde la raíz del repositorio se ejecutan como python -m examples.quick_slope y python -m examples.api_acads.
5.3.2El motor#
Proyectos#
Un modelo es un Project (ogr_core.project). Project.load(path) lee un archivo .ogr y project.save(path) guarda el proyecto en uno (Sección 5.4); Project(name) crea un proyecto vacío, al que se añaden contornos y materiales con add_boundary y add_material, como hace examples/quick_slope.py. ogr_core.project.demo. devuelve el talud de demostración.
El análisis que describe el proyecto#
run_analysis(project, method_ids=None, progress_cb=None, *, allow_unconfigured=False), del módulo ogr_slip2d.analysis_runner, es el análisis que ejecutan Analysis → Compute, la línea de comandos y la capa de operaciones: una búsqueda por método, construida a partir de los ajustes del proyecto. Aplica los coeficientes parciales de la norma de diseño a una copia (el proyecto que se pasa no se modifica) y tiene en cuenta el desembalse rápido, los límites del talud, los filtros de superficies, los objetos de foco, el modo sísmico, los ajustes de convergencia, la semilla y las comprobaciones de admisibilidad.
from ogr_core.project import Project
from ogr_slip2d.analysis_runner import run_analysis
def main():
project = Project.load("slope.ogr")
outcome = run_analysis(project) # the methods enabled in the project
for note in outcome.warnings:
print("Note:", note)
for method_id, result in outcome.results.items():
critical = result.critical
if critical is None:
print(f"{method_id}: no valid surface")
else:
print(f"{method_id}: {critical.fos:.4f} "
f"({result.valid_count} valid of {result.attempts})")
if __name__ == "__main__":
main()- Devuelve un
AnalysisOutcomeconresults(id del método → resultado de la búsqueda),factor_report(el informe de la norma de diseño),warnings(las notas que muestra la ventana) yproject(la copia con los coeficientes parciales aplicados, que es la que se analizó).results, report = run_analysis(project)también funciona. - Si el proyecto no se puede analizar tal como está configurado, lanza
AnalysisNotConfigured, unValueErrorcuyo atributoproblemsenumera todos los motivos;allow_unconfigured=Trueejecuta el análisis de todos modos, para quien ya los haya leído. - Con una norma de diseño activa,
critical.foses un factor de sobredimensionamiento, que ha de superar 1, y no un factor de seguridad. progress_cb(done, total)se invoca a lo largo de toda la ejecución, con el avance de todos los métodos en conjunto.
Una búsqueda construida a mano#
Las búsquedas (GridSearch, SlopeSearch, AutoRefineSearch, BlockSearch, PathSearch, SimulatedAnnealingSearch; la de enjambre de partículas está en ogr_slip2d.particle_swarm) y los nueve métodos (BishopSimplified, JanbuSimplified, JanbuCorrected, OrdinaryFellenius, Spencer, GLEMorgensternPrice, LoweKarafiath, CorpsOfEngineers1, CorpsOfEngineers2) se pueden crear directamente; method_registry() asocia cada id de método con su clase.
from ogr_core.project import Project, save_results
from ogr_slip2d import BishopSimplified, GridSearch
project = Project.load("slope.ogr")
search = GridSearch(method=BishopSimplified(), grid_nx=6, grid_ny=6,
radius_increment=5, num_slices=25)
result = search.run(project) # 7 × 7 centres × 6 radii = 294 circles
print(result.critical.fos, result.attempts)
save_results("slope_bishop.h5", result, project_id=project.id)Un objeto construido a mano usa sus propios valores por defecto y toma del proyecto únicamente el modelo. Un método parte de una tolerancia de 0.001 y 75 iteraciones, sin aceleración de Steffensen (en el proyecto, los valores por defecto son 0.005, 50 y Steffensen activado); GridSearch parte de 10 × 10 intervalos, un incremento de radio de 10, 30 dovelas y un área mínima de 0.5 m², y coloca la rejilla por su cuenta cuando no se indican grid_x y grid_y. Los límites del talud, los filtros de superficies, los objetos de foco y el modo sísmico Ky del proyecto solo llegan a una búsqueda construida a mano si se le pasan, y el desembalse rápido y la norma de diseño los aplica únicamente el módulo que ejecuta los análisis. Para obtener lo que calcula la ventana, usa run_analysis. build_search(project, method_id) devuelve la búsqueda que el proyecto configura para un método, con el desembalse rápido incluido; la norma de diseño la aplica run_analysis a una copia del proyecto.
SearchResult) y qué contiene cada superficie evaluada (LEMResult).| Atributo | Significado |
|---|---|
result.critical | Superficie admisible con el menor factor de seguridad (el menor coeficiente sísmico crítico en un análisis Ky), o None si ninguna superficie es válida. Si todas las superficies válidas incumplen las comprobaciones de admisibilidad, estas se ignoran en lugar de no devolver nada, y inadmissible_count lo indica. |
result.evaluations | Todas las superficies que se dividieron en dovelas y se calcularon, sean válidas o no, en el orden en que se generaron. |
valid_count, invalid_count | Superficies con y sin factor de seguridad; su suma es total_count. |
attempts, focus_rejected | Superficies candidatas generadas (una Grid Search intenta (nx + 1)(ny + 1)(radius increment + 1)) y candidatas descartadas por los objetos de foco. |
top_n(n), min_fos | Las n mejores superficies válidas; factor de seguridad de la superficie crítica. |
minima, optimized, objective | Mínimos locales distintos (enjambre de partículas multimodal); superficie generada por Optimize Surfaces cuando mejoró el resultado de la búsqueda; "fos" o "ky". |
fos | Factor de seguridad de una superficie, o None si no existe (nunca NaN). |
converged, iterations, method_id | Convergencia de la iteración, iteraciones empleadas y método. |
surface, slices | Superficie de rotura (surface.to_dict() da su geometría) y sus dovelas. |
is_valid | Ha convergido, con un factor positivo y sin error. |
admissible, admissibility_note, admissibility_reason | Veredicto de las comprobaciones posteriores al análisis (tracción, m-alfa). |
error_message, reason | Motivo por el que no hay factor de seguridad, en texto y como código (Sección 5.5.2). |
details | Datos adicionales, como lambda, ky o newmark_displacement. |
Una superficie#
evaluate_surfaces(project, surface, method_ids=None) calcula el factor de seguridad de una superficie dada con cada método, y lo hace con las mismas comprobaciones, la misma copia con coeficientes y la misma búsqueda configurada que run_analysis. Su atributo results asocia a cada id de método un resultado, o None si la superficie no corta el modelo.
from ogr_core.project import Project
from ogr_slip2d import SlipCircle
from ogr_slip2d.analysis_runner import evaluate_surfaces
project = Project.load("slope.ogr")
circle = SlipCircle(centre_x=37.5, centre_y=31.7, radius=16.5)
outcome = evaluate_surfaces(project, circle, ["bishop_simplified", "spencer"])
for method_id, res in outcome.results.items():
print(method_id, None if res is None else res.fos)Archivos de resultados#
save_results(path, search_result, project_id="") escribe un resultado de búsqueda en HDF5 y load_summary(path) vuelve a leer sus metadatos y sus matrices de resumen, sin las dovelas; ambas funciones están en ogr_core.project. La estructura del archivo se describe en la Sección 5.4.5.
Scripts y procesos de trabajo#
Una Grid Search de 400 círculos o más se evalúa en un grupo de procesos de trabajo (como máximo 8, que por defecto usan el 50 % de los procesadores lógicos; Project Settings → Advanced permite desactivarlo). En Windows cada proceso de trabajo vuelve a importar el script, por lo que un script que ejecute una búsqueda debe mantener su código de nivel superior dentro de if __name__ == "__main__":, como hacen los ejemplos de esta página y los del repositorio. Si el grupo de procesos no puede arrancar, el análisis no se detiene: la búsqueda pasa a ejecutarse en un solo proceso.
5.3.3La capa de operaciones#
ogr_api reúne lo que el programa puede hacer con un modelo, en forma de operaciones con nombre, argumentos tipados y respuestas compatibles con JSON, sin depender de Qt ni del SDK de MCP. Hay 73 operaciones: las herramientas MCP, salvo server_info, con los mismos nombres; cada parámetro de una herramienta es un parámetro de su operación, así que las tablas de herramientas de la Sección 5.1.7 también las describen. ogr_api.OPERATIONS es el registro.
from pathlib import Path
from ogr_api import OgrApiError, Workspace, call
def main():
ws = Workspace(workdir=Path.cwd())
try:
pid = call(ws, "project_open", path="slope.ogr")["project_id"]
call(ws, "analysis_configure", project_id=pid,
methods=["bishop_simplified", "spencer"],
grid={"nx": 6, "ny": 6}, radius_increment=5)
run = call(ws, "analysis_run", project_id=pid, wait_seconds=300)
if run["state"] != "done":
print("still running:", run["job_id"])
return
for m in run["summary"]["methods"]:
print(m["method_id"], m["caption"], m["value"], m["counts"]["valid"])
try:
call(ws, "settings_set", project_id=pid,
changes={"search.search_methd": "grid"})
except OgrApiError as exc:
print(exc.code, exc.hint) # E_INVALID_ARGUMENT Did you mean 'search_method'?
finally:
ws.shutdown()
if __name__ == "__main__":
main()Workspace(workdir=None, jobs_root=None, max_concurrent_jobs=1, max_results_per_project=5)guarda los modelos abiertos, su historial de deshacer, sus resultados y el gestor de tareas.workdirsirve de base para las rutas relativas; sin él, una ruta relativa produce un error. Conserva los cinco últimos resultados de cada modelo.call(ws, "operation", **kwargs)ejecuta una operación. El modelo se indica conproject_id, que puede omitirse mientras haya un solo modelo abierto.- Las ediciones son atómicas y cada una es un paso de deshacer (
call(ws, "project_history", action="undo")). - Los análisis (
analysis_run,groundwater_run,statistics_run,back_analysis_run,optimize_run,drawdown_sweep_run) se ejecutan como tareas en un proceso hijo, sobre una copia independiente del modelo. La llamada espera hastawait_secondsy, si el análisis no ha terminado, respondestate: "running"con unjob_idque se pasa ajob_get;job_cancelfinaliza el árbol de procesos de la tarea. La respuesta de una ejecución terminada incluyeresult_id,summaryystale(si el modelo ha cambiado desde entonces).ws.shutdown()finaliza las tareas que sigan en ejecución y elimina sus archivos. - Los errores son subclases de
OgrApiErrorcon uncodeestable, unmessage, unhintydetails(Sección 5.5.4). Un nombre de argumento que la operación no admite no es unOgrApiError: Python lanzaTypeError. python_execejecuta un script que dispone deproject,api(cada operación comoapi.<name>(...), conproject_idya rellenado),np,ogr_core,ogr_slip2dyresult(result_id)(un resultado almacenado, completo), todo ello como un único paso de deshacer; devuelveok,stdout,stderr,value(la representación de la última expresión),erroryrolled_back.
La capa de operaciones existe porque los objetos de ajustes del motor aceptan sin dar aviso un ajuste mal escrito y un id de búsqueda desconocido se convierte en una Grid Search; aquí se rechazan ambos, con una sugerencia. Nunca importa Qt ni el SDK de MCP, lo que comprueba un test, de modo que el mismo registro sirve al servidor MCP, al puente para agentes de la ventana y a un script cualquiera.
Código: ogr_api/__init__.py · ogr_api/workspace.py · examples/api_acads.py · examples/quick_slope.py5.3.4La consola integrada#
Window → Terminal (Ctrl+`) abre una consola de Python dentro del programa, conectada al proyecto abierto. Se ejecuta en el propio proceso del programa y actúa directamente sobre el modelo que se ve en pantalla.
| Nombre | Qué es |
|---|---|
project | Project actual; se vuelve a enlazar al crear o abrir un proyecto. |
canvas | Lienzo de dibujo de la ventana principal. |
mainwindow | Ventana principal. |
np | NumPy. |
ogr_core, ogr_slip2d | Paquetes del modelo y del motor de cálculo. |
help_ogr() | Muestra una breve lista de consejos. |
>>> print(len(project.materials), project.bounding_box())
>>> from ogr_slip2d.analysis_runner import run_analysis
>>> outcome = run_analysis(project, ["spencer"])
>>> print(outcome.results["spencer"].critical.fos)- Enter ejecuta la entrada, Shift+Enter empieza una nueva línea, Ctrl+↑ y Ctrl+↓ recorren el historial y Ctrl+L borra la consola.
- El valor de una expresión suelta no se muestra: usa
print(), como en el ejemplo anterior. - La consola se ejecuta en el propio hilo de la ventana, de modo que un cálculo largo iniciado en ella bloquea la ventana hasta que termina.
- Los cambios que se hacen en
projectdesde la consola actúan directamente sobre el modelo y no son pasos de Edit → Undo. Para hacer ediciones que se puedan deshacer desde un script, usa la capa de operaciones o elpython_execde un agente.
La consola ejecuta cada entrada como un bloque de sentencias, por lo que las expresiones no se muestran. Sus consejos (help_ogr()) todavía incluyen expresiones sueltas como r.critical.fos, que tal como están escritas no imprimen nada.