336
Desarrollo de un laboratorio virtual de geotecnia enfocado en el ensayo de compresión triaxial modalidad compresión axial. Jhon Oscar Gerena González Universidad Nacional de Colombia Facultad de Ingeniería, Departamento de ingeniería civil y agrícola Bogotá, Colombia Año 2020

Desarrollo de un laboratorio virtual de geotecnia enfocado

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Desarrollo de un laboratorio virtual de geotecnia enfocado

Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Jhon Oscar Gerena González

Universidad Nacional de Colombia

Facultad de Ingeniería, Departamento de ingeniería civil y agrícola

Bogotá, Colombia

Año 2020

Page 2: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 3: Desarrollo de un laboratorio virtual de geotecnia enfocado

Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Jhon Oscar Gerena González

Trabajo de investigación presentado como requisito parcial para optar al título de:

Magíster en Ingeniería - Geotecnia

Modalidad de profundización

Director:

Guillermo Eduardo Ávila ÁlvarezIngeniero Civil, Especialista en Geotecnia, PhD

Línea de Investigación:

Relaciones constitutivas de suelos, rocas y materiales afines

Modelación y análisis en geotecnia

Universidad Nacional de Colombia

Facultad de Ingeniería, Departamento de ingeniería civil y agrícola

Ciudad, Colombia

Año 2020

Page 4: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 5: Desarrollo de un laboratorio virtual de geotecnia enfocado

(Dedicatoria)

A mis padres.

Page 6: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 7: Desarrollo de un laboratorio virtual de geotecnia enfocado

Agradecimientos

El autor desea expresar su más sincero agradecimiento al Dr. Guillermo Eduardo Ávila A.,

por su disposición, comentarios y sugerencias que permitieron la consecución de este

trabajo

Al Ingeniero Mauricio Tapias, por sus valiosos comentarios que orientaron ampliamente

este trabajo. Al ingeniero Félix Hernández por sus clases y devoción a los métodos

numéricos. Al igual a mis compañeros, a Luisa y Andrés quienes con mucha paciencia

motivaron en gran medida la solución de diversos problemas.

A mi familia por su total apoyo, ayuda y cariño.

Page 8: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 9: Desarrollo de un laboratorio virtual de geotecnia enfocado

Resumen y Abstract IX

Resumen

Los ensayos de laboratorio de geotecnia son fundamentales para la caracterización del

comportamiento mecánico de los suelos, muchos de los modelos constitutivos que se

emplean actualmente se basan en observaciones experimentales, de tal manera que el

laboratorio es, sin duda, una herramienta primordial para la comprensión de diversos

comportamientos mecánicos y permite afianzar procesos de enseñanza y aprendizaje. Tal

vez el ensayo triaxial es el desarrollo que más se ha empleado en los estudios del

comportamiento de los suelos porque brinda gran cantidad de información. Esta práctica,

sin embargo, no es accesible a todos los estudiantes durante tiempos extensos y en

algunos casos esta es una limitante.

Asimismo, los laboratorios virtuales se muestran como un mecanismo útil para fomentar

el aprendizaje en los estudiantes de ingeniería, mientras que se establecen como un

esfuerzo para reducir costos inherentes al manejo de equipos, facilitan la repetición y la

variación en los datos de entrada. El desarrollo de este tipo de herramientas virtuales lleva

implícito la aplicación de modelos de comportamiento que permitan simular la respuesta

del suelo ante unas ciertas condiciones impuestas, bien sea de carga o de deformación.

Este trabajo de grado presenta las bases teóricas y prácticas para el desarrollo de

actividades virtuales de geotecnia basadas en la etapa de falla de la prueba de compresión

triaxial modalidad compresión axial. La modelación usa la aproximación por elementos

finitos, esta sigue la formulación de Galerkin la cual se puede emplear para incluir de

manera adecuada análisis no lineales (Griffiths, 1994), asimismo se usa el criterio de

fluencia de Drucker-Prager. Este proyecto es desarrollado en Python.

Palabras clave: elementos finitos, elastoplasticidad, Python.

Page 10: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 11: Desarrollo de un laboratorio virtual de geotecnia enfocado

Resumen y Abstract XI

Abstract

Laboratory testing is fundamental for characterization of soil mechanical behavior,

numerous constitutive models currently used are based on experimental observations, in

such a way that laboratory practices are undoubtedly a good tool for understanding

mechanical behavior and to strengthen teaching and learning processes. Perhaps triaxial

test is the development that has been most used in studies of the behavior of soils because

it provides good amount of data. However, these practices are not accessible to all students

during the required time, this fact becomes a limitation.

On the other hand, virtual laboratories are an useful instrument to promote learning in

engineering students, since these are established as an effort to reduce costs inherent in

the management of equipment, also allow repetition and variation in input data. The

development of this type of virtual tools implicitly involves the application of behavior

models that simulate the soil response to certain imposed conditions, e.g. load or strains.

This document presents the theoretical and practical bases for developing a geotechnical

virtual laboratory based on the triaxial compression test. This model is a finite element

approach, this follows the Galerkin's formulation which can be used to adequately include

nonlinear analyzes (Griffiths, 1994). Thus, the compression model uses theory of nonlinear

finite element analysis with the elastoplastic considerations of Drucker-Prager yield

criterion. This project uses the Python programming language.

Keywords: Finite element method, elasto-plasticity, Python.

Page 12: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 13: Desarrollo de un laboratorio virtual de geotecnia enfocado

Contenido XIII

Contenido

Pág.

Resumen........................................................................................................................ IX

Lista de figuras.............................................................................................................XV

Lista de tablas ...........................................................................................................XVIII

Lista de Símbolos y abreviaturas.............................................................................XVIII

1. Introducción .............................................................................................................11.1 Propósito .........................................................................................................11.2 Conceptos clave de discusión..........................................................................2

1.2.1 Teoría para el modelo triaxial consolidado drenado ..............................21.2.2 Teoría para el modelo acoplado de consolidación.................................5

1.3 Objetivos..........................................................................................................7

2. Laboratorio virtual....................................................................................................92.1 Aplicabilidad de los laboratorios virtuales en mecánica de suelos .................102.2 Antecedentes de los laboratorios virtuales.....................................................112.3 Herramientas alternas de simulación. ............................................................17

3. Marco teórico..........................................................................................................193.1 Ensayo de compresión triaxial .......................................................................193.2 Ensayo de consolidación unidimensional.......................................................213.3 Plasticidad del suelo ......................................................................................23

3.3.1 Modelos de comportamiento ...............................................................233.3.2 Endurecimiento por deformación.........................................................253.3.3 Ablandamiento por deformación..........................................................263.3.4 Características de un modelo elastoplástico .......................................27

3.4 Método de los elementos finitos.....................................................................343.4.1 Funciones de forma y de interpolación de desplazamientos................363.4.2 Elemento triangular lineal ....................................................................373.4.3 Elemento triangular cuadrático............................................................383.4.4 Puntos de integración..........................................................................403.4.5 Idealización geométrica.......................................................................413.4.6 Matriz de interpolación de desplazamientos........................................423.4.7 Matriz constitutiva 𝑫𝒆𝒑........................................................................433.4.8 Modelación del comportamiento de endurecimiento por deformación .44

3.5 Análisis no lineal por elementos finitos ..........................................................46

Page 14: Desarrollo de un laboratorio virtual de geotecnia enfocado

XIV Desarrollo de un laboratorio virtual de geotecnia mediante el uso de elementos

finitos

3.5.1 Métodos para el análisis no lineal ....................................................... 473.5.2 Algoritmos de integración de esfuerzos. ............................................. 49

4. Metodología y actividades desarrolladas............................................................. 554.1 Desarrollo del modelo triaxial ........................................................................ 55

4.1.1 Discretización ..................................................................................... 554.1.2 Modelo interno.................................................................................... 574.1.3 Interfaz gráfica .................................................................................... 60

4.2 Desarrollo del modelo acoplado de consolidación ......................................... 624.2.1 Consideraciones de Biot ..................................................................... 634.2.2 Anotaciones sobre la estabilidad numérica del modelo acoplado de consolidación. ................................................................................................... 654.2.3 Pasos de análisis................................................................................ 674.2.4 Grado promedio de consolidación....................................................... 70

5. Desarrollo y organización de los códigos computacionales.............................. 715.1 Estructura para el modelo acoplado de consolidación................................... 71

5.1.1 Funcionalidad e interfaz gráfica de la simulación edométrica.............. 785.1.2 Tiempos de ejecución del modelo acoplado de consolidación: ........... 81

5.2 Estructura del modelo de falla en condición drenada .................................... 825.2.1 Funcionalidad e interfaz gráfica de la simulación triaxial..................... 845.2.2 Tiempos de ejecución del modelo no lineal:........................................ 885.2.3 Ejercicios didácticos de operación de la prueba triaxial ...................... 88

6. Calibración y validación de los modelos ............................................................. 956.1 Análisis del modelo triaxial ............................................................................ 95

6.1.1 Descripción del ejemplo de estudio N° 1............................................. 956.1.2 Análisis de sensibilidad para el modelo no lineal en el ensayo triaxial

1006.2 Análisis del modelo acoplado de consolidación........................................... 105

6.2.1 Consideraciones sobre el modelo acoplado de consolidación. ......... 1066.2.2 Relación con el ensayo edométrico .................................................. 110

7. Conclusiones y recomendaciones ..................................................................... 1157.1 Conclusiones............................................................................................... 115Recomendaciones ................................................................................................. 116

A. Anexo: Formulación del modelo acoplado mediante elementos finitos.......... 119

B. Anexo: Anotaciones sobre la implementación del modelo acoplado.............. 127

C. Manual, instalación y ejecución.......................................................................... 131

D. Anexo: código desarrollado................................................................................ 137

Bibliografía .................................................................................................................. 309

Page 15: Desarrollo de un laboratorio virtual de geotecnia enfocado

Contenido XV

Lista de figuras

Pág.

Figura 1-1: Sección de análisis configuración axisimétrica, (a) geometría general, (b)

sección de análisis. .......................................................................................................... 3

Figura 1-2: Sección de la celda de carga para el ensayo edométrico. .............................. 6

Figura 2-1: Interfaz gráfica del módulo de efectos de sitio de SISMILAB........................ 12

Figura 2-2: Panel para ingresar información del suelo y pilote........................................ 13

Figura 2-3: Ejecución de archivo en análisis de OpenSees. ........................................... 14

Figura 2-4: Herramienta la interpretación de resultados en el laboratorio de gravedad

específica. ...................................................................................................................... 14

Figura 2-5: Interfaz de GeoSim en el ensayo de corte directo. ....................................... 15

Figura 3-1: Celda triaxial (con conexión de drenaje)....................................................... 21

Figura 3-2: Edómetros usuales....................................................................................... 22

Figura 3-3: Curva de compresibilidad. ............................................................................ 22

Figura 3-4: Tipos de deformación en procesos de carga y descarga.............................. 24

Figura 3-5: Respuesta de una barra elástica perfectamente plástica cargada de manera

uniaxial. .......................................................................................................................... 25

Figura 3-6: Respuesta de un material elástico con plasticidad que endurece por

deformación. .................................................................................................................. 26

Figura 3-7: Respuesta de un material elástico con plasticidad que ablanda por

deformación. .................................................................................................................. 26

Figura 3-8: Representación de la función de fluencia. .................................................... 28

Figura 3-9: Función de potencial plástico y la dirección del incremento de las

deformaciones plásticas. ................................................................................................ 29

Figura 3-10: Círculos de Mohr para diferentes estados de esfuerzos de confinamiento. 30

Figura 3-11: Representación esquemática del hexágono de Tresca y los círculos de Von

Mises en el plano octaédrico. ......................................................................................... 30

Figura 3-12: Superficies de fluencia de Mohr-Coulomb y Drucker-Prager en el plano

octaédrico....................................................................................................................... 32

Figura 3-13: Ejemplos de las reglas de endurecimiento o ablandamiento ...................... 34

Figura 3-14: Diagrama de flujo del MEF ......................................................................... 37

Figura 3-15: Coordenadas de área para el elemento triangular y las correspondientes

áreas para los nodos 1, 2 y 3. ......................................................................................... 38

Figura 3-16: Funciones de forma cuadráticas para el elemento triangular...................... 39

Figura 3-17: condiciones axisimétricas........................................................................... 42

Figura 3-18: Deformaciones elásticas, plásticas y la definición de 𝐻’. ............................ 46

Page 16: Desarrollo de un laboratorio virtual de geotecnia enfocado

XVI Desarrollo de un laboratorio virtual de geotecnia mediante el uso de elementos

finitos

Figura 3-19: Método de la rigidez tangente (análisis lineal por partes)............................48

Figura 3-20: Representación de 𝛼...................................................................................50

Figura 3-21: Interpretación geométrica del esquema secante de Newton – Raphson. ....50

Figura 3-22: Reconocimiento de las deformaciones elastoplásticas................................51

Figura 3-23: Diagrama de flujo del algoritmo modificado de Euler...................................54

Figura 4-1: Ejemplo de (a) malla estructurada y (b) malla no estructurada......................56

Figura 4-2: Estados iniciales de esfuerzos que implican ambigüedad.............................59

Figura 4-3: Resultados típicos para un ensayo triaxial drenado. .....................................60

Figura 4-4: Interfaz de trabajo de Qtdesigner..................................................................62

Figura 4-5: Barra de menú propuesta para el ensayo triaxial ..........................................62

Figura 4-6: Esquema de continuidad...............................................................................65

Figura 4-7: Carga en forma de rampa. ............................................................................67

Figura 4-8: Ejemplo de distribución de presión de poros para el ensayo edométrico. .....69

Figura 4-9: Disminución de la presión de poros al interior de la muestra.........................70

Figura 5-1: Estructura adoptada para realizar el análisis incremental mediante las

ecuaciones de Biot..........................................................................................................72

Figura 5-2: Módulo encargado de la construcción de las matrices globales de la forma

débil del problema analizado...........................................................................................73

Figura 5-3: Módulos encargados de la construcción de los vectores globales de la forma

débil del problema de consolidación acoplado. ...............................................................75

Figura 5-4: Módulos responsables de incluir las condiciones de frontera. .......................76

Figura 5-5: Módulo que posibilita la estimación de deformaciones y esfuerzos...............77

Figura 5-6: Módulo utilizado para graficar los resultados. ...............................................78

Figura 5-7: Vista principal del programa de consolidación. .............................................79

Figura 5-8: Interfaz para el ingreso de variables de consolidación poro-elástica. ............80

Figura 5-9: Documentación y ayuda de la aplicación de consolidación. ..........................81

Figura 5-10: Estructura adoptada para realizar el análisis incremental mediante para el

ensayo de compresión triaxial. ........................................................................................83

Figura 5-11: Módulo que posibilita la estimación de deformaciones y esfuerzos.............84

Figura 5-12: Vista principal del programa de compresión triaxial. ...................................85

Figura 5-13: Interfaz para el docente para el ingreso de variables de compresión triaxial.

.......................................................................................................................................86

Figura 5-14: Interfaz del estudiante para la manipulación de variables. ..........................87

Figura 5-15: Documentación y ayuda de la aplicación de compresión triaxial. ................87

Figura 5-16: Archivos suministrados para realizar los análisis didácticos........................90

Figura 6-1: Variación del parámetro de plasticidad 𝐻’ para el ejemplo N° 1. ...................96

Figura 6-2: Datos experimentales para el ejemplo N° 1. .................................................96

Figura 6-3: Ejemplo de modelo por elementos finitos para el ejemplo N°1 (cargas)........97

Figura 6-4: Ejemplo de modelo por elementos finitos para el ejemplo N°1

(desplazamientos preestablecidos). ................................................................................97

Figura 6-5: Resultados para el tamaño de búsqueda de 0.02𝑚. .....................................98

Figura 6-6: Resultados para el tamaño de búsqueda de 0.015𝑚.....................................98

Figura 6-7: Resultados para el tamaño de búsqueda de 0.01𝑚. .....................................99

Page 17: Desarrollo de un laboratorio virtual de geotecnia enfocado

Contenido XVII

Figura 6-8: Influencia de 𝑐′ en los resultados de deformación axial. ..............................101

Figura 6-9: Influencia de Փ’ en los resultados de deformación axial. .............................102

Figura 6-10: Influencia de 𝐸′ en los resultados de deformación axial.............................103

Figura 6-11: Influencia de 𝜈 en los resultados de deformación axial..............................103

Figura 6-12: Influencia de 𝜈 en los resultados, estimación para 𝜈 = 0.01. .....................104

Figura 6-13: Influencia de 𝜈 en los resultados estimación para 𝜈 = 0.49. ......................105

Figura 6-14: Geometría y condiciones de frontera del modelo.......................................107

Figura 6-15: Discretización de la geometría para el ejemplo N°2. .................................108

Figura 6-16: Resultados del modelo para el “Grado promedio de consolidación vs factor

tiempo para la consolidación alrededor de un dren ideal”..............................................109

Figura 6-17: Datos para la corroboración del problema de consolidación......................109

Figura 6-18: Discretización, carga y condiciones de frontera para el estudio de la

configuración edométrica. .............................................................................................112

Figura 6-19: Curva de consolidación estimada mediante el modelo acoplado de

consolidación ................................................................................................................113

Figura 6-20: Disminución de la presión de poros en el centro de la muestra. ................113

Page 18: Desarrollo de un laboratorio virtual de geotecnia enfocado

Contenido XVIII

Lista de tablas

Pág.

Tabla 3-1. Puntos de muestreo y coeficientes de peso para elementos triangulares en el

sistema coordenado (𝐿1, 𝐿2). ..........................................................................................40

Tabla 5-1: Tiempo de análisis para el modelo acoplado..................................................81

Tabla 5-2: Tiempos de análisis para el modelo no lineal. ................................................88

Tabla 5-3: Variación de los parámetros de resistencia de la superficie de fluencia. ........88

Tabla 5-4: Tamaño promedio de los elementos finitos para la identificación de la

dependencia de los resultados........................................................................................89

Tabla 5-5: Datos para la variación de los parámetros elásticos del modelo. ...................89

Tabla 6-1: Propiedades índice y parámetros elásticos del ejemplo N°1. .........................95

Tabla 6-2: Resultados en función del número de incrementos de carga para el ejemplo

N°1................................................................................................................................100

Tabla 6-3: Variación de las deformaciones en función del ángulo de fricción para el

ejemplo N°1. .................................................................................................................102

Tabla 6-4: Parámetros para el ejemplo N°2: .................................................................106

Tabla 6-5: Propiedades y parámetros del material de estudio en la configuración

edométrica. ...................................................................................................................111

Lista de Símbolos y abreviaturas

Símbolos con letras latinas

Símbolo Término Unidad SI

𝑐′ Cohesión del suelo 𝑘𝑃𝑎

𝑐 Coeficiente de consolidación 𝑚2/𝑠

𝑑𝐸 Vector de desplazamientos nodales en el elemento 𝑚

Page 19: Desarrollo de un laboratorio virtual de geotecnia enfocado

Contenido XIX

Símbolo Término Unidad SI

𝑑𝑛𝐺 Vector de desplazamientos nodales globales 𝑚𝑑𝑢 Vector de desplazamientos desconocidos 𝑚𝑑𝑝 Vector de desplazamientos prescritos 𝑚

𝑚 Coeficiente de compresibilidad volumétrica 1/𝑘𝑃𝑎𝑝𝑓 Presión de poros 𝑘𝑃𝑎

𝑞 Esfuerzo desviador 𝑘𝑃𝑎𝑞𝑛 Tasa de infiltración 𝑚3/𝑠

𝑢, 𝑣,Componentes de desplazamiento correspondientes a 𝑥, 𝑦 en condiciones planas de deformación y a 𝑟, 𝑧 en condiciones axisimétricas respectivamente

𝑚

𝑥, 𝑦, 𝑧 Coordenadas cartesianas

𝑧, 𝑟, 𝜃 Coordenadas cilíndricas𝐴 Módulo elastoplástico

𝑩 Matriz de interpolación de desplazamientos 1/𝑚𝑫′ Matriz constitutiva para esfuerzos totales 𝑘𝑁/𝑚2

𝑫 Matriz constitutiva para esfuerzos efectivos 𝑘𝑁/𝑚2

𝑫𝒆𝒑 Matriz constitutiva elastoplástica 𝑘𝑁/𝑚2

𝑬′ Módulo de Young drenado 𝑘𝑃𝑎𝑬 Energía potencial total 𝑘𝑁𝑚𝑭 Vector de fuerzas de cuerpo 𝑘𝑁

𝐹({𝝈}, {𝒌}) Función de fluencia 𝑘𝑃𝑎𝐺 Módulo de corte elástico 𝑘𝑃𝑎𝑱 Matriz jacobiana de transformación de coordenadas 𝑚𝑲𝑬 Matriz de rigidez del elemento 𝑘𝑁/𝑚𝑲𝑮 Matriz de rigidez global del sistema 𝑘𝑁/𝑚

𝑲𝒖, 𝑲𝒑

Componentes de la matriz de rigidez global correspondientes a los grados de libertad desconocidos 𝑢 y prescritos 𝑝

𝑘𝑁/𝑚

𝐿 Trabajo realizado por las cargas aplicadas 𝑘𝑁𝑚𝐿𝑖 Coordenadas de área 𝑎𝑑𝑖𝑚

𝐿𝐺Matriz de acoplamiento en la matriz de rigidez generalen consolidación

𝑚2

𝑵 Matriz de funciones de forma o de interpolación 𝑎𝑑𝑖𝑚𝑄({𝝈}, {𝒌}) Función de potencial plástico 𝑘𝑃𝑎

𝑄 Flujo a través de fuentes y sumideros 𝑚3

𝑹𝑬 Vector de fuerzas nodales en el elemento 𝑘𝑁𝑹𝑮 Vector de fuerzas nodales globales 𝑘𝑁

𝑹𝒑Vector de fuerzas global correspondiente a los desplazamientos preestablecidos

𝑘𝑁

𝑹𝒖Vector de fuerzas global correspondiente a los desplazamientos desconocidos

𝑘𝑁

𝑇 − 𝑇𝑣Factor de tiempo ajustado en el análisis de consolidación

𝑎𝑑𝑖𝑚

𝑉𝑜𝑙 Volumen de integración 𝑚3

𝑊 Energía de deformación 𝑘𝑁𝑚

𝑊𝑖Pesos de evaluación para la evaluación de integrales numéricas

𝑎𝑑𝑖𝑚

Page 20: Desarrollo de un laboratorio virtual de geotecnia enfocado

XX Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Símbolos con letras griegas

Símbolo Término Unidad SI

𝛼Parámetro para definir la porción elástica del incremento de esfuerzo en el algoritmo de subpasos

𝑎𝑑𝑖𝑚

𝛽 Parámetro para la solución iterativa del modelo de consolidación

𝑎𝑑𝑖𝑚

𝛾 Peso unitario 𝑘𝑁/𝑚3

𝛾𝑓 Peso unitario del fluido de poros 𝑘𝑁/𝑚3

𝜺 Vector de deformaciones

휀𝑥 , 휀𝑦, 휀𝑧Componentes del tensor de deformaciones en coordenadas cartesianas

휀𝑟, 휀𝑧, 휀𝜃Componentes del tensor de deformaciones en coordenadas cilíndricas

휀𝑠Porción elastoplástica del incremento de deformación en el algoritmo de subpasos

휀𝑠𝑠Deformación en el subpaso en el algoritmo de subpasos

𝜆 Multiplicador escalar de las deformaciones plásticas𝝈 Vector de esfuerzo total 𝑘𝑃𝑎𝝈′ Vector de esfuerzos efectivos 𝑘𝑃𝑎𝝈𝒇 Vector de presión de poros 𝑘𝑃𝑎

𝜎𝑥 , 𝜎𝑦, 𝜎𝑧Componentes del tensor de esfuerzos en coordenadas cartesianas

𝑘𝑃𝑎

𝜎𝑟, 𝜎𝑧, 𝜎𝜃Componentes del tensor de esfuerzos en coordenadas cilíndricas

𝑘𝑃𝑎

𝜑′ Ángulo de resistencia °

Φ𝐺Submatriz de permeabilidad en la matriz de rigidez general en consolidación

𝑚5/𝑘𝑁𝑠

Abreviaturas

Abreviatura Término

FEM-MEF Método de los elementos finitos

SSTOLTolerancia en el subpaso en el algoritmo de integración de esfuerzos de los subpasos

YTOL Tolerancia para la función de fluencia

Page 21: Desarrollo de un laboratorio virtual de geotecnia enfocado

1. Introducción

1.1 Propósito

El crecimiento de la producción de conocimiento y desarrollo de nuevas tecnologías es

cada vez mayor en diversas áreas, la ingeniería, por supuesto no es ajena a este hecho y

está abocada a adoptar estos avances para mejorar sus técnicas en la solución de diversos

problemas. En ingeniería geotécnica el aprendizaje experimental juega un papel

importante en la formación de nociones críticas sobre el comportamiento mecánico de los

materiales térreos. Por una parte, en los primeros cursos de geotecnia, las bases teóricas

están determinadas por las proposiciones del medio continuo y el uso de parámetros

elásticos, a la vez que, algunas pruebas de laboratorio son ejecutadas con la finalidad de

identificar los mecanismos que rigen el comportamiento del suelo.

Los laboratorios virtuales resultan ser una herramienta innovadora para la enseñanza de

la ingeniería y consisten en aplicaciones computarizadas capaces de simular el

comportamiento físico de configuraciones experimentales (Ramírez & Rivera, 2017). El

desarrollo de este tipo de software, además de facilitar los procesos de aprendizaje,

constituyen una manera efectiva de reducir los costos que implica la operación y

mantenimiento de equipos y una estrategia complementaria ante la problemática de

espacio y tiempo de los laboratorios tradicionales. En el caso de la ingeniería geotécnica,

el laboratorio virtual del ensayo triaxial tiene un alto potencial para modelar diferentes

trayectorias de esfuerzos proporcionando resultados en tiempo real, que además pueden

ser repetidos o ajustados para analizar ciertos tipos especiales de comportamiento.

Por su parte, en el contexto de la ingeniería geotécnica el método de los elementos finitos

tiene gran aceptación en la solución de problemas estáticos y dinámicos (Zeevaert, 1980),

y es una de las estrategias más populares para la determinación de soluciones precisas

de ecuaciones diferenciales parciales (Cardoso, 2016).

Page 22: Desarrollo de un laboratorio virtual de geotecnia enfocado

2 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

En este documento se realiza la descripción de la implementación del método de los

elementos finitos en un código computacional libre que permite modelar la etapa de falla

del ensayo de compresión triaxial drenado. De manera adicional a los objetivos del

proyecto, en el contexto de los laboratorios virtuales se describe la codificación por

elementos finitos de un modelo acoplado de consolidación, esto último encaminado a

realizar una aproximación a la modelación del ensayo edométrico. Es importante destacar

que los dos análisis son independientes y que, aunque no se relacionan de manera directa

entre ellos, el modelo de consolidación unidimensional sirve de base conceptual para la

comprensión de ciertos comportamientos esfuerzo-deformación-tiempo, que también se

dan en la fase de consolidación axisimétrica en el ensayo triaxial. A continuación, se

describe brevemente el marco de referencia de desarrollo de los modelos tratados.

1.2 Conceptos clave de discusión

En este numeral se describen las particularidades inherentes a los tipos de ensayos

triaxiales, se identifican las características geométricas y operativas del ensayo simulado

y se resume la teoría usada en el proceso de simulación.

1.2.1 Teoría para el modelo triaxial consolidado drenado

Existen diferentes tipos de ensayo triaxial entre ellos el no consolidado no drenado (UU)

que busca determinar la respuesta ante un proceso de carga rápida, en este ensayo no se

permite desarrollar consolidación y se encuentra una respuesta constante de resistencia

al corte no drenada Su independiente del esfuerzo de confinamiento de la muestra.

Otros tipos de ensayos que permiten la estimación de los parámetros de resistencia a largo

plazo, es decir, en términos de esfuerzos efectivos, son los ensayos consolidado no

drenado (CU) y consolidado drenado (CD). En el ensayo consolidado no drenado (CU) se

permite la consolidación inicial de la muestra y seguido a ello se lleva a la falla sin dejar

que se disipen los excesos de presión de poros; estos últimos se producen por los

procesos de dilatancia o tendencia al cambio de volumen de la muestra ante esfuerzos de

corte. La ventaja en este tipo de ensayos es que mediante transductores de presión de

poros se puede medir esta variación en todo momento y, por lo tanto, se pueden conocer

los esfuerzos efectivos.

Page 23: Desarrollo de un laboratorio virtual de geotecnia enfocado

Introducción 3

Por su parte, en el ensayo consolidado drenado (CD) se permite tanto la consolidación

inicial de la muestra como el drenaje en la etapa de falla, esto se logra al aplicar

desplazamientos de manera lenta si se trata de un ensayo a deformación controlada, o

mediante pequeños incrementos de carga en el caso de los ensayos a esfuerzo controlado.

De esta manera se permite la disipación de los excesos de presión de poros y los esfuerzos

efectivos coinciden con los esfuerzos totales.

El modelo que se plantea en este trabajo corresponde a la etapa de falla de un ensayo

triaxial consolidado drenado (CD) en modalidad de esfuerzo controlado, en este se

determinan los cambios de volumen. Se seleccionó este tipo de análisis por ser el más

simple para la modelación numérica ya que una vez resueltas las ecuaciones de

interacción esfuerzo-deformación; que constituyen la parte central de este proyecto, en

otras investigaciones se podrá ampliar el código a otras modalidades de ensayos que

involucren los cambios de presión de poros.

Las condiciones de contorno del problema consisten en la configuración axisimétrica

propia de la geometría del ensayo triaxial y su consiguiente representación bidimensional

en donde se analiza sólo una sección de la geometría (Figura 1-1). A partir de este análisis

se busca la reproducción de las curvas esfuerzo deformación, deformación volumétrica y

deformación cortante para la etapa.

Figura 1-1: Sección de análisis configuración axisimétrica, (a) geometría general, (b) sección de análisis.

Nombre de la fuente: elaboración propia.

Siendo esta práctica un ejercicio bajo el cual se establecen los parámetros que describen

el módulo de Young drenado y la relación de Poisson drenada, entre otros, para la

simulación de algunas respuestas de este ensayo se hace uso de los siguientes conceptos:

Page 24: Desarrollo de un laboratorio virtual de geotecnia enfocado

4 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

1) Teoría de los elementos finitos correspondiente a elementos triangulares

cuadráticos de seis nodos para el escenario de compresión triaxial, estos permiten

estimar esfuerzos variables al interior de los elementos y modelar fronteras curvas.

2) Comportamiento no lineal esfuerzo deformación elastoplástico del material.

3) Carga incremental para el modelo de compresión, es decir, el ensayo es realizado

en condiciones de esfuerzo controlado.

4) Función de fluencia. Esta función es una hipótesis que define el límite del

comportamiento elástico en un material y el inicio de deformaciones plásticas bajo

una combinación posible de esfuerzos.

5) Condiciones de falla en el modelo de compresión.

a. Las características elastoplásticas del material son modeladas mediante el

criterio de fluencia de Drucker y Prager. No se incluyen efectos debidos a la

viscosidad, a la consolidación y presiones de poros. Tampoco se manejan

respuestas debidas a fuerzas de inercia, ablandamiento por deformación y

tasa de carga. La formulación plástica se limita a pequeñas deformaciones.

b. Verificación de la condición de fluencia del material mediante algoritmos de

integración de esfuerzos, la finalidad de estos procedimientos es la

obtención del tensor de esfuerzos correspondiente a las deformaciones de

un incremento de carga.

6) En el ensayo de compresión triaxial consolidado drenado (CD) no se tienen en

cuenta incrementos en la presión de poros. El criterio de falla que se emplea es el

de Drucker y Prager que representa materiales perfectamente plásticos; sin

embargo, mediante cierto tratamiento matemático se le puede permitir que se

acerque al comportamiento de materiales que endurecen por deformación, esto

último se detalla en el título 3.3 sobre plasticidad. El uso de este criterio requiere la

descripción mecánica del material mediante las siguientes variables:

1) Ángulo de fricción interna del material Φ′.

2) Intercepto de cohesión 𝑐′.

3) Módulo de Young drenado 𝐸.

4) Relación de Poisson 𝜈.

Como ya se ha mencionado, este tipo de modelación se puede enmarcar en la etapa de

falla de un ensayo drenado, entretanto, la función de fluencia elegida corresponde al

criterio de plastificación de Drucker y Prager, sus ventajas son su simplicidad, su forma

Page 25: Desarrollo de un laboratorio virtual de geotecnia enfocado

Introducción 5

circular y con la excepción de algunos criterios modificados, la simetría de su superficie de

fluencia que facilita su implementación en códigos numéricos (Cividini, 1993). Así mismo,

estima que la influencia del esfuerzo principal intermedio (𝜎′2) tiene el mismo peso que los

otros dos esfuerzos principales (𝜎′1) y (𝜎′3).

La etapa de consolidación axisimétrica no se modela en la presente investigación, esto

requiere el análisis de un modelo acoplado que incluya la evolución de la disipación de

presión de poros a medida que el suelo se deforma volumétricamente. No obstante, y como

una aproximación a esa modelación, se adelantó la evaluación de consolidación

unidimensional de forma acoplada, como se describe la sección 1.2.2.

1.2.2 Teoría para el modelo acoplado de consolidación

La consolidación es la reducción gradual de volumen de un suelo parcial o completamente

saturado bajo carga y se debe principalmente a la expulsión de agua de los vacíos, en

otras palabras, se generan deformaciones a medida que ocurre flujo en función del tiempo,

esta relación se fundamenta en que la variación de los esfuerzos efectivos se debe tanto

a los cambios en las presiones intersticiales y en los esfuerzos totales.

Este comportamiento se conoce como consolidación primaria y se puede explicar mediante

el tradicional ensayo edométrico, en este procedimiento se emplaza una muestra de suelo

dentro de un anillo rígido de metal. Tal es el caso de la Figura 1-2 en donde inicialmente

se evita todo tipo de drenaje, permitiendo que la totalidad de la carga sea tomada por el

agua de los intersticios, es decir, no hay aumento en los esfuerzos efectivos. Por otra parte,

una vez se permite el drenaje se evidencia una disminución en el volumen y un aumento

de esfuerzos efectivos diferidos en el tiempo.

Algunos análisis que buscan tratar este problema se realizan teniendo en cuenta sólo la

disipación de presión de poros, este es el caso de la ecuación de consolidación

unidimensional de Terzaghi. En contraste a aquella teoría, es factible tratar al esqueleto

de suelo como un medio poroso elástico con acoplamiento al fluido laminar de poros

mediante condiciones de equilibrio y continuidad (Smith et al., 2014). En este último

acercamiento se puede asumir un comportamiento esfuerzo–deformación lineal elástico,

con una formulación acoplada de las ecuaciones de Biot (1941), es decir, que existen

grados de libertad para desplazamientos y presiones poros (Smith & Hobbs, 1976).

Page 26: Desarrollo de un laboratorio virtual de geotecnia enfocado

6 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Debido a su construcción esta formulación puede manejar problemas que implican

condiciones axisimétricas y planas de deformación, por lo que se pueden simular las

condiciones geométricas del ensayo edométrico.

El desarrollo de la modelación numérica del ensayo edométrico tiene en cuenta los

siguientes aspectos conceptuales:

1. Elementos triangulares lineales de tres nodos para el modelo de consolidación.,

Estos facilitan la implementación del modelo acoplado.

2. Anisotropía en la permeabilidad.

3. La totalidad de la carga se aplica en el primer paso de análisis, es decir, el ensayo

es realizado en condiciones de esfuerzo controlado.

4. Comportamiento lineal elástico. Esto repercute en las limitaciones del ensayo de

consolidación aquí implementado, dado que el modelo usado no incluye historia de

esfuerzos a la vez que trabaja con materiales poroelásticos y no maneja criterio de

falla ya que las condiciones de esfuerzos siempre se mantienen por debajo de las

condiciones de falla en la etapa de consolidación. Las variables de entrada de este

modelo son:

a. Módulo de Young drenado 𝐸.

b. Relación de Poisson 𝜈.

c. Permeabilidad horizontal 𝑘ℎ y vertical de la muestra 𝑘𝑣.

Figura 1-2: Sección de la celda de carga para el ensayo edométrico.

Nombre de la fuente: Adaptado Duque, G. & Escobar C. (2016)

Page 27: Desarrollo de un laboratorio virtual de geotecnia enfocado

Introducción 7

1.3 Objetivos

General

- Desarrollar un modelo de laboratorio virtual con la capacidad de simular la prueba

de compresión triaxial modalidad compresión axial, en condición no lineal elástica

y condición elasto-plástica.

Específicos

- Desarrollar ejercicios didácticos de operación de la prueba de compresión triaxial

modalidad compresión axial.

- Desarrollar algoritmos y ejercicios didácticos de interpretación de resultados.

Page 28: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 29: Desarrollo de un laboratorio virtual de geotecnia enfocado

2. Laboratorio virtual

En términos generales un laboratorio virtual es una actividad informática donde los

estudiantes pueden interactuar con muestras, aparatos y datos empíricos mediante una

interfaz computacional. En ellos se permite la libre experimentación con distintas variables

a requerimientos computacionales que pueden ser de bajo costo. Este concepto tiene

opiniones a favor y en contra en el ámbito educacional, y aunque se busque brindar un

acercamiento a diversos tipos de ensayos, esta aproximación no debe reemplazar del todo

a las experiencias físicas de laboratorio, sino que pueden incluirse como actividades de

refuerzo (Hatherly, 2016).

A pesar de la importancia del desarrollo de ensayos de laboratorio para y por los

estudiantes de ingeniería; debido a limitaciones de tiempo, espacio y por supuesto, de

recursos económicos (Budhu, 2001), la mayoría de los ensayos acerca de un fenómeno

físico, en el mejor de los casos llega a realizarse en tan solo una ocasión. La

implementación de laboratorios virtuales hace posible que los estudiantes adquieran

sensibilidad ante el cambio de una u otra cantidad física en determinados procesos físicos

(Sutterer, 2010).

Por su parte, los ambientes virtuales de aprendizaje (AVA) se definen como un grupo de

entornos que facilitan la interacción enfocada en la enseñanza y el aprendizaje, estos

ambientes se encuentran dirigidos por las disposiciones de un programa curricular y,

algunas de sus partes esenciales son los contenidos, las actividades de aprendizaje y los

elementos de contextualización.

Por otro lado, los objetos virtuales de aprendizaje (OVA) son entidades digitales enfocadas

en un objetivo educativo específico, en general. Estos elementos pueden ser de diferentes

tipos, por ejemplo, un texto, un video o herramientas de mayor complejidad como un

software auxiliar. En este sentido, los ambientes virtuales de aprendizaje (AVA) son

complementados con los objetos virtuales de aprendizaje (OVA) (Granados, 2018). De esta

Page 30: Desarrollo de un laboratorio virtual de geotecnia enfocado

10 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

manera, el software producto de este trabajo de grado se enmarca en el concepto OVA y

es susceptible de ser usado como parte de un ambiente virtual de aprendizaje del curso

de mecánica de suelos.

2.1 Aplicabilidad de los laboratorios virtuales en mecánica de suelos

En mecánica de suelos la prueba edométrica tiene la posibilidad de resultar la menos

gratificante debido a las limitaciones en términos de tiempo, sin embargo, es de suma

importancia en las obras civiles. Este procedimiento se usa para determinar el coeficiente

de consolidación y los parámetros de compresibilidad. En general se basa en incrementos

de carga aplicados sobre una muestra saturada, a la vez que se realiza una medición de

las deformaciones verticales en momentos específicos durante cada incremento; en las

prácticas de laboratorio el tiempo disponible tiende a ser reducido (Masala & Biggar, 2005).

Por su parte, el estudio de la resistencia al corte es fundamental en geotecnia, su influencia

comprende la estabilidad de taludes, la capacidad portante de las cimentaciones, el diseño

de muros de contención y de manera implícita, el diseño de pavimentos. Este valor puede

ser estimado con ensayos de campo que buscan eliminar la alteración de la muestra

debida a la extracción de material del subsuelo, no obstante, en ellos se recurren a

correlaciones que muchas veces limitan su validez y rango de aplicación. Por otro lado, los

procedimientos de laboratorio que atañen a la medición de la resistencia al corte cubren

las especificaciones de los ensayos de carga uniaxial, corte directo y compresión triaxial.

Así pues, algunas de los aspectos que limitan al ensayo triaxial son (Bishop & Henkel,

1957):

1) La influencia del esfuerzo intermedio principal.

2) El cambio en las direcciones de los esfuerzos principales.

3) La influencia en los extremos del aparato muestreador.

4) La duración del ensayo.

En otro sentido se tienen los desafíos teóricos y numéricos que se plantean en el campo

de la ingeniería geotécnica y la mecánica de suelos, así pues, pueden reconocerse dos

campos de acción en el desarrollo de laboratorios virtuales, estos son el reconocimiento

Page 31: Desarrollo de un laboratorio virtual de geotecnia enfocado

Laboratorio virtual 11

de los ensayos y el desarrollo teórico y las limitaciones que rigen los resultados, de esta

manera ambos aspectos pueden considerarse complementarios.

En este punto se destaca que este trabajo de grado se enfoca en la implementación de

algunas de las características teóricas que rigen el comportamiento esfuerzo deformación

de los suelos, se dejan de lado las cuestiones que atañen al reconocimiento interactivo de

equipos y se centra la atención en los resultados que provee el ensayo modelado, así pues,

el apartado de los equipos y su reconocimiento queda supeditado a futuros desarrollos que

hagan un uso más profundo de técnicas avanzadas de programación, entre ellas, la

visualización e interacción dinámica de los usuarios con diversos objetos virtuales.

2.2 Antecedentes de los laboratorios virtuales

En las últimas décadas debido al desarrollo y crecimiento de las Tecnologías de la

Información y la Comunicación (TIC), se han implementado laboratorios virtuales en

diferentes áreas de conocimiento enfocados en mejorar el aprendizaje de los estudiantes.

En cuanto a ingeniería civil, se destacan ejemplos como: GeoSim, un simulador basado en

redes neuronales propuesto en Estados Unidos (Penumadu et al, 2000), SIMSOLS 3D, un

software canadiense enfocado en evaluar la inestabilidad interna en suelos no cohesivos

(Roubtsova et al, 2012), algunos módulos con accesibilidad en línea desarrollados por el

MIT (Instituto tecnológico de Massachusetts), los cuales permiten el aprendizaje en las

áreas de mecánica de sólidos y diseño estructural, un Laboratorio virtual de dinámica

Estructural (VSDL) desarrollado por el Instituto Internacional de Tecnología de la

Información (International Institute of Information Technology), que presenta ejercicios

experimentales que buscan mejorar la compresión de la respuesta estructural ante sismos

(Kumar & Munipala, 2012), y diferentes módulos descargables de topografía desarrollados

por el laboratorio de ingeniería de civil del Instituto Indio de Tecnología (IIT Roorkee).

En Colombia, la Universidad del Valle ha formulado un laboratorio con énfasis en la

ingeniería sísmica y dinámica estructural, SISMILAB, este contiene tres módulos uno de

ellos de Geotecnia conformado por dos aplicaciones realizadas en MATLAB (Figura 2-1)

(Guerrero et al, 2014), mientras que, en el área de pavimentos, la Universidad Militar Nueva

Granada, elaboró un programa dinámico en Flash Action 3.0 para el diseño Marshall, con

el objetivo de reforzar la educación a distancia.

Page 32: Desarrollo de un laboratorio virtual de geotecnia enfocado

12 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Un ejemplo de laboratorio virtual en geotecnia es VLEG, encaminado a dar solución

problemas comunes que se presentan en el ámbito de la construcción y el diseño, entre

estos problemas se abordan las cuestiones inherentes al diseño sísmico de pilotes, diseño

de zapatas, la determinación de asentamientos, el cálculo de la capacidad lateral y la

estimación de la carga de hundimiento en pilotes (Valarezo, 2010). La interfaz provista por

esta aplicación ofrece esquemas y elementos de entrada de información que pueden

verificarse en la Figura 2-2:

Figura 2-1: Interfaz gráfica del módulo de efectos de sitio de SISMILAB.

Nombre de la fuente: Guerrero et al., 2014.

Page 33: Desarrollo de un laboratorio virtual de geotecnia enfocado

Laboratorio virtual 13

Figura 2-2: Panel para ingresar información del suelo y pilote.

Nombre de la fuente: Valarezo, M., (2010).

VLEG hace uso de OpenSees, un software que permite la simulación de la respuesta

sísmica de sistemas estructurales y geotécnicos, su objetivo es suplir las necesidades de

investigación de la respuesta sísmica en el Centro de Investigación en Ingeniería Sísmica

del Pacífico PEER en colaboración con la Universidad de Berkeley. OpenSees no tiene

interfaz gráfica, sino que los proyectos son manejados forma directa en código, en la Figura

2-3 se muestra la ejecución inicial de un análisis sísmico en OpenSees.

Otro ejemplo de laboratorio virtual en geotecnia, esta vez por parte de la Universidad

Politécnica de Valencia, consiste en una implementación para estudiar las relaciones de

fase de los suelos con énfasis en la comprensión de la gravedad específica del suelo. Así

pues, las características provistas por este laboratorio se muestran en la Figura 2-4, en

ella se relacionan el contenido de aire, la humedad y la gravedad específica, al igual que

contiene objetos virtuales para el ingreso de variables.

Page 34: Desarrollo de un laboratorio virtual de geotecnia enfocado

14 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 2-3: Ejecución de archivo en análisis de OpenSees.

Nombre de la fuente: Mckenna et al., (2008).

Figura 2-4: Herramienta la interpretación de resultados en el laboratorio de gravedad específica.

Nombre de la fuente: Universidad Politécnica de Valencia (s. f).

Page 35: Desarrollo de un laboratorio virtual de geotecnia enfocado

Laboratorio virtual 15

En cuanto al ensayo de corte directo, GeoSim trabaja las especificaciones para su

realización, en este software los resultados están basados en análisis a partir de redes

neuronales. En la Figura 2-5 se muestra el reconocimiento de equipos, este acercamiento

se hace por medio de un diagrama sencillo que no incluye cuestiones que atañen a la

interactividad con el aparato de ensayo.

A partir de estos ejemplos se verifica que, si bien las herramientas tienen características

que familiarizan al usuario con los procesos y pueden dar resultados susceptibles de

interpretación, lo correspondiente a la interacción con los aparatos es relegado a un nivel

de menor importancia, esto también puede explicarse dado que la implementación de estas

características requiere el uso de herramientas avanzadas de programación orientada a

objetos.

Figura 2-5: Interfaz de GeoSim en el ensayo de corte directo.

Nombre de la fuente: Penumadu et al., (2000).

Page 36: Desarrollo de un laboratorio virtual de geotecnia enfocado

16 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

En síntesis, las diferentes aplicaciones enfocadas en la resolución de laboratorios virtuales

con énfasis en geotecnia han sido desarrolladas para simular los ensayos de compresión

triaxial, de permeabilidad (Mašala & Biggar, 2003), de consolidación unidimensional y el

ensayo edométrico (Biggar & Mašala, 2006); aunque suelen ser herramientas útiles, en la

mayoría de los casos son de uso exclusivo de las entidades que las implementaron. En

términos generales, el tipo de pruebas experimentadas por los estudiantes deben incluir

conceptos de contenido de agua, gravedad específica, distribución de tamaño de grano,

humedad y relaciones de fase, permeabilidad, corte directo, compresión inconfinada y

consolidación unidimensional (Sutterer, 2010).

Sin duda alguna, las prácticas de laboratorio facilitan la comprensión o demostración de

leyes y principios que explican procesos reales. No obstante, debido al creciente número

de estudiantes y a las limitaciones de espacio y tiempo en los laboratorios, se hace

necesario el desarrollo e implementación de nuevas herramientas de enseñanza y

aprendizaje, que sirvan de complemento para las prácticas tradicionales (Budhu, 2001).

Además de un correcto desarrollo del modelo y de la generación de una interfaz para los

usuarios, la creación de un software debe estar acompañada de una serie de pruebas de

validación que garanticen el correcto funcionamiento del programa. Lo anterior, puede

lograrse comparando resultados experimentales con los simulados de manera virtual. Para

esto, algunas alternativas pueden usar redes neuronales artificiales, que con una base de

datos robusta y un entrenamiento adecuado, pueden ser capaces de predecir parámetros

como los coeficientes de consolidación y permeabilidad, constituyendo así un método de

validación viable, de acuerdo con estudios realizados en otras ramas de la ingeniería civil

(Casanova & Atilus, 2013).

De igual manera, los laboratorios virtuales deben estar enfocados en promover la

responsabilidad y autonomía de los estudiantes, en fomentar la participación expresa de

todos los miembros de un grupo sin limitarse a seguir unos pasos a modo de receta, como

suele ocurrir en laboratorios tradicionales; sino que debe ser planteado como una

herramienta para motivar el análisis y la puesta en práctica de los conocimientos teóricos

previamente adquiridos. De igual manera, pueden ser un acercamiento a la comprensión

de las diferentes limitaciones que pueden tener los programas de análisis. Asimismo, en

condiciones especiales bajo las cuales se dificulte el acceso a los equipos o a los

Page 37: Desarrollo de un laboratorio virtual de geotecnia enfocado

Laboratorio virtual 17

laboratorios, este tipo de herramientas cobran mayor validez y permiten un acercamiento

al proceso de experimentación.

2.3 Herramientas alternas de simulación.

Otra forma indirecta de modelación de un ensayo la constituyen el uso de programas

comerciales de modelación numérica en geotecnia, un primer ejemplo es Plaxis® en donde

es posible comparar los esfuerzos y deformaciones en pruebas de compresión triaxial y

ensayos de corte directo (Medzvieckas, Dirgėlienė & Skuodis, 2017), el módulo GTS-NX

2016 de Midas® que tiene la capacidad de simular las características de los ensayos

triaxial, edométrico y de corte directo (Simulsoft, 2018) y en abaqus en donde es posible

estudiar el comportamiento en un ensayo triaxial no drenado de materiales con diferentes

índices de plasticidad (Ho & Hsieh, 2013).

Aunque se demarque la posibilidad de ejecutar los modelos aquí analizados en programas

de uso comercial, se busca generar una aplicación computacional de acceso libre que a

su vez permita el estudio de los elementos finitos mediante la lectura del código, esto último

debido a que los distintos archivos se encuentran documentados para ser legibles.

Por otro lado, es posible ejecutar análisis elastoplásticos en condiciones axisimétricas con

otro tipo de herramientas que combinen diferentes técnicas, tal es el ejemplo de la unión

del método de los elementos discretos con el de los elementos finitos sentando así las

bases de un procedimiento alterno al descrito en este documento (Medzvieckas et al.,

2017).

Page 38: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 39: Desarrollo de un laboratorio virtual de geotecnia enfocado

3. Marco teórico

En este capítulo se delinean las características de los ensayos triaxial y de consolidación

unidimensional, esta descripción se da para generar el marco de referencia del problema

tratado en términos de la geometría y del comportamiento mecánico. Para abordar la

simulación se tratan temas referentes a las bases de los modelos constitutivos, su

implementación en el método de los elementos finitos, a la vez que se estudia el análisis

no lineal por elementos finitos adaptando el criterio de fluencia de Drucker-Prager para

materiales que endurecen por deformación, por último, se trata el control de errores

mediante la inclusión de un algoritmo de integración de esfuerzos.

3.1 Ensayo de compresión triaxial

Los parámetros mecánicos que definen la resistencia al corte son susceptibles de ser

determinados tanto de pruebas de compresión triaxial no drenadas (𝐶𝑈) que incluyan la

medición de presiones intersticiales, como de pruebas triaxiales drenadas ensayos (𝐶𝐷).

Asimismo, existe otra modalidad de ensayo en donde a la muestra de suelo no se le

permite desarrollar el proceso de consolidación ni drenaje en absoluto, estas son

conocidas como no consolidadas no drenadas (𝑈𝑈) y permiten obtener parámetros de

resistencia no drenada o respuesta a cargas con tiempo rápido de aplicación (Germaine &

Ladd, 1988).

En el tipo de prueba que se hace de manera rápida al no permitírsele a la muestra

desarrollar consolidación ni drenaje (𝑈𝑈) se desconocen los esfuerzos efectivos. En

particular este ensayo trabaja en el marco de referencia de materiales cohesivos saturados

para los cuales la resistencia al corte es constante e independiente del esfuerzo de

confinamiento, esto se puede explicar debido a que no se permite cambio de volumen

alguno.

Page 40: Desarrollo de un laboratorio virtual de geotecnia enfocado

20 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

En los ensayos consolidados no drenados (𝐶𝑈) en primera instancia el espécimen de suelo

también es sometido a consolidación bajo condición de presión hidrostática, y

seguidamente el suelo es llevado a la falla mediante un incremento de carga en la dirección

axial (Valerio, 2011). En el caso de las arenas sueltas si se permite el drenaje habría una

disminución en el volumen; dado que en este tipo de ensayo no lo acepta, la presión de

poros tiende a aumentar, por otra parte, para arenas densas en las etapas iniciales de

carga tiende a haber un aumento en el volumen; sin embargo, al restringirse todo tipo de

drenaje se desarrollan presiones de poros negativas. Entretanto, al realizarse este tipo de

ensayo en materiales arcillosos, la magnitud de la presión de poros generada depende en

gran medida del grado de sobreconsolidación (Henkel, 1956).

Finalmente, para los ensayos consolidados drenados (𝐶𝐷) el funcionamiento se basa en

que los esfuerzos a los que se somete la muestra son efectivos. En primera instancia se

le aplica al suelo un esfuerzo hidrostático y se deja que este actúe buscando que se

desarrolle el proceso de consolidación, es decir, que se alcance equilibrio estático en

donde las fuerzas exteriores se encuentren aplicadas en la fase sólida. Seguidamente la

muestra es conducida a la falla aplicando la carga de manera axial en pequeños

incrementos, cada uno de estos aumentos se mantiene constante durante el tiempo

necesario para que el exceso de presión de poros sea despreciable (Valerio, 2011). El

arreglo en laboratorio de este tipo de ensayo se encuentra en la Figura 3-1. En general

para este ensayo se establecen el esfuerzo desviador (𝑞) y el esfuerzo promedio (𝑝) como:

𝑞 = 𝜎′1 − 𝜎′3 = 𝜎′𝑎 − 𝜎′𝑐 (3.1)

𝑝 =𝜎′1 + 2𝜎′3

3=𝜎′𝑎 + 2𝜎′𝐶

3(3.2)

En donde 𝜎𝑎 y 𝜎𝑐 son los esfuerzos en la dirección axial y de cámara y toman el papel del

esfuerzo principal mayor (𝜎1) y del esfuerzo principal menor (𝜎3), respectivamente.

Hace parte del análisis principal propuesto la simulación de la etapa de falla de la muestra,

por otra parte, para sentar las bases de un futuro análisis de la etapa de consolidación se

opta por estudiar el contexto de un modelo bidimensional axisimétrico susceptible de ser

aplicado en la simulación del ensayo edométrico, así pues, en el numeral 3.2 se abordan

algunas cuestiones propias a este ensayo.

Page 41: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 21

Figura 3-1: Celda triaxial (con conexión de drenaje)

Nombre de la fuente: Harkness et al., (2016).

3.2 Ensayo de consolidación unidimensional

También conocido como ensayo de compresibilidad edométrica posibilita la representación

de manera controlada del proceso de consolidación, también permite obtener los

parámetros de compresibilidad y da un estimativo del tiempo necesario en el que se disipa

la presión de poros.

Este ensayo consiste en el emplazamiento de una muestra de suelo blando en un anillo

rígido entre dos estratos permeables, sobre el material poroso superior se coloca una placa

rígida de acuerdo con las configuraciones de la Figura 3-2 y se sumerge emulando

condiciones de saturación. En este arreglo el suelo es comprimido bajo ciertos incrementos

de carga para los cuales se busca que el proceso de consolidación se complete (Duque &

Escobar, 2016). Así pues, el exceso de presión intersticial se disipa a una velocidad

controlada por la permeabilidad del suelo (𝑘) por lo que el esfuerzo efectivo va

incrementándose a medida que el agua fluye.

El ensayo completo permite obtener la curva de compresibilidad, para ello se somete a la

muestra a diferentes cargas sucesivas, esta curva permite identificar el esfuerzo de

preconsolidación de la muestra de suelo (𝜎𝑝) (Figura 3-3). Este concepto se basa en que

cuando una muestra tomada en campo a una profundidad determinada se carga de nuevo,

en los primeros incrementos de carga se deforma en menor cuantía, hasta que llega al

Page 42: Desarrollo de un laboratorio virtual de geotecnia enfocado

22 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

máximo esfuerzo al que estuvo sometida en su historia geológica; a partir de este punto

las deformaciones crecen en mayor medida. Este comportamiento, tanto a etapas

tempranas de carga donde las deformaciones se mantienen pequeñas, como en descarga

donde se observa la recuperación de cierta magnitud en las deformaciones, es posible de

verse en la Figura 3-3.

Figura 3-2: Edómetros usuales

Nombre de la fuente: Duque, G. & Escobar C. (2016) Geomecánica.

Figura 3-3: Curva de compresibilidad.

Nombre de la fuente: Elaboración propia.

Page 43: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 23

3.3 Plasticidad del suelo

En mecánica de suelos la teoría de elasticidad ha sido un modelo constitutivo ampliamente

usado para el estudio de problemas geotécnicos. Algunas imprecisiones pueden generarse

al asumir la teoría elástica en materiales que suelen mostrar comportamiento mecánico no

lineal. Además de no seguir la ley de Hooke, el suelo suele mostrar zonas en flujo plástico

incluso a niveles bajos de esfuerzos. En general, para muchos materiales la respuesta

global esfuerzo – deformación no puede ser condensada en una única relación, es decir,

muchos estados de deformaciones pueden corresponder a un estado de esfuerzos y

viceversa (Wood, 1991), así que ciertos aspectos que complican las modelaciones son

ignorados.

Algunas de las bases de la plasticidad han sido presentadas en Terzaghi (1943), (1968) y

Westergaard (1952), mientras que Wood (1991) realiza un compendio de comparaciones

entre el comportamiento no lineal elastoplástico de alambres de cobre recocido sometidos

a tensión simple repetida y las curvas 𝑞 vs 휀 de arcillas blandas en el ensayo edométrico.

Por su parte, Atkinson (2007) parte de conceptos de plasticidad perfecta, deconstruye las

definiciones de superficie de fluencia y elastoplasticidad y discute acerca de los efectos de

su cambio en el tiempo.

Entretanto, las relaciones constitutivas más usadas en las construcciones por elementos

finitos para representar suelos cohesivos y friccionales son los modelos de Tresca y Mohr

– Coulomb (Griffiths, 1982), (Sloan, 1981). Estas leyes constitutivas contienen superficies

de fluencia discontinuas con esquinas en las cuales la función no es diferenciable. Aunque

estas singularidades con frecuencia no son alcanzadas en condiciones planas de

deformación, son importantes en configuraciones axisimétricas (Sloan, 1981). En este

orden de ideas, las relaciones que redondean estas singularidades para la implementación

de Tresca y Mohr – Coulomb son el criterio de Von Mises y la superficie de fluencia de

Matsuoka (1976) respectivamente.

3.3.1 Modelos de comportamiento

Las deformaciones que pueden experimentar los suelos bajo cargas externas pueden ser

representadas de diversas formas, en la Figura 3-4 se especifican y a partir de ellas es

posible definir modelos de comportamiento esfuerzo.

Page 44: Desarrollo de un laboratorio virtual de geotecnia enfocado

24 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 3-4: Tipos de deformación en procesos de carga y descarga

Nombre de la fuente: Elaboración propia.

Según las características de la Figura 3-4 del comportamiento esfuerzo-deformación se

pueden extender como:

1) Deformación elástica: en donde se experimentan deformaciones recuperables, es

decir, la carga que las provoca genera deformaciones dentro de la masa del suelo,

pero la relación de vacíos permanece más o menos constante (Duque & Escobar,

2016).

2) Deformación elastoplástica: en donde una vez alcanzada una carga en particular,

el material tiende a mostrar deformaciones que no son recuperables.

3) Rígido perfectamente plástico: mostrado en la Figura 3-4 en donde el material no

experimenta deformaciones antes de alcanzar el punto de cedencia pero que al

sobrepasarlo ocurre deformación plástica pura. (Cueto et al., 2013).

4) Elástico perfectamente plástico: donde el comportamiento antes del punto de

cedencia es elástico y una vez se alcanza dicha carga las deformaciones crecen

sin que ello implique un aumento en la carga aplicada (Figura 3-4).

5) Endurecimiento por deformación: donde hay un aumento en la resistencia del

material debido a las deformaciones producidas.

6) Ablandamiento por deformación: donde hay disminución en la resistencia del

material debido a las deformaciones producidas

De acuerdo con las anteriores aseveraciones respecto a los modelos perfectamente

plásticos (Figura 3-4 y Figura 3-5) y verificando el modelo elástico para una barra cargada

uniaxialmente en un ensayo a deformación controlada; mostrada en la Figura 3-5, se tiene

que para las primeras etapas de carga el gradiente esfuerzo-deformación de la línea 𝐴𝐵

Page 45: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 25

corresponde al módulo de Young 𝐸 (Figura 3-5), si el proceso de carga o deformación se

detiene antes de alcanzar el punto 𝐵 la respuesta esfuerzo deformación regresa al punto

inicial en la misma trayectoria demarcada por la línea 𝐴𝐵 (Figura 3-5). Si la deformación

inducida sobrepasa el punto 𝐵 la respuesta se vuelve plástica, y la relación lineal esfuerzo-

deformación desaparece. Por otra parte, si la carga es retirada una vez se sobrepasa el

punto 𝐵 por ejemplo en el punto 𝐶, su comportamiento vuelve a ser elástico y la trayectoria

esfuerzo-deformación sigue los puntos 𝐶𝐷 de manera paralela a 𝐴𝐵.

El punto 𝐵 también es conocido como punto de cedencia, y de acuerdo con la Figura 3-5

en el caso de ser superado por ejemplo en el estado de esfuerzos del punto 𝐶 la barra

experimenta un cambio de longitud que puede ser representado mediante la relación de la

deformación plástica (휀𝐶𝑝). Así pues, el comportamiento es reversible en los segmentos 𝐴𝐵

y 𝐶𝐷 mientras que si se recorre 𝐵𝐶𝐹 experimenta deformaciones no recuperables. Por otra

parte, al realizar este experimento en condiciones controladas de deformación no es

posible sobrepasar el esfuerzo de cedencia del punto 𝐵, es decir el esfuerzo de fluencia

(𝜎𝑌) permanece constante obteniendo deformaciones muy grandes.

Figura 3-5: Respuesta de una barra elástica perfectamente plástica cargada de manera uniaxial.

Nombre de la fuente: adaptado de Potts, D., y Zdravkovic L., (1999).

3.3.2 Endurecimiento por deformación

Siguiendo la discusión de los modelos anteriores, apelando al ensayo conceptual de barras

cargadas de forma uniaxial y asumiendo en esta ocasión que este material se comporta

de manera tal que endurece por deformación se presenta la Figura 3-6, en ella se tiene

que, si el objeto de análisis se carga a lo largo de la trayectoria 𝐴𝐵 la relación esfuerzo-

Page 46: Desarrollo de un laboratorio virtual de geotecnia enfocado

26 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

deformación es elástica, entretanto, si se alcanza el punto 𝐶 el esfuerzo de fluencia en 𝐵

es superado y, al descargar desde el punto 𝐶 la barra se comporta de manera elástica y

paralela a 𝐴𝐵 nuevamente, en este nuevo punto 𝐷 se experimentan deformaciones

permanentes (휀𝐶𝑝).

Figura 3-6: Respuesta de un material elástico con plasticidad que endurece por deformación.

Nombre de la fuente: adaptado de Potts & Zdravkovic (1999).

3.3.3 Ablandamiento por deformación

En contraste a la explicación del modelo de endurecimiento por deformación, en el de

ablandamiento por deformación se observa que una vez alcanzado el punto de cedencia

en 𝐵, el esfuerzo que es capaz de resistir el material es menor que el de fluencia (𝜎𝑌𝐵) en

𝐵 (Figura 3-7). Desde la perspectiva de la ingeniería un material que se comporta de esta

manera, es decir, frágil puede llegar a generar inquietud e interés dado que su resistencia

y capacidad de resistir cargas disminuye a medida que se deforma.

Figura 3-7: Respuesta de un material elástico con plasticidad que ablanda por deformación.

Nombre de la fuente: Adaptado de Potts & Zdravkovic (1999).

Page 47: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 27

3.3.4 Características de un modelo elastoplástico

En este apartado se abordan de manera general los conceptos más sobresalientes

referentes a los modelos elastoplásticos del suelo. Las definiciones esenciales dentro de

un modelo elastoplástico son (Wood, 1991):

1) Parámetros elásticos, que son las variables con las que se describe el

comportamiento elástico, refiriéndose a las deformaciones recuperables.

2) Superficie de fluencia, definida como la frontera que divide el comportamiento

elástico al especificar la región donde se generan deformaciones elásticas.

3) Potencial plástico y principio de la normalidad, que muestran la definición del modo

en que ocurren las deformaciones plásticas, es decir, su magnitud y dirección.

4) Leyes de endurecimiento, acerca de cómo la magnitud de las deformaciones

plásticas está relacionada con el cambio de tamaño de la curva de fluencia, esta

relación es conocida como la ley de endurecimiento.

Función de fluencia

En contraste a la configuración unidimensional tratada en las definiciones de los modelos

de comportamiento, en donde un esfuerzo de fluencia ayuda a identificar el límite entre el

comportamiento elástico y su complemento plástico; en condiciones que impliquen un

mayor número de dimensiones no es posible hablar de esfuerzo de fluencia, esto debido

a que existen varias componentes de esfuerzos que no son cero (Simo & Hughes, 1998).

Así pues, se puede definir un criterio de fluencia como una función escalar escrita en

términos de las componentes de esfuerzo o de sus invariantes y algunos parámetros de

estado {𝑘}, es decir:

𝐹({𝜎}, {𝑘}) = 0 (3.3)

Esta función separa el comportamiento puramente elástico del plástico. La discusión

general reside en que esta superficie es dependiente del estado de esfuerzos {𝜎} y de los

parámetros de estado {𝑘}, estas cantidades {𝑘} pueden relacionarse con parámetros de

endurecimiento o ablandamiento. Para los casos de plasticidad con endurecimiento o

ablandamiento, los parámetros de estado varían para indicar cómo cambia la magnitud de

los esfuerzos a medida que ocurren deformaciones plásticas (Atkinson, 2007).

El valor de la función de fluencia es usado para identificar el tipo de comportamiento del

material: si 𝐹 < 0, ocurre comportamiento puramente elástico; si 𝐹 = 0, el comportamiento

Page 48: Desarrollo de un laboratorio virtual de geotecnia enfocado

28 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

es elastoplástico; y si 𝐹 > 0, se determina una situación imposible, este hecho se

esquematiza en la Figura 3-8.

Figura 3-8: Representación de la función de fluencia.

Nombre de la fuente: elaboración propia.

Función de potencial plástico

En los ejemplos uniaxiales de la sección 3.3.1 las deformaciones tienen la misma dirección

de los esfuerzos impuestos. En contraste, para la configuración multidimensional se tienen

seis componentes tanto de deformación como de esfuerzo (Figura 3-9), en este contexto

se puede especificar la dirección de las deformaciones plásticas en cada estado de

esfuerzos mediante una regla de flujo de acuerdo a la ecuación (3.4):

∆휀𝑖𝑝= 𝜆

𝜕𝑃

𝜕𝜎𝑖(3.4)

En donde ∆휀𝑖𝑝

representa las seis componentes del incremento de deformaciones

plásticas, 𝑃 es la función de potencial plástico y 𝜆 es un multiplicador escalar. La función

de potencial plástico tiene una forma similar la función de fluencia, es decir, 𝑃({𝜎}, {𝑘}) =

0. En algunos casos como en plasticidad perfecta y en general con condiciones coaxiales

se realiza otra simplificación extra, en ella, se toma a la función de potencial plástico igual

a la función de fluencia, o sea 𝑃 = 𝐹.

Page 49: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 29

Figura 3-9: Función de potencial plástico y la dirección del incremento de lasdeformaciones plásticas.

Nombre de la fuente: elaboración propia.

Algunas funciones de fluencia

Dentro de los modelos constitutivos más simples se encuentran los conocidos como Tresca

y Von Mises que trabajan en el marco de los modelos elásticos perfectamente plásticos,

estos se expresan en términos de esfuerzos totales y son aplicables en el estudio del

comportamiento no drenado del suelo (Chen, 2013). Asimismo, la condición de falla de

Coulomb se extiende para generar los modelos de Mohr-Coulomb y Drucker-Prager, estos

últimos son expresados en términos de esfuerzos efectivos. Por último, es posible realizar

algunas modificaciones para que el modelo de Drucker-Prager pueda representar

características de endurecimiento por deformación.

Superficies de fluencia de Tresca y Von Mises

Para la función de fluencia de Tresca se tiene que, si dos muestras de suelo similares son

ensayadas en dos presiones de cámara diferentes, sin permitir ningún tipo de

consolidación, los círculos de Mohr en la falla para los dos ensayos tienen el mismo

diámetro (Figura 3-10). Así pues, se puede tomar un criterio de falla que relacione la

resistencia al corte no drenada con el diámetro del círculo de Mohr (ecuación (3.5)).

𝜎1 − 𝜎3 = 2𝑆𝑢 (3.5)

En donde 𝑆𝑢 es la resistencia al corte no drenada del material ensayado. Para este caso

la función de fluencia se establece de acuerdo con la ecuación (3.6).

𝐹({𝜎}, {𝑘}) = 𝜎1 − 𝜎3 − 2𝑆𝑢 = 0 (3.6)

Por su parte el criterio de Von Mises opta por suavizar el hexágono regular que forma el

criterio de Tresca en el espacio de los esfuerzos principales. Así pues, se tienen dos

Page 50: Desarrollo de un laboratorio virtual de geotecnia enfocado

30 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

posibles funciones que suavizan la superficie de Tresca, en específico existe una opción

inscrita y otra circunscrita en el hexágono regular de Tresca, estas se encuentran en la

Alnuaim, A. M. (2014).

Figura 3-11 en el plano octaédrico. En la misma figura aparece el ángulo de Lode (𝜃), este

se define en el plano octaédrico por la línea que bisecta las proyecciones de los ejes 𝜎2 y

𝜎3, asimismo su valor crece en sentido contrahorario.

Figura 3-10: Círculos de Mohr para diferentes estados de esfuerzos de confinamiento.

Nombre de la fuente: adaptado de Alnuaim, A. M. (2014).

Figura 3-11: Representación esquemática del hexágono de Tresca y los círculos de Von Mises en el plano octaédrico.

Nombre de la fuente: adaptado de Smith, I.M. & Griffiths, D.V. 2004.

El uso de estos criterios de fluencia requiere que dentro del modelo sean especificados

tanto la resistencia al corte no drenada del suelo (𝑆𝑢) como el módulo de Young no drenado

(𝐸𝑢).

Page 51: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 31

Superficies de fluencia de Mohr-Coulomb y Drucker-Prager

En el criterio de Mohr-Coulomb se ignoran los efectos que puedan surgir debido al esfuerzo

intermedio principal; también asume que la falla depende únicamente de los esfuerzos

principal menor y mayor, la condición de Coulomb está basada en que una envolvente de

resistencia lineal que permite determinar una combinación crítica de esfuerzo normal (𝜎) y

cortante (𝜏) que puede causar la falla en determinado plano (Labuz & Zang, 2012). Esta

envolvente de falla tiene la forma de la ecuación (3.7):

𝜏 = 𝑐′ + 𝜎′tan(∅′) (3.7)

En donde ∅′ es el ángulo de fricción interna del suelo.

Algunas de las ventajas en la utilización del criterio de fluencia de Mohr-Coulomb son su

simplicidad matemática y la definición clara de los parámetros mecánicos del material,

mientras que algunas de sus limitaciones se encuentran relacionadas con la

implementación numérica dado que posee esquinas en el plano octaédrico, esto implica

que se encuentran singularidades a la hora de calcular derivadas (Figura 3-12).

En el numeral 3.3.4 se introdujo el concepto de regla de flujo, es decir, una relación entre

incremento de deformaciones y esfuerzos, de manera tal que se determina la orientación

del vector de incremento de deformación respecto a la condición de fluencia. De esta

manera la orientación de los vectores de incremento de deformación es constante en cada

una de las caras en la representación del criterio de Mohr-Coulomb en el plano octaédrico,

sin embargo, en las esquinas de dicho hexágono irregular la orientación es indeterminada

(Figura 3-12). La función de fluencia de Mohr-Coulomb está definida por la ecuación (3.8).

𝐹({𝜎}, {𝑘}) = (𝜎′1 − 𝜎′3) − 2𝑐′ cos(∅′) − (𝜎′1 + 𝜎

′3)𝑠𝑒𝑛(∅

′) = 0 (3.8)

Que de manera similar al criterio de Von Mises, también puede ser escrita en términos de

invariantes de esfuerzos de acuerdo con la ecuación (3.9).

Por otra parte, la función de fluencia de Drucker-Prager que presupone una modificación

al criterio de Mohr-Coulomb se representa como un círculo en el plano octaédrico. Esta

función se asume como una función independiente del ángulo de Lode, la opción

𝐹({𝜎}, {𝑘}) = 𝐽 − (𝑐′

tan(∅′)+ 𝑝′)

2√3𝑠𝑒𝑛(∅′)

3 + 𝑠𝑒𝑛(∅′) (3.9)

Page 52: Desarrollo de un laboratorio virtual de geotecnia enfocado

32 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

circunscrita y que coincide con el ángulo de −30° de compresión triaxial genera la ecuación

(3.10).

Figura 3-12: Superficies de fluencia de Mohr-Coulomb y Drucker-Prager en el plano octaédrico

Nombre de la fuente: Adaptado de Sagrilo et al., (2012).

Entretanto, el uso de estas dos superficies de fluencia análogas requiere la especificación

de 5 parámetros de entrada, tres de ellos controlan el comportamiento plástico, es decir,

la cohesión (𝑐’), el ángulo de fricción (∅′) y el ángulo de dilatancia (𝜈), las dos restantes son

la relación de Poisson (𝜇′) y el módulo de Young (𝐸′), que controlan el comportamiento

elástico. Cabe recordar que en condiciones de flujo no asociado (𝑃 ≠ 𝐹) se permite que 𝑃

sea una función del ángulo de dilatancia (𝜈) en lugar del ángulo de fricción interna (∅′), así

pues, en condiciones de flujo asociado se asume que 𝜈 es igual a ∅′.

De esta manera, el modelo está limitado si se usa junto a una regla de flujo asociado que

hace que se presenten dilataciones excesivas durante la falla del material (Grujicic et al.,

𝐹({𝜎}, {𝑘}) = 𝐽 − (𝑐′

tan(∅′)+ 𝑝′)

2√3𝑠𝑒𝑛(∅′)

3 + 𝑠𝑒𝑛(∅′)

𝐽 =1

√6√(𝜎′1 − 𝜎′2)

2 + (𝜎′2 − 𝜎′3)2 + (𝜎′3 − 𝜎′1)

2

(3.10)

Page 53: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 33

2009) y a pesar de ello, es usado de manera extensa en mecánica de suelos dado que su

implementación computacional no es en extremo complicada y a que los parámetros de

entrada son susceptibles de ser obtenidos de ensayos triaxiales y del modelo de Mohr-

Coulomb. Por estas razones es el elegido para representar el comportamiento

elastoplástico de los materiales modelados en este trabajo de grado. Sin embargo, la

evidencia experimental indica que las deformaciones plásticas en suelos comienzan desde

etapas tempranas de carga, así pues, para representar dicho comportamiento los modelos

típicos elastoplásticos no son adecuados (Zeevaert, 1980; Rocscience, s.f.).

Al igual que el criterio de Von Mises, el modelo de Drucker-Prager se encuentra dentro del

marco de referencia de los modelos elásticos perfectamente plásticos, así pues, es posible

modificar su funcionamiento para que pueda representar materiales que endurecen por

deformación, este tratamiento se explica en el título 3.4.8.

Finalmente, no puede desconocerse la importancia de los modelos del estado crítico que

permiten un mejor ajuste en el uso de la teoría de plasticidad en el comportamiento del

suelo. Entre estos modelos se encuentran los bien conocidos Cam clay y Cam clay

modificado que requieren de diversas aseveraciones para que puedan ser usados en el

análisis de problemas con valor conocido en la frontera (Potts & Axelsson, 2002).

En este tópico se destaca que estos modelos fueron desarrollados basados en

observaciones del espacio de esfuerzos triaxial, es decir, en donde dos de los esfuerzos

principales son iguales ya sea el mayor y el intermedio o el menor y el intermedio. Así pues,

para ser usados en análisis numéricos, debe realizarse una generalización al espacio

completo de esfuerzos reemplazando al esfuerzo desviador 𝑞 por 𝐽 de la ecuación (3.10)

y, aunque, algunos autores sugieren que la superficie de fluencia utilizada en el plano

octaédrico sea circular junto al criterio de falla Mohr-Coulomb; esto implica que las

condiciones de estado crítico solamente se alcanzan bajo condiciones de compresión

triaxial es decir 𝜎′2 = 𝜎′3 (Potts & Zdravkovic, 1999-b).

Coincidencia de los ejes

Una de las mayores deficiencias de la teoría del potencial plástico es que su uso implica

aceptar la coincidencia de ejes de los esfuerzos principales con los ejes de las

deformaciones plásticas, en otras palabras, acepta coaxialidad, no obstante, hay evidencia

fuerte de índole experimental y de micromecánica que indica que en suelos granulares

Page 54: Desarrollo de un laboratorio virtual de geotecnia enfocado

34 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

reales estos ejes principales no coinciden (Yu, 2007). Algunos resultados de ensayos

torsionales en el denominado “hollow cylinder” demuestran que en general la aproximación

de coincidencia de ejes es válida cuando la dirección de los esfuerzos de los ejes

principales se mantiene fija en el proceso de carga (Gutierrez et al, 1991).

Reglas de endurecimiento o ablandamiento

También conocidas como leyes describen cómo los parámetros de estado {𝑘} varían con

la deformación plástica y cómo cambia el tamaño de la superficie de fluencia. En el caso

de plasticidad perfecta no ocurre ablandamiento ni endurecimiento por lo que estos

parámetros de estado {𝑘} son constantes. Entretanto, para representar materiales que

exhiben endurecimiento o ablandamiento, estas reglas son necesarias para incluir la forma

en que la función fluencia cambia. En la Figura 3-13 se esquematizan dos casos, en el

primero de ellos con el aumento en deformación el material aumenta su esfuerzo de

fluencia, mientras que, en el segundo con el aumento en deformación acumulada el

esfuerzo de fluencia disminuye. A esta relación se le conoce como regla de

endurecimiento.

Figura 3-13: Ejemplos de las reglas de endurecimiento o ablandamiento

Nombre de la fuente: adaptado de Potts y Zdravkovic (1999).

3.4 Método de los elementos finitos

Gran cantidad de procesos físicos que se intentan abordar en ingeniería se pueden

proponer en términos de ecuaciones diferenciales parciales, muchas de ellas difíciles de

abordar por lo que para resolverlas se cuenta tanto con procedimientos analíticos como

con métodos numéricos. Los primeros proveen soluciones exactas, sin embargo, su campo

Page 55: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 35

de aplicación es limitado debido a sus numerosas simplificaciones en la geometría y en las

condiciones de frontera, por otro lado, los métodos numéricos presentan una solución

aproximada que con la precisión suficiente son de oportuna aplicación.

Por lo general, los métodos numéricos se basan en la distribución deliberada de puntos en

el dominio geométrico con la finalidad de encontrar la solución en dichos lugares, esto

permite interpolar el resultado en el resto del dominio del sistema. Los métodos numéricos

más conocidos son (Cardoso, 2016):

1) Diferencias finitas, más fácil de desarrollar que los otros métodos, pero limitado al

tipo de discretización del dominio que debe estar basado siempre en cuadrículas.

2) Volumen finito, con la ventaja de manejar gran cantidad de configuraciones de

mallas, pero que presenta menor estabilidad numérica en comparación con los

elementos finitos.

3) Elementos finitos, con mayor dificultad en la implementación, pero con mayor

precisión y estabilidad en los cálculos.

El método de los elementos finitos (MEF) es una de las estrategias más populares para la

determinación de soluciones precisas de ecuaciones diferenciales parciales. También

referido en este documento como FEM por sus siglas en inglés, se basa en reducir un

problema de valor conocido en la frontera de una ecuación diferencial parcial lineal a un

sistema de ecuaciones lineales según la ecuación (3.11). Esta ecuación matricial es

análoga a la ley de Hooke, así pues, [𝐾] es la matriz de rigidez del sistema, {𝐹} es el vector

de fuerzas y {𝑈} es el vector de desplazamientos desconocidos debidos a {𝐹}.

Aunque muchos de los libros referentes a este tema presentan una exposición amplia de

las bases teóricas del MEF dejan de lado las implicaciones inherentes a su aplicación y

puesto que su exigencia conceptual a nivel computacional es alta, diversas

consideraciones de este deben ser tenidas en cuenta (Gockenbach, 2006).

El método de los elementos finitos envuelve los siguientes pasos:

Discretización, en donde se busca modelar la geometría del sistema en cuestión al dividirla

en pequeñas partes, delimitadas en sus vértices por nodos, aunque éstos también pueden

ubicarse en cualquier lugar dentro de sus aristas.

[𝐾]{𝑈} = {𝐹}. (3.11)

Page 56: Desarrollo de un laboratorio virtual de geotecnia enfocado

36 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

1) Elección de la variable primaria, la cual puede ser desplazamientos o esfuerzos.

La variación de esta debe ser establecida en cada uno de los nodos que definen

los elementos de la discretización, esto se logra mediante la generación de

grados de libertad.

2) Ecuaciones de los elementos.

3) Ecuaciones globales, en donde se combinan las ecuaciones “locales” de cada

uno de los elementos para dar forma al sistema que gobierna el comportamiento

total del problema.

4) Condiciones de frontera, las cuales pueden modificar las ecuaciones globales,

estas condiciones pueden darse como fuerzas o desplazamientos.

5) Por último, la solución del modelo de ecuaciones, que forma sistemas extensos

de ecuaciones.

De esta manera, diagrama de flujo típico del proceso de análisis por el MEF se muestra en

la Figura 3-14.

3.4.1 Funciones de forma y de interpolación de desplazamientos

La principal aproximación en el método de los elementos finitos es asumir que los

desplazamientos de los elementos varían de una forma en particular, asimismo, es

importante que cumplan condiciones de compatibilidad, por lo que, se asume que las

componentes de los desplazamientos tienen forma polinomial cuyo orden depende del

número de nodos que hacen parte del elemento.

Algunos autores recalcan que los elementos triangulares son de alguna manera mejores

que los elementos cuadrilaterales (Potts & Zdravkovic, 1999), un ejemplo son los casos de

análisis por elementos finitos en materiales incompresibles en donde los cuadrilaterales

requieren un total de 17 nodos para realizar una integración completa en cálculos en

condiciones planas de deformación (Sloan, 1981; Burd, 1986). Asimismo, otros afirman

que en la práctica el uso de elementos de menor orden es preferido (Bathe, 2014).

Por otro lado, existen procedimientos que buscan mejorar la estimación de esfuerzos,

estas soluciones son presentadas por Payen y Bathe (2011) para elementos

cuadrilaterales y por Jeon, Lee y Bathe (2014) para elementos triangulares lineales. En

síntesis, hay diferentes tipos de elementos cada uno de ellos con ventajas y desventajas,

Page 57: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 37

así pues, en el desarrollo de este trabajo se hizo uso de los elementos triangulares lineales

por su facilidad en el manejo computacional.

Figura 3-14: Diagrama de flujo del MEF

Nombre de la fuente: Universidad de Castilla-La Mancha, (s. f)

3.4.2 Elemento triangular lineal

El elemento triangular lineal en el sistema coordenado (𝐿1, 𝐿2) es mostrado en la Figura

3-15, este sistema representa porciones de área respecto al área total del elemento

Page 58: Desarrollo de un laboratorio virtual de geotecnia enfocado

38 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

triangular, por ello los valores de las funciones de forma de las ecuaciones (3.12), (3.13) y

(3.14) se encuentran en el rango (0, 1):

Figura 3-15: Coordenadas de área para el elemento triangular y las correspondientes áreas para los nodos 1, 2 y 3.

Nombre de la fuente: Segerlind, L. J., (1984).

En resumen, las funciones de forma se describen por las ecuaciones (3.12), (3.13) y (3.14):

𝑁1 = 𝐿1 (3.12)𝑁2 = 𝐿2 (3.13)

𝑁3 = 1 − 𝐿1 − 𝐿2 (3.14)Entretanto, las componentes de la matriz de transformación de coordenadas, es decir, las

partes del jacobiano en la ecuación (3.19), son constantes y se determinan derivando

(3.15) y (3.16), estas derivadas se presentan en (3.17) y (3.18) (Segerlind, 1984):

𝑥(𝐿1, 𝐿2) = 𝐿1𝑋1 + 𝐿2𝑋2 + (1 − 𝐿1 − 𝐿2)𝑋3 (3.15)𝑦(𝐿1, 𝐿2) = 𝐿1𝑌1 + 𝐿2𝑌2 + (1 − 𝐿1 − 𝐿2)𝑌3 (3.16)

𝜕𝑥

𝜕𝐿1= 𝑋1 − 𝑋3,

𝜕𝑦

𝜕𝐿1= 𝑌1 − 𝑌3 (3.17)

𝜕𝑥

𝜕𝐿2= 𝑋2 − 𝑋3,

𝜕𝑦

𝜕𝐿2= 𝑌2 − 𝑌3 (3.18)

En este caso la matriz jacobiana se organiza de acuerdo a los resultados de (3.17) y (3.18)

y toma la forma de la igualdad en (3.19):

[𝐽] = [𝑋1 − 𝑋3 𝑌1 − 𝑌3𝑋2 − 𝑋3 𝑌2 − 𝑌3

] (3.19)

3.4.3 Elemento triangular cuadrático

La representación de este elemento se muestra en la Figura 3-16, en este tipo de elemento

se tienen seis nodos que se definen por las funciones de forma de las ecuaciones (3.20),

a (3.25).

Page 59: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 39

Figura 3-16: Funciones de forma cuadráticas para el elemento triangular.

Nombre de la fuente: Segerlind, L. J. (1984). Applied Finite Element Analysis.

𝑁1 = 𝐿1(2𝐿1 − 1) (3.20)𝑁2 = 4𝐿1𝐿2 (3.21)

𝑁3 = 𝐿2(2𝐿2 − 1) (3.22)𝑁4 = 4𝐿2(1 − 𝐿1 − 𝐿2) (3.23)

𝑁5 = 1 − 3(𝐿1 + 𝐿2) + 2(𝐿1 + 𝐿2)2 (3.24)

𝑁6 = 4𝐿1(1 − 𝐿1 − 𝐿2) (3.25)Para encontrar la matriz jacobiana se sigue un procedimiento similar al realizado en el

elemento triangular lineal, es decir, se derivan las coordenadas globales (𝑥, 𝑦) respecto a

las naturales (𝐿1, 𝐿2):

𝜕𝑥

𝜕𝐿1= (4𝐿1 − 1)𝑋1 + 4𝐿2𝑋2 − 4𝐿2𝑋4 + [−3 + 4(𝐿1 + 𝐿2)]𝑋5

+ [4(1 − 2𝐿1 − 𝐿2)]𝑋6

(3.26)

𝜕𝑦

𝜕𝐿1= (4𝐿1 − 1)𝑌1 + 4𝐿2𝑌2 − 4𝐿2𝑌4 + [−3 + 4(𝐿1 + 𝐿2)]𝑌5

+ [4(1 − 2𝐿1 − 𝐿2)]𝑌6

(3.27)

𝜕𝑥

𝜕𝐿2= 4𝐿1𝑋2 + (4𝐿2 − 1)𝑋3 + [4(1 − 𝐿1 − 2𝐿2)]𝑋4

+ [−3 + 4(𝐿1 + 𝐿2)]𝑋5 − 4𝐿1𝑋6

(3.28)

𝜕𝑦

𝜕𝐿2= 4𝐿1𝑌2 + (4𝐿2 − 1)𝑌3 + [4(1 − 𝐿1 − 2𝐿2)]𝑌4

+ [−3 + 4(𝐿1 + 𝐿2)]𝑌5 − 4𝐿1𝑌6

(3.29)

De nuevo estas cantidades permiten conocer la matriz jacobiana [𝐽] a usar durante los

procesos de integración, en esencia se reemplaza 𝐿1 y 𝐿2 por los puntos de integración

definidos en la Tabla 3-1. El jacobiano de la transformación para condiciones

bidimensionales se muestra en la ecuación (3.30), contiene las derivadas de calculadas en

las ecuaciones (3.26), (3.27), (3.28) y (3.29).

Page 60: Desarrollo de un laboratorio virtual de geotecnia enfocado

40 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

[𝐽] =

[ 𝜕𝑥

𝜕𝐿1

𝜕𝑦

𝜕𝐿1𝜕𝑥

𝜕𝐿2

𝜕𝑦

𝜕𝐿2]

(3.30)

3.4.4 Puntos de integración

Los puntos de integración para la construcción de las matrices para el análisis en

elementos triangulares tanto lineales como cuadráticos, se detallan en la Tabla 3-1

(Segerlind, 1984), estos fueron definidos por Hammer et al., (1956).

Tabla 3-1. Puntos de muestreo y coeficientes de peso para elementos triangulares en el sistema coordenado (𝐿1, 𝐿2).

𝒏 𝑷𝒖𝒏𝒕𝒐𝒔 𝑳𝟏 𝑳𝟐 𝑾𝒊 𝑬𝒓𝒓𝒐𝒓

1 a 1/3 1/3 1/2 𝑂(ℎ)

3 a

b

c

1/2

1/2

0

0

1/2

1/2

1/6

1/6

1/6

𝑂(ℎ2)

7 a

b

c

d

e

f

g

1/3

𝛼

𝛽

𝛽

𝛾

Δ

𝛾

1/3

𝛽

𝛽

𝛼

𝛾

Δ

Δ

0.11250

0.0661971

0.0661971

0.0661971

0.0629696

0.0629696

0.0629696

𝑂(ℎ6)

𝛼 = 0.0597159

𝛽 = 0.470142

𝛾 = 0.101287

Δ = 0.797427

Nombre de la fuente: Segerlind, L. J. (1984). Applied Finite Element Analysis.

Page 61: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 41

Para la Tabla 3-1, 𝑛 indica el número de puntos en donde se evalúa determinada expresión,

𝐿1 y 𝐿2 definen la ubicación de dichos puntos dentro del elemento, 𝑤𝑖 es el peso para

ponderar los resultados, mientras que, el error asociado disminuye al realizar cálculos en

mayor cantidad de puntos. Así pues, se reconoce que al usar mayor cantidad de puntos

no se gana precisión perdida en otros pasos del problema.

En estos puntos de integración se pueden tener estimaciones de los diferentes campos

haciendo uso de la matriz [𝐵]; esta matriz varía punto a punto para el caso del elemento

triangular cuadrático y es constante en los elementos lineales. El esquema de integración

se detalla en la ecuación (3.31):

∫ ∫ 𝑔(𝐿1, 𝐿2)𝑑𝐿1𝑑1−𝐿2

0

𝐿2

1

0

=∑𝑔(𝐿1𝑖, 𝐿2𝑖)𝑊𝑖

𝑛

𝑖=1

(3.31)

Aquí la función 𝑔 incluye el determinante de la matriz jacobiana de transformación de

coordenadas globales a locales.

3.4.5 Idealización geométrica

Algunos de los problemas que se dan en geotecnia pueden ser objeto de simplificaciones

en cuanto a su geometría, esto se debe a que se presentan configuraciones especiales,

en específico se tienen condiciones axisimétricas y planas de deformación. En esta sección

se presenta una ligera introducción de las condiciones axisimétricas.

Condiciones axisimétricas

En el caso de las condiciones que poseen simetría rotacional, por ejemplo, en zapatas

circulares aisladas, pilotes y muestras triaxiales, se suelen utilizar coordenadas cilíndricas.

Es de suma utilidad dado que no hay desplazamientos en la dirección angular y los

desplazamientos en las otras dos direcciones son independientes de esta primera

coordenada (𝜃). En la Figura 3-17 se ilustra esta configuración, mientras que, las

deformaciones se definen de acuerdo a las ecuaciones en (3.32)

휀𝑟 =−𝜕𝑢

𝜕𝑟;휀𝑧 =−

𝜕𝑣

𝜕𝑧;휀𝜃 =−

𝑢

𝑟; 𝛾𝑟𝑧 =−

𝜕𝑣

𝜕𝑟−𝜕𝑢

𝜕𝑧;𝛾𝑟𝜃 = 𝛾𝑧𝜃 = 0 (3.32)

Page 62: Desarrollo de un laboratorio virtual de geotecnia enfocado

42 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 3-17: condiciones axisimétricas

Nombre de la fuente: elaboración propia.Donde 𝑟 es la dirección radial, 𝑧 es la profundidad y los desplazamientos en 𝑟 y 𝑧 son 𝑢 y

𝑣 respectivamente.

3.4.6 Matriz de interpolación de desplazamientos

Con el objetivo de generar un código computacional capaz de lidiar con configuraciones

planas de deformación y axisimétricas en el modelo acoplado, las matrices de interpolación

de desplazamientos [𝐵] se pueden organizar de acuerdo a la ecuación (3.33) para un

elemento general de 𝑛 nodos.

{Δ휀} = [𝐵]{Δ𝑢} (3.33)

Para condiciones planas de deformación se tiene la igualdad (3.34):

{

∆휀𝑥∆휀𝑦∆𝛾𝑥𝑦∆휀𝑧 }

=

[ 𝜕𝑁1𝜕𝑥

0𝜕𝑁2𝜕𝑥

0 … …𝜕𝑁𝑛𝜕𝑥

0

0𝜕𝑁1𝜕𝑦

0𝜕𝑁2𝜕𝑦

… … 0𝜕𝑁𝑛𝜕𝑦

𝜕𝑁1𝜕𝑦

𝜕𝑁1𝜕𝑥

𝜕𝑁2𝜕𝑦

𝜕𝑁2𝜕𝑥

… …𝜕𝑁𝑛𝜕𝑦

𝜕𝑁𝑛𝜕𝑥

0 0 0 0 … … 0 0 ]

{

Δ𝑢1Δ𝑣1Δ𝑢2Δ𝑢2……Δ𝑢𝑛Δ𝑣𝑛}

(3.34)

Para condiciones axisimétricas se define la ecuación (3.35):

{

∆휀𝑟∆휀𝑧∆𝛾𝑟𝑧∆휀𝜃

} =

[ 𝜕𝑁1𝜕𝑟

0𝜕𝑁2𝜕𝑟

0 … …𝜕𝑁𝑛𝜕𝑟

0

0𝜕𝑁1𝜕𝑧

0𝜕𝑁2𝜕𝑧

… … 0𝜕𝑁𝑛𝜕𝑧

𝜕𝑁1𝜕𝑧

𝜕𝑁1𝜕𝑟

𝜕𝑁2𝜕𝑧

𝜕𝑁2𝜕𝑟

… …𝜕𝑁𝑛𝜕𝑧

𝜕𝑁𝑛𝜕𝑟

𝑁1𝑟

0𝑁2𝑟

0 … …𝑁𝑛𝑟

0 ]

{

Δ𝑢1Δ𝑣1Δ𝑢2Δ𝑢2……Δ𝑢𝑛Δ𝑣𝑛}

(3.35)

Por otra parte, para la determinación de la matriz de rigidez de los elementos para ambas

configuraciones se maneja la ecuación (3.36):

Page 63: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 43

[𝐾𝐸] = ∫ ∫ 𝑡[𝐵]𝑇[𝐷][𝐵]det(𝐽)𝑑𝐿1𝑑𝐿2

1−𝐿2

0

1

0(3.36)

En donde para condiciones planas de deformación se tiene que 𝑡 = 1 y para

configuraciones axisimétricas 𝑡 = 2𝜋𝑟, donde 𝑟 es la distancia radial del punto de

integración al eje de simetría en el esquema numérico que se plantea en el numeral 3.4.4.

3.4.7 Matriz constitutiva [𝑫𝒆𝒑]

Este subtítulo se basa en la referencia de Zeevaert (1980) respecto a la plasticidad del

suelo. Así pues, para la definición de algunas de las características mecánicas plásticas

de materiales térreos es necesario establecer las métricas que controlan la relación

esfuerzo deformación, para ello se pueden dividir a las deformaciones totales en plásticas

y elásticas (ecuación (3.37)).

휀 = 휀𝑒 + 휀𝑝 (3.37)

A partir del principio de normalidad se puede enlazar al anterior incremento de las

deformaciones plásticas con una función de potencial plástico (𝑄) que al igual que la

función de fluencia (𝐹), depende del estado de esfuerzos y del parámetro de

endurecimiento (𝑘), como lo esquematizan las ecuaciones (3.38) y (3.39).

𝐹 = 𝐹(𝜎, 𝑘) (3.38)

𝑄 = 𝑄(𝜎, 𝑘) (3.39)

Que de manera similar al principio de normalidad, puede regir los incrementos de

deformaciones plásticas, de acuerdo a la forma de la ecuación (3.40).

𝑑휀𝑝 = 𝜆𝜕𝑃

𝜕𝜎 (3.40)

En el caso en el que 𝑄 = 𝐹 la situación es conocida como plasticidad asociada. A partir de

las ecuaciones (3.4) y (3.40) y la matriz de elástica [𝐷] se tiene la ecuación (3.41).

𝑑휀 = [𝐷]−1𝑑𝜎 + 𝜆𝜕𝑄

𝜕𝜎 (3.41)

Cuando el material se encuentra en fluencia, el estado de esfuerzos debe satisfacer la

condición de 𝐹 = 0así que 𝑑𝐹 = 0, y aplicando el diferencial total a la ecuación (3.38) se

obtiene la forma de la ecuación (3.42).

𝑑𝐹 = {𝜕𝐹

𝜕𝜎}𝑇

{𝑑𝜎} + {𝜕𝐹

𝜕𝑘}𝑇

{𝑑𝑘} = 0 (3.42)

La ecuación (3.42) también es conocida como la condición de consistencia. De donde se

puede tomar el último término de la mano derecha como la aproximación de (3.43).

Page 64: Desarrollo de un laboratorio virtual de geotecnia enfocado

44 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

{𝜕𝐹

𝜕𝑘}𝑇

{𝑑𝑘} = −𝐴𝜆 (3.43)

Reemplazando (3.43) en (3.42) se obtiene la relación (3.44).

{𝜕𝐹

𝜕𝜎}

𝑇

{𝑑𝜎} − 𝐴𝜆 = 0 (3.44)

En donde 𝐴 es una función de las características de endurecimiento del material. Las

ecuaciones (3.41) y (3.44) pueden formar un sistema de ecuaciones, de acuerdo a la

igualdad (3.45).

{{𝑑휀}0} =

[ [𝐷]−1 {

𝜕𝑄

𝜕𝜎}

{𝜕𝐹

𝜕𝜎}

𝑇

−𝐴 ]

{{𝑑𝜎}𝜆} (3.45)

Multiplicando el primer renglón de (3.45) por {𝜕𝐹

𝜕𝜎}𝑇[𝐷] y sustituyendo el término {

𝜕𝐹

𝜕𝜎}𝑇{𝑑𝜎}

en el segundo se encuentra la ecuación (3.46).

{𝜕𝐹

𝜕𝜎}

𝑇

[𝐷]{𝑑휀} − [{𝜕𝐹

𝜕𝜎}

𝑇

[𝐷] {𝜕𝑄

𝜕𝜎} + 𝐴] 𝜆 = 0 (3.46)

De (3.46) se puede despejar 𝜆 y reemplazar en el primer renglón de (3.45) ya multiplicado

a la izquierda por [𝐷] y se obtiene (3.47).

{𝑑𝜎} = [𝐷]{𝑑휀} −[𝐷] {

𝜕𝑄𝜕𝜎} {

𝜕𝐹𝜕𝜎}

𝑇

[𝐷]

{𝜕𝐹𝜕𝜎}𝑇

[𝐷] {𝜕𝑄𝜕𝜎} + 𝐴

{𝑑휀} (3.47)

De esta manera, en la ecuación (3.48) queda definida la matriz elastoplástica (𝐷𝑒𝑝):

[𝐷𝑒𝑝] = [𝐷] −[𝐷] {

𝜕𝑄𝜕𝜎} {

𝜕𝐹𝜕𝜎}

𝑇

[𝐷]

{𝜕𝐹𝜕𝜎}

𝑇

[𝐷] {𝜕𝑄𝜕𝜎}

+ 𝐴(3.48)

En el caso de plasticidad asociada [𝐷𝑒𝑝] es simétrica. Para el presente desarrollo se hace

uso de plasticidad asociada.

3.4.8 Modelación del comportamiento de endurecimiento por deformación

El criterio de Drucker-Prager se puede expresar de acuerdo a la ecuación (3.49) (Drucker

& Prager, 1952).

Page 65: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 45

𝐹 = 3𝛼′𝜎𝑚 + �̃� − 𝑘 (3.49)

Las componentes de la ecuación (3.49) se definen por las ecuaciones (3.50) a (3.53).

𝛼′ =2𝑠𝑒𝑛𝜙′

√3(3 − 𝑠𝑒𝑛𝜙′)(3.50)

𝑘 =6𝑐′𝑐𝑜𝑠𝜙′

√3(3 − 𝑠𝑒𝑛𝜙′)(3.51)

𝜎𝑚 =𝐽13=(𝜎𝑟 + 𝜎𝜃 + 𝜎𝑧)

3=(𝜎1 + 𝜎2 + 𝜎3)

3 (3.52)

�̃� = √𝐽2 = [1

2(𝑆𝑟

2 + 𝑆𝜃2 + 𝑆𝑧

2) + 𝜏𝑟𝑧2 ]

1/2

𝑆𝑟 = 𝜎𝑟 − 𝜎𝑚𝑆𝜃 = 𝜎𝜃 − 𝜎𝑚𝑆𝑧 = 𝜎𝑧 − 𝜎𝑚

(3.53)

En donde 𝐽1 y 𝐽2 son el primero y el segundo invariante de esfuerzos y 𝜎𝑟, 𝜎𝜃 y 𝜎𝑧 los

esfuerzos en dirección radial, tangencial y vertical respectivamente.

Dadas las limitaciones del criterio de Drucker-Prager en donde 𝑘 es constante el parámetro

𝐴 es indefectiblemente cero (ecuación (3.54)) y, por tanto, la respuesta mecánica después

de fluencia es perfectamente plástica.

𝐴 = −1

𝜆{𝜕𝐹

𝜕𝑘}𝑇

Δ𝑘 (3.54)

En este punto, en un marco de endurecimiento por deformación 𝐴 puede relacionarse con

los cambios en las deformaciones plásticas (Zeevaert, 1980), de acuerdo con la ecuación

(3.55).

𝐴 =1

𝜆{𝜕𝐹

𝜕𝜎}

𝑇

{𝜕𝜎} (3.55)

En donde la regla de flujo define el valor de 𝜆 se indica mediante la ecuación (3.56):

𝜆 =𝑑휀𝑝𝑑𝐹𝑑𝜎𝑧

(3.56)

Donde 𝑑휀𝑝 es el incremento de deformación plástica uniaxial. Asimismo, se constituye un

concepto clave en la consecución de insumos para este modelo y modifica lo establecido

en la ecuación (3.55) y se obtiene (3.57).

𝐴 =

𝑑𝐹𝑑𝜎𝑧𝑑휀𝑝

{𝜕𝐹

𝜕𝜎}

𝑇

{𝜕𝜎} (3.57)

Page 66: Desarrollo de un laboratorio virtual de geotecnia enfocado

46 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Así pues, los insumos para el modelo deben ser tomados de un ensayo uniaxial en donde

el vector gradiente es calculado aplicando la ecuación (3.58). En caso de usar datos de

otro tipo de ensayo debe reformularse la ecuación (3.58):

𝑑𝐹

𝑑𝜎=

𝛼′

3𝜎𝑚[

1 1 1 01 1 1 01 1 1 00 0 0 0

]{

0𝜎𝑧00

} +1

2�̅�

1

3[

2 −1 −1 0−1 2 −1 0−1 −1 2 00 0 0 2

]{

0𝜎𝑧00

} (3.58)

En síntesis, el tratamiento algebraico y las condiciones de ensayo de (3.58) conducen a

(3.59)

𝑑𝐹

𝑑𝜎= 𝛼′ {

1110

} +1

2√3{

−12−10

} (3.59)

Reemplazando (3.59) en (3.57) la variable 𝐴 queda definida de en la ecuación (3.60):

𝐴 =𝑑𝜎𝑧𝑑휀𝑝

(𝛼′ +1

√3)2

(3.60)

En la ecuación (3.60) la cantidad𝑑𝜎𝑧

𝑑𝜀𝑝es la pendiente de la curva esfuerzo deformación en

la zona deformaciones elastoplásticas y se denota mediante el símbolo 𝐻′. De manera

esquemática se muestra 𝐻′ en la Figura 3-18.

Figura 3-18: Deformaciones elásticas, plásticas y la definición de 𝐻’.

Nombre de la fuente: elaboración propia.

3.5 Análisis no lineal por elementos finitos

La estrategia para encontrar la respuesta no lineal en un sistema en elementos finitos

consiste en la generación de formulaciones incrementales. Para obtener una solución a un

problema con condiciones de frontera el cambio en dichas condiciones debe darse en

incrementos suficientemente pequeños, su finalidad es lograr la precisión necesaria para

cada problema estudiado (Potts & Zdravkovic, 1999). En estos tipos de problemas las

Page 67: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 47

dificultades provienen tanto de las no linealidades geométricas como de las impuestas por

el comportamiento constitutivo, por estas razones la matriz de rigidez global del sistema

no es constante, sino que varía a lo largo de cada uno de los incrementos (Zeevaert, 1980).

3.5.1 Métodos para el análisis no lineal

Dado que es menester establecer el contexto para reconocer los requerimientos del

problema tratado, son abordados tres métodos de análisis no lineal:

1) En el método viscoplástico se usan las ecuaciones del modelo viscoplástico

como un artificio matemático para estimar el comportamiento no lineal,

elastoplástico e independiente de tiempo. En este el material tiene permitido tener

un estado de esfuerzos por fuera de la superficie de fluencia por periodos finitos.

En lugar de deformaciones plásticas, en este método se habla de deformaciones

viscoplásticas, estas son generadas en forma de una tasa que está relacionada con

la magnitud de esfuerzos con la magnitud que ha sido sobrepasada la función de

fluencia (Griffiths & Smith, 1988).

2) El método modificado de Newton Raphson se basa en corregir los estados de

esfuerzos ilegales antes de continuar con incrementos de carga subsiguientes,

para ello se evalúan las relaciones constitutivas en un estado de esfuerzos legal o

cercano a este, de esta manera se hace necesario el uso de un valor de tolerancia

de desfase del criterio de fluencia y, un valor de carga desbalanceada de

convergencia, este último se compara con la carga que no toma el modelo en un

incremento dado y se itera hasta que la magnitud no tomada sea menor que el valor

de convergencia. Este desbalance se genera porque que la matriz de rigidez se

asume constante a lo largo de cualquier incremento de carga (Potts & Zdravkovic,

1999).

3) El método de la rigidez tangente o método de la rigidez variable es equivalente

a hacer un análisis lineal por partes, este asume que la matriz de rigidez del sistema

es constante durante cada incremento (Figura 3-19), sin embargo, en algunos

casos puede generar estados de esfuerzos de tensión que ciertamente los sistemas

particulados no son capaces de desarrollar. En condiciones de desplazamiento

controlado pueden converger con un número relativamente bajo de incrementos,

en contraste en carga controlada el número de pasos suele ser elevado (Smith et

Page 68: Desarrollo de un laboratorio virtual de geotecnia enfocado

48 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

al., 2014). En general destaca porque tiene en cuenta la reducción de rigidez a

medida que el material se acerca a la falla (Griffiths & Smith, 1988).

Figura 3-19: Método de la rigidez tangente (análisis lineal por partes).

Nombre de la fuente: adaptado de Potts, D. (2003).

En este documento se trabaja con el método de la rigidez variable por su facilidad en el

manejo computacional. Por otro lado, se busca evitar algunas de sus limitaciones mediante

el algoritmo modificado de Euler con control de errores. En este sentido, algunos de los

algoritmos alternativos se basan en la corrección arbitraria de los estados de esfuerzos

que se encuentran por fuera de la superficie de fluencia, para tal caso se “obliga” a que en

dichos puntos de integración los esfuerzos cumplan con una función de fluencia, muchas

veces Mohr-Coulomb, dicha corrección puede generar vectores fuerza de cargas

desbalanceadas o residuales muchas veces difíciles de tratar.

En el numeral 3.5.2 se describe el algoritmo de integración de esfuerzos modificado de

Euler, el objetivo de este algoritmo es que una vez determinadas las deformaciones en el

dominio del problema debido a acciones externas se deben estimar sus esfuerzos

correspondientes, así pues, en primera instancia se debe conocer qué porción del

incremento de esfuerzos produce una respuesta elástica y la porción restante se calcula

mediante iteraciones propias del algoritmo.

Page 69: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 49

3.5.2 Algoritmos de integración de esfuerzos.

Por lo regular estos métodos pueden ser clasificados en dos categorías: de un solo paso

y de múltiples pasos (Gear, 1971). Los primeros desarrollan la solución basándose en

información de un solo paso, mientras que los segundos usan información que se ha

generado en los pasos anteriores. En este último tipo se encuentran los algoritmos de

subpasos (Sloan, 1987) y del retorno (Borja, 1991). Se reconoce que la metodología de

Sloan ofrece ventajas en cuanto a su implementación.

Así pues, la formulación de subpasos tiene algunas variantes, entre ellas, el algoritmo

modificado de Euler con control de errores y el esquema de integración de Runge–Kutta

(Sloan, 1987). Por una parte, el procedimiento que ofrece Euler es de segundo orden y el

control de errores se lleva a cabo manejando el tamaño de cada subpaso, entretanto el

esquema de Runge–Kutta maneja aproximaciones de cuarto y quinto orden, y aunque este

último presenta soluciones más precisas, requiere de la evaluación de la matriz

elastoplástica ([𝐷𝑒𝑝]) y de las relaciones de endurecimiento y ablandamiento ({𝑘}) un total

de seis veces, por lo que su costo computacional es mucho mayor (Papakaliatakis &

Simos, 1999), esta formulación fue desarrollada por England (1969).

• Determinación de la fluencia inicial:

Luego de estimar las deformaciones mediante la ecuación (3.33) para cada punto de

integración de la Tabla 3-1 se busca evaluar los esfuerzos correspondientes a esa

deformación incremental en relación a la ecuación (3.61):

{∆𝜎} = [𝐷]{∆휀} (3.61)

En donde {∆𝜎} es el vector de incremento de esfuerzos, [𝐷] es la matriz elástica y {∆휀}

es el vector de incremento de deformaciones. A su vez, el estado de esfuerzos final está

dado por la ecuación 3.65:

{𝜎} = {𝜎0} + {∆𝜎} (3.62)

En donde {𝜎} es el vector de esfuerzos finales, {𝜎0} el vector de esfuerzos iniciales y {∆𝜎}

el vector de incremento de esfuerzos. En la función de fluencia si 𝐹({𝜎0}, {𝑘}) ≤ 0 y

𝐹({𝜎0}+ {∆𝜎}, {𝑘}) ≤ 0 la totalidad del incremento tiene respuesta elástica. En

contraposición si 𝐹({𝜎0}, {𝑘}) ≤ 0 y 𝐹({𝜎0}+ {∆𝜎}, {𝑘}) > 0 se tiene que en cierta fracción

del incremento de deformaciones se alcanza el punto de fluencia y para estimarlo se puede

Page 70: Desarrollo de un laboratorio virtual de geotecnia enfocado

50 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

hacer uso de la técnica de Newton – Raphson; así pues, denotando esta fracción con la

cantidad escalar 𝛼 se tiene la ecuación (3.63).

𝐹({𝜎0} + 𝛼{∆𝜎}) = 0 (3.63)

La relación de 𝐹 y 𝛼 se esquematiza en la Figura 3-20 en ella 𝑝′ corresponde al esfuerzo

medio efectivo y 𝑞′ es el esfuerzo desviador.

Figura 3-20: Representación de 𝛼

Nombre de la fuente: elaboración propia

Para hallar el valor de 𝛼 se usa el método secante de Newton-Raphson, mostrado en la

ecuación (3.64) y la interpretación geométrica del esquema secante aparece en la Figura

3-21.

𝛼𝑖+1 = 𝛼𝑖 −𝐹({𝜎0} + 𝛼𝑖{∆𝜎}, {𝑘})

𝐹({𝜎0} + 𝛼𝑖{∆𝜎}, {𝑘}) − 𝐹({𝜎0} + 𝛼𝑖−1{∆𝜎}, {𝑘})(𝛼𝑖 + 𝛼𝑖−1) (3.64)

Figura 3-21: Interpretación geométrica del esquema secante de Newton – Raphson.

Nombre de la fuente: adaptado de Universidad de Valencia, (1998).

En donde 𝛼0 = 0 y 𝛼1 = 1. Luego de determinar el valor de 𝛼 los incrementos de esfuerzos

y deformaciones elásticas corresponden a las siguientes ecuaciones:

Page 71: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 51

{∆𝜎𝑒} = 𝛼{∆𝜎} (3.65)

{∆휀𝑒} = 𝛼{∆휀} (3.66)

La porción del incremento correspondiente a (1 − 𝛼){∆휀} está controlada por la matriz

elastoplástica [𝐷𝑒𝑝], esta matriz debe integrarse a lo largo de las deformaciones

elastoplásticas, para ello estas últimas deben dividirse en partes que constituyen los

subpasos que le dan el nombre al algoritmo. En este punto entran en juego los esquemas

de integración de Euler modificado con control de errores y de Runge – Kutta.

• Algoritmo modificado de Euler

Este procedimiento parte de dividir la totalidad de la deformación elastoplástica en partes

de tamaño ∆𝑇(1 − 𝛼){∆휀}, con ∆𝑇 variando en 0 < ∆𝑇 ≤ 1, la influencia de estas

deformaciones se esquematiza en la Figura 3-22. Así pues, el tamaño de cada paso está

determinado mediante la estimación del error en el cambio de esfuerzos y su comparación

con un valor de tolerancia 𝑆𝑆𝑇𝑂𝐿. El procedimiento se describe a continuación:

1) Generación de los parámetros iniciales, en donde se asume que solamente se

requiere un subpaso, en otras palabras, que ∆𝑇 = 1 ecuaciones (3.67) a (3.70).

{𝜎} = {𝜎0} + {∆𝜎𝑒} (3.67)

{∆휀𝑠} = (1 − 𝛼){∆휀} (3.68)

𝑇 = 0 (3.69)

∆𝑇 = 1 (3.70)

Como es demarcado por Nayak y Zienkiewicz (1972), la precisión de este método es

mejorada si el paso ∆𝑇 = 1 es dividido en un número de pasos más pequeños de igual

tamaño. Por otro lado, este método también asume que dentro de un subpaso todas las

componentes del tensor de deformaciones varían en la misma proporción.

Figura 3-22: Reconocimiento de las deformaciones elastoplásticas

Page 72: Desarrollo de un laboratorio virtual de geotecnia enfocado

52 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Nombre de la fuente: elaboración propia.

2) Se acepta que en los subpasos la deformación correspondiente es de la forma de

la ecuación (3.71).

{∆휀𝑠𝑠} = ∆𝑇{∆휀𝑠} (3.71)

Y a partir de ellas se determina la primera aproximación de Euler (ecuación (3.72)).

{∆𝜎1} = [𝐷𝑒𝑝({𝜎}, {𝑘})]{∆휀𝑠𝑠} (3.72)

Nota: Para el criterio de fluencia de Drucker-Prager el parámetro de estado ({𝑘})es

independiente del estado de esfuerzos; por lo que inherentemente modela plasticidad

perfecta. Así pues, en el numeral 3.4.8 se trata esta cuestión y se añade una proposición

bajo la cual se puede hacer variar a una función del parámetro de estado respecto a la

pendiente de la curva esfuerzo-deformación en la región de deformaciones elastoplásticas,

añadiéndole así la capacidad de representar materiales que endurecen por deformación.

3) Usando la suposición de {∆𝜎1} se realiza una segunda estimación de la misma

variable (3.73).

{∆𝜎2} = [𝐷𝑒𝑝({𝜎 + ∆𝜎1}, {𝑘})]{∆휀𝑠𝑠} (3.73)

4) Mediante los resultados de las ecuaciones (3.72) y (3.73) se obtiene una mejor

aproximación de los cambios de esfuerzos en (3.74).

{∆𝜎} = 1/2({{∆𝜎1} + {∆𝜎2}}) (3.74)

5) Un acercamiento al error local del subpaso (ecuación (3.75)), se puede hacer al

sustraer las dos aproximaciones de los esfuerzos de las ecuaciones (3.72) y (3.73).

𝐸 ≈ 1/2({∆𝜎2} − {∆𝜎1}) (3.75)

Y una opción del error relativo del subpaso a comparar con el criterio de tolerancia (𝑆𝑆𝑇𝑂𝐿)

queda supeditada a la ecuación (3.76).

𝑅 =‖𝐸‖

‖{𝜎 + ∆𝜎}‖ (3.76)

Para los casos en que 𝑅 > 𝑆𝑆𝑇𝑂𝐿, se debe disminuir el tamaño del incremento del

subpaso, así pues, en la ecuación (3.77) se hace uso del escalar 𝛽 .

Δ𝑇𝑛𝑒𝑤 = 𝛽Δ𝑇 (3.77)

Este escalar 𝛽 es una medida del error local el cual es de segundo orden 𝑂(∆𝑇2) según la

ecuación (3.74) y, puede utilizarse para truncar el error local en un paso posterior de

acuerdo a la ecuación (3.78).

Page 73: Desarrollo de un laboratorio virtual de geotecnia enfocado

Revisión teórica 53

‖𝐸𝑛𝑒𝑤‖ = 𝛽2‖𝐸‖ (3.78)

A su vez puede estimarse mediante el control de errores por medio de la ecuación (3.79)

𝛽 = 0.8 [𝑆𝑆𝑇𝑂𝐿

𝑅]1/2

(3.79)

6) Entretanto si 𝑅 < 𝑆𝑆𝑇𝑂𝐿 los esfuerzos acumulados y las deformaciones plásticas

son se actualizan con las ecuaciones (3.80) y (3.81).

{𝜎} = {𝜎} + {∆𝜎} (3.80)

{휀𝑝} = {휀𝑝} + {∆휀𝑝} (3.81)

Una vez establecidos el estado de esfuerzos y las deformaciones plásticas se verifica que

se cumpla con el criterio de fluencia, en caso de no cumplirla se puede corregir el

corrimiento de la superficie de fluencia de acuerdo con Potts y Gens (1985), por otro lado,

el problema puede solventarse disminuyendo el tamaño del subpaso y volviendo al paso

2.

7) Finalmente, el proceso termina cuando 𝑇 = 1

𝑇 = 𝑇+ Δ𝑇 (3.82)

Page 74: Desarrollo de un laboratorio virtual de geotecnia enfocado

54 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 3-23: Diagrama de flujo del algoritmo modificado de Euler.

Nombre de la fuente: elaboración propia.

No

Magnitud total de las deformaciones elastoplásticas

Magnitud de deformación tomada para el subpaso i

Primera aproximación al estado corregido de esfuerzos.

Mejor aproximación de Euler al estado corregido de esfuerzos.

a

a

No

Fin.

Segunda aproximación al estado corregido de esfuerzos.

Inicio

Estimación del error local (E) y el error relativo (R).

Inicia el subpaso i.

Actualización de las variables acumuladas.

?

Page 75: Desarrollo de un laboratorio virtual de geotecnia enfocado

4. Metodología y actividades desarrolladas

En este capítulo se describen las estrategias y herramientas utilizadas en el desarrollo del

código computacional, estas comprenden: el módulo para realizar la discretización, el

análisis por elementos finitos y el desarrollo de la interfaz del programa. Adicionalmente se

exponen algunas implicaciones referentes a la modelación edométrica acoplada.

4.1 Desarrollo del modelo triaxial

Algunos pasos importantes en la programación del modelo triaxial incluyen:

1) La implementación del núcleo de las funciones de forma y de las matrices de

interpolación de desplazamientos de cada uno de los elementos.

2) La construcción de las matrices de rigidez elementales.

3) El ensamblaje de la matriz de rigidez global mediante el método directo de la

rigidez, en este se suman los aportes de los elementos a cada grado de libertad.

4) La modificación de esta matriz de acuerdo con las condiciones de frontera, en

cuanto a desplazamientos que son cero y los que se encuentran en “contacto con

el cabezal”, en donde deben darse los mismos desplazamientos, estos últimos se

conocen como desplazamientos acoplados o enlazados “tied displacement”.

5) El cálculo de los esfuerzos debidos a las deformaciones estos deben cumplir con

la función de fluencia por lo que se hace necesaria la codificación del algoritmo de

integración de esfuerzos modificado de Euler.

4.1.1 Discretización

Mientras que el proceso clave de la discretización de la geometría es relegado al código

libre denominado Pycalculix, el resto del proceso inherente al MEF es codificado en Python

y constituye el producto principal de este trabajo. Por su parte, Pycalculix es una librería

para automatizar y construir modelos por elementos finitos con aplicación en análisis

Page 76: Desarrollo de un laboratorio virtual de geotecnia enfocado

56 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

estructural, asimismo, algunas de sus características son su código abierto y la ausencia

de una interfaz gráfica, sumado a esto, también busca facilitar el aprendizaje del MEF

(Black, 2014).

Pycalculix no ofrece una interfaz gráfica de trabajo, sino código plano que entre otras

facilita el uso y la comprensión del proceso de mallado, este el procedimiento de

discretización correspondiente a un algoritmo no estructurado1 2D basado en el algoritmo

Delaunay, en donde nuevos puntos son insertados en el circuncentro del elemento que

tiene el circunradio más grande de manera iterativa. Este algoritmo muestra ser mucho

más rápido que otras opciones cuando se requiere una cantidad considerable de

elementos además de presentar un alto grado de robustez. El uso de este algoritmo no

estructurado se justifica ya que permite más configuraciones de los elementos en los que

se discretiza, es decir, no se limita a generar mallas que muestran un patrón ordenado,

sino que se pueden tener casos como el de la Figura 4-1 para la malla no estructurada.

Figura 4-1: Ejemplo de (a) malla estructurada y (b) malla no estructurada.

Nombre de la fuente: Modificado de NASA, (1993).

1 Un algoritmo no estructurado aborda mallados no estructurados, estos son discretizaciones en donde la distribución y tamaño de los elementos no tienen o siguen patrón determinado. Este tipo de algoritmo se usa ya que puede generar mayor densidad de elementos en lugares de interés dentro de la geometría.

Page 77: Desarrollo de un laboratorio virtual de geotecnia enfocado

Modelo acoplado de consolidación 57

4.1.2 Modelo interno

En la generación de la matriz de rigidez global del sistema se toma la numeración generada

por Pycalculix, dado que esta busca una numeración que disminuya el ancho de banda de

la matriz de rigidez, lo ideal es minimizar la longitud del ancho de banda dado que este

influye de manera directa en el tiempo que toma la solución del sistema lineal.

Para la programación de estas rutinas el principio de herencia en el lenguaje de

programación juega un papel destacable, por ejemplo, cantidades ya calculadas pueden

ser reutilizadas al llamar a un atributo de una clase o elemento de menor jerarquía, así

pues, los resultados anidados pueden reducir el tiempo de cálculo en procesos que pueden

ser dispendiosos y costosos en cuanto a tiempo de máquina se refiere.

En esta implementación se usa el método directo de la rigidez, este comprende la

generación de la matriz de rigidez del sistema a partir de las matrices de los elementos. El

procedimiento se rige por la numeración de los grados de libertad en los nodos que

comprenden la geometría. En primera instancia la matriz rigidez global tiene tantas filas y

columnas como grados de libertad haya en el modelo, por otra parte, cada uno de los

nodos de los elementos tienen una numeración local (respecto al elemento en sí), y una

global. Así pues, aplicando este recurso para todos los elementos dentro de la malla de

discretización y sabiendo qué grados de libertad son influenciados por qué elemento su

contribución se suma a la matriz de rigidez.

Para la construcción de las matrices de interpolación de desplazamientos se deben

organizar los nodos de los elementos de forma contra-horaria, dado que esto es un

requisito teórico para desarrollar los procesos de integración.

La modificación del sistema lineal de ecuaciones para incluir las condiciones de contorno,

en primera instancia, puede limitarse a eliminar aquellos grados de libertad en los que se

sabe que los desplazamientos son cero, estos pueden tratarse eliminándolos y

guardándolos de manera ordenada de forma tal que puedan ser utilizados para el cálculo

de las reacciones en lo que se puede denominar “los apoyos. Por otra parte, algunos

inconvenientes llegan a darse en aquellos nodos en donde se requiere que los

desplazamientos sean iguales, este es el caso de los grados de libertad en dirección

vertical en “contacto” con el cabezal de carga, el problema reside en que se deben

localizar, sumar y guardar todas sus aportaciones, de manera tal que, el desplazamiento

Page 78: Desarrollo de un laboratorio virtual de geotecnia enfocado

58 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

calculado en ese lugar sea debido a la carga que actúa en todos y cada uno de esos grados

de libertad.

En la solución de estos sistemas lineales de ecuaciones se opta por usar un procedimiento

óptimo para matrices dispersas, este consiste en que los valores nulos pueden ser

ignorados y no se tiene la necesidad de invertir la matriz de rigidez dado que esta inversa

se usaría en tan solo una ocasión; por lo que los recursos invertidos encontrando la inversa

no compensan el poco uso que se le da. La solución alterna se da a partir de soluciones

iterativas a partir de álgebra lineal, así pues, la librería de Python utilizada para este fin es

scipy.sparse.

Los algoritmos de subpasos (Sloan, 1987) y del retorno (Borja, 1991) ofrecen alternativas

para realizar la integración de las relaciones constitutivas a lo largo de la trayectoria de

deformaciones, en síntesis, en este marco de referencia se busca evitar el cálculo de

estados ilegales de esfuerzos, es decir, estados por “fuera” de la superficie de fluencia.

Aunque los dos proveen soluciones precisas, debido a la complejidad extra ligada a la

implementación del procedimiento de Borja y su complicación con ciertos modelos

constitutivos se prefiere el uso del algoritmo de subpasos modificado de Euler (Potts &

Ganendra, 1994).

Las dificultades para el algoritmo de integración de esfuerzos se dan porque existen casos

ambiguos, estos se general cuando el estado inicial de esfuerzos en cualquier incremento

representa fluencia y las trayectorias se configuran de acuerdo a la Figura 4-2, en ese caso

las medidas tomadas se asocian a la dirección del incremento de esfuerzos calculando la

cantidad𝜕𝐹

𝜕𝜎Δ𝜎, si el resultado es positivo se da el caso (a) y 𝛼 = 0 es decir, la totalidad del

incremento es elastoplástico, en caso de ser negativo se procede a determinar el valor de

𝛼, en otras palabras, se busca qué fracción del cambio de esfuerzos tiene respuesta

elástica.

En la inclusión del parámetro de endurecimiento (𝐻′) del material en caso de no ser

ingresado de una manera correcta, es decir, para valores bajos de esfuerzo altos valores

de 𝐻′ y viceversa, el programa se encarga de organizarlos para poder interpolar los valores

que se necesiten en los análisis en ejecución, esta organización corresponde a la función

sort en arreglos numéricos o vectores en Python.

Page 79: Desarrollo de un laboratorio virtual de geotecnia enfocado

Modelo acoplado de consolidación 59

Figura 4-2: Estados iniciales de esfuerzos que implican ambigüedad.

Nombre de la fuente: Potts & Zdravkovic, (1999).

En cuanto al cumplimiento del segundo objetivo específico se ofrece el archivo

ejemploTRX.mqb donde se especifica un proyecto con valores ejemplo de todas las

variables, este puede ser ejecutado y las variables de entrada son susceptibles de ser

alteradas con la finalidad de ver cuál es su inferencia en los resultados. Los resultados se

ofrecen en términos de la Figura 4-3.

Para la calibración del modelo, el análisis se realiza de manera similar a lo mencionado en

el anterior párrafo, es decir, diferentes casos en los que se varía de manera independiente

las variables de entrada del modelo.

De esta manera se vislumbra la operación general del código, por otra parte, la

organización y operación de este se detalla en el capítulo de 5”. El estudio de los resultados

provistos por el código incluye ejercicios que se muestran en el capítulo número 6, por una

parte, se realiza la corroboración de algunos resultados aportados por este modelo y por

otra, se muestra cómo influyen en estos resultados la variación de los parámetros de

entrada, estos datos incluyen:

1) El módulo de Young E

2) La relación de Poisson.

3) El número de incrementos en los que se divide la carga.

4) El tamaño de los elementos finitos.

5) La cohesión.

6) El ángulo de fricción interna.

Page 80: Desarrollo de un laboratorio virtual de geotecnia enfocado

60 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 4-3: Resultados típicos para un ensayo triaxial drenado.

Nombre de la fuente: elaboración propia.

4.1.3 Interfaz gráfica

La interfaz gráfica se diseña mediante un software libre para construir ventanas de usuario

a partir de scripts, este es conocido como Qtdesigner y, aunque permite el diseño de

interfaces que incluyen ventanas y desplegables de ingreso de datos y de ayuda, todos

estos elementos gráficos deben adecuarse y estructurarse junto a un código con el que se

haga el manejo y operación de proyectos, de esta manera se permite que se pueda

acceder a funciones como guardar, abrir y por su puesto editar, esto último realiza

mediante contenedores de datos. El contenedor de este ensayo transforma y guarda los

datos en cadenas de bytes de manera directa sin necesidad de realizar conversión de

dicha información; el formato de estos archivos es “.mqb”. La interfaz de trabajo que

suministra Qtdesigner se puede verificar en la Figura 4-4 en ella se pueden generar tanto

los botones como las opciones del menú, pero solamente desde un sentido estético, es

decir, su funcionalidad queda definida tanto por el contenedor como por el código principal

del programa.

En este sentido, la literatura consultada para lograr su aplicación computacional se

resumen los libros de Zelle (2004) y Summerfield (2007), el primero con énfasis en la

Page 81: Desarrollo de un laboratorio virtual de geotecnia enfocado

Modelo acoplado de consolidación 61

programación en Python con aplicación a las ciencias y el segundo enfocado en la

adecuación y el manejo de interfaces gráficas.

La programación anterior se hace con miras en cumplir el primer objetivo específico, es

decir, la ejecución de una simulación del ensayo de compresión axial, esta se hace en el

marco de una interfaz que junto con un panel integrado de ayuda brinda información sobre

la ejecución del ensayo. Es importante que este panel sea visible y debe ubicarse en la

barra de menú (Figura 4-5). Así pues, la aplicación computacional se encamina en la

consecución de ejercicios del ensayo en cuestión, de esta manera en el subtítulo 5.2.3 se

proponen casos de análisis y ejercicios de ejecución rápida por parte de los usuarios.

En este punto, se opta por realizar dos interfaces de trabajo, la primera enfocada en la

construcción del modelo por parte del docente y la segunda en donde se puede reconocer

el ensayo, cambiar las condiciones de carga, el peso unitario de la muestra, determinar su

volumen inicial, realizar el proceso de discretización, ejecutar el modelo, obtener los

resultados para finalmente calcular los parámetros de resistencia con el que el educador o

guía alimentó al proyecto del software.

Para la interpretación de los resultados de la simulación del ensayo triaxial se hace uso de

las herramientas para gráficas (plot) de Python. Por su parte el volumen se determina como

un sólido de revolución con la fórmula para este fin del cálculo integral, para ello se usan

las coordenadas de los lados de los elementos triangulares en la frontera lateral de la

geometría, esta formulación es dada por la ecuación (4.1) en donde 𝑎 y 𝑏 son las

coordenadas horizontales de los lados de los elementos en cuestión.

𝑣 = 𝜋∫[𝑓(𝑥)]2𝑑𝑥

𝑏

𝑎

(4.1)

Page 82: Desarrollo de un laboratorio virtual de geotecnia enfocado

62 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 4-4: Interfaz de trabajo de Qtdesigner

Nombre de la fuente: elaboración propia.

Figura 4-5: Barra de menú propuesta para el ensayo triaxial

Nombre de la fuente: elaboración propia.

4.2 Desarrollo del modelo acoplado de consolidación

Los análisis de la relación esfuerzo deformación en suelos pueden catalogarse dentro del

espectro que definen los comportamientos drenado y no drenado, estas dos situaciones

son válidas para la solución de diversos problemas, por ejemplo, en el estudio de la

Page 83: Desarrollo de un laboratorio virtual de geotecnia enfocado

Modelo acoplado de consolidación 63

estabilidad de taludes de corte se puede tomar una combinación de los dos acercamientos,

es decir, el estado no drenado a corto plazo y el estado drenado a largo plazo.

Dado que el comportamiento mecánico está relacionado con el tiempo, se puede entrever

que es deseable que las ecuaciones de flujo sean combinadas con las ecuaciones de

equilibrio y constitutivas (Potts & Zdravkovic, 1999). En el modelo trabajado se acoplan los

desplazamientos y las presiones en los nodos de los elementos a través de los principios

de la mínima energía potencial y del trabajo virtual (Borja et al., 1999). Investigaciones

pioneras para desarrollar el análisis de la difusión transitoria de fluidos en medios porosos

convergen en los conceptos generados por Terzaghi y Biot, estos autores lidiaron con

condiciones unidimensionales y tridimensionales respectivamente (Terzaghi, 1943), (Biot,

1941).

Por su parte, algunos problemas de flujo son tratados en términos de solo una variable

dependiente, por ejemplo, el exceso de presión de poros y la temperatura, y sus soluciones

implican la existencia de sólo un grado de libertad por nodo en la malla de elementos finitos.

Aunque esta aproximación llega a ser aceptable, en muchos casos pueden abordarse

problemas en los que se generen diversos grados de libertad en el mismo nodo, dado que

las variables dependientes son “acopladas” o aparecen en las mismas ecuaciones

diferenciales (Smith et al., 2014). En síntesis, el término acoplado se encuentra asociado

con análisis en los que las variables dependientes no son del mismo tipo (Griffiths, 1994).

4.2.1 Consideraciones de Biot

Los problemas de mecánica deben considerar la aplicación y el cumplimiento de las

ecuaciones de equilibrio, las relaciones constitutivas del material y de las condiciones de

compatibilidad de desplazamientos. En este sentido, Biot generaliza el mecanismo de

consolidación unidimensional propuesto por K. Terzaghi asumiendo las siguientes

condiciones:

1) Isotropía del material.

2) Reversibilidad de las relaciones esfuerzo deformación bajo procesos de carga

y descarga.

3) Relación lineal entre esfuerzos y deformaciones.

4) Pequeñas deformaciones.

5) Fluido intersticial incompresible.

Page 84: Desarrollo de un laboratorio virtual de geotecnia enfocado

64 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

6) El agua puede contener burbujas de aire.

7) El agua fluye a través del esqueleto del suelo de acuerdo con la ley de Darcy.

Así pues, el autor reconoce que los puntos 2 y 3 son los que más pueden ser objeto de

crítica, pero que, al compararlo con los buenos resultados obtenidos en la aplicación de la

ya mencionada teoría de Terzaghi y que, según la sedimentación de las partículas

coloidales y el cumplimiento del principio de mínima energía potencial en dicho proceso,

bajo pequeñas deformaciones, es decir en condiciones de poca perturbación el concepto

de reversibilidad puede ser aplicable (Biot, 1941).

Continuando con la discusión de la anterior lista de suposiciones, el punto 6 no es

abordado dentro de la formulación de las ecuaciones en elementos finitos, mientras que

debido a las facultades de este tipo de análisis, diferentes condiciones de anisotropía

pueden ser consideradas (punto 1). La misma observación es válida en cuanto a las

condiciones iniciales de esfuerzos y su incidencia, la cual es mayor en materiales de bajo

módulo de Young. Así pues, se puede decir que Biot formuló una teoría de la interacción

suelo-fluido y esta tiene aplicación en la mecánica de suelos (Smith & Hobbs, 1976).

El desarrollo del modelo por elementos finitos de las ecuaciones de Biot va de la mano con

las preposiciones adoptadas por este autor y es presentado de manera similar al orden de

Potts y Zdravkovic, pero con el agregado de mostrar algunos pasos intermedios que en

ese último documento no aparecen. En resumen, el esqueleto del suelo es tratado como

un sólido elástico poroso con fluido de poros laminar y, los desplazamientos y las presiones

de poros se acoplan mediante condiciones de equilibrio (trabajo virtual) y continuidad, ver

Figura 4-6 (Smith et al., 2014).

Por otro lado, es posible realizar un contraste con las ecuaciones de Navier Stokes donde

los desplazamientos del esqueleto del suelo asumen el papel de las velocidades 𝑢 y 𝑣 en

direcciones perpendiculares y el exceso de la presión de poros reemplaza a la presión de

fluido 𝑝 en la solución de las ecuaciones de Navier – Stokes (Griffiths & Smith, 1988).

Page 85: Desarrollo de un laboratorio virtual de geotecnia enfocado

Modelo acoplado de consolidación 65

Figura 4-6: Esquema de continuidad

Nombre de la fuente: elaboración propia.

4.2.2 Anotaciones sobre la estabilidad numérica del modelo acoplado de consolidación.

En el anexo A se especifica la formulación por elementos finitos de las ecuaciones de Biot

mientras que en el anexo B se explica el manejo de esas ecuaciones para incluir las

condiciones de frontera. En síntesis, lo expresado en dichos anexos puede expresarse por

medio de las ecuaciones (4.2) y (4.3).

[[𝐾𝐺] [𝐿𝐺]

[𝐿𝐺]𝑇 −𝛽∆𝑡[Φ𝐺]

] {{Δ𝑑}𝑛𝐺{∆𝑝𝑓}𝑛𝐺

} = {{∆𝑅𝐺}

{Δ𝑈𝐺}} (4.2)

La anterior formulación incluye al lado izquierdo la matriz tradicional de rigidez global

([𝐾𝐺]), la matriz de acoplamiento entre la fase líquida y sólida ([𝐿𝐺]), la matriz de

permeabilidad ([Φ𝐺]), el incremento desconocido de desplazamientos ({Δ𝑑}𝑛𝐺) y de

presión de poros ({∆𝑝𝑓}𝑛𝐺), y en la parte derecha, el vector típico de fuerzas impuestas

({∆𝑅𝐺}), y el vector incremental de flujo nodal ({Δ𝑈𝐺}).

[ [𝐾𝑢] [𝐾𝑢𝑝] [𝐿𝑢] [𝐿𝑢𝑝1]

[𝐾𝑢𝑝]𝑇

[𝐾𝑝] [𝐿𝑢𝑝2] [𝐿𝑝]

[𝐿𝑢]𝑇 [𝐿𝑢𝑝2]

𝑇−𝛽∆𝑡[Φ𝑢] −𝛽∆𝑡[Φ𝑢𝑝]

[𝐿𝑢𝑝1]𝑇

[𝐿𝑝]𝑇

−𝛽∆𝑡[Φ𝑢𝑝]𝑇

−𝛽∆𝑡[Φ𝑝] ]

{

Δ𝑑𝑢Δ𝑑𝑝Δ𝑝𝑢Δ𝑝𝑝}

=

{

Δ𝑅𝑢Δ𝑅𝑝Δ𝑈𝑢Δ𝑈𝑝}

(4.3)

La inclusión de las condiciones de frontera en (4.2) genera la ecuación (4.3) el subíndice

𝑢 indica que la cantidad es desconocida mientras que 𝑝 señala a los grados de libertad

Page 86: Desarrollo de un laboratorio virtual de geotecnia enfocado

66 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

conocidos (preestablecidos). Así pues, habiendo especificado esta información se procede

a reconocer algunos aspectos inherentes al proceso de discretizar el tiempo.

En primera medida, con la finalidad lograr la estabilidad numérica en los diferentes pasos

de cálculo, se multiplica por −1 el segundo renglón de la ecuación (4.2) o (4.3), esto es

debido a que −𝛽 afecta directamente a la diagonal principal de la matriz de rigidez ‘general’

y es deseable que esta sea de diagonal dominante (Schneider & Hans 1977). Trayendo a

colación a la ecuación (4.4).

[[𝐾𝑢] [𝐿𝑢]

[𝐿𝑢]𝑇 −𝛽∆𝑡[Φ𝑢]

] {{Δ𝑑𝑢}

{Δ𝑝𝑢}}

= {{Δ𝑅𝑢} − [𝐾𝑢𝑝]{Δ𝑑𝑝} − [𝐿𝑢𝑝1]{Δ𝑝𝑝}

{Δ𝑈𝑢} − [𝐿𝑢𝑝2]𝑇{Δ𝑑𝑝} + 𝛽∆𝑡[Φ𝑢𝑝]{Δ𝑝𝑝}

}(4.4)

Por otra parte, cabe notar que el valor del parámetro de discretización del tiempo 𝛽 y su

criterio de estabilidad proporcionado por Potts y Zdravkovic, se trata de manera alterna al

presentado en el artículo de estabilidad numérica de las ecuaciones de Biot escrito por

Booker y Small, (1975). Dado que la definición de la integral en la ecuación (4.5) también

se muestra ligeramente diferente resulta viable comparar las dos propuestas anteriores,

es decir:

Para Potts y Zdravkovic:

∫ [Φ𝐺]{𝑝𝑓}𝑛𝐺𝑑𝑡

𝑡+1

𝑡

= [Φ𝐺] [𝛽 ({𝑝𝑓}𝑛𝐺)𝑡+1

+ (1 − 𝛽) ({𝑝𝑓}𝑛𝐺)𝑡] ∆𝑡 (4.5)

Para Booker y Small:

∫ 𝑞(𝑡)𝑑𝑡

𝑡+∆𝑡

𝑡

= [𝛼𝑞(𝑡) + (1 − 𝛼)𝑞(𝑡 + ∆𝑡)]∆𝑡 (4.6)

Se llega a conocer que la relación entre las variables 𝛼 y 𝛽 de ambas propuestas es:

𝛼 = 1 − 𝛽 (4.7)

En este punto cabe aclarar que, el cambio de variable de 𝛼 a 𝛽 se hace con el propósito

de dejar las cantidades conocidas de presión de poros en el vector general de fuerzas de

la ecuación (4.4).

Asimismo, es necesario un 𝛽 ≥ 0.5 o 𝛼 < 0.5 Dado el caso de no cumplir con este

requerimiento, se hace necesario establecer un valor de convergencia para los valores de

∆t el cual está dado por la ecuación (4.8) (Booker & Small, 1975):

Page 87: Desarrollo de un laboratorio virtual de geotecnia enfocado

Modelo acoplado de consolidación 67

∆𝑡 ≤ 𝑚𝑖𝑛𝑗 {1

𝜆𝑗(𝛼 − 1/2)} (4.8)

Donde 𝜆𝑗 representa a valores propios de la matriz de rigidez general ([𝐾𝐺]).

En cuanto a la forma en que se aplica la carga, se usa el esquema basado en una carga

en forma de rampa, en donde la totalidad es aplicada en el tiempo cero del análisis, dicha

carga puede esquematizarse mediante la Figura 4-7.

Figura 4-7: Carga en forma de rampa.

Nombre de la fuente: adaptado de Smith, Griffiths, & Margetts, (2014).

4.2.3 Pasos de análisis

De igual manera al procedimiento triaxial, la discretización de la geometría en el modelo

acoplado también es relegado a Pycalculix, mientras que el resto del proceso inherente al

MEF es codificado en Python.

Algunos pasos importantes en la programación del modelo triaxial incluyen:

1) La implementación de las funciones de forma para el elemento triangular lineal y

de las matrices de interpolación de desplazamientos de cada uno de los elementos.

2) La construcción de las matrices de rigidez elementales

3) El ensamblaje de la matriz de rigidez global mediante el método directo de la rigidez

en donde se suman los aportes de los elementos a cada grado de libertad

4) La modificación de esta matriz de acuerdo con las condiciones de frontera, en

cuanto a desplazamientos los que son cero y los que se encuentran con la placa

de carga por lo que allí deben darse los mismos desplazamientos, estos últimos se

conocen como desplazamientos acoplados.

Page 88: Desarrollo de un laboratorio virtual de geotecnia enfocado

68 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

5) Para realizar la interpretación en términos de los resultados del ensayo edométrico

se codifica la gráfica que incluye la curva de consolidación para cada carga.

El estudio de los resultados provistos por el código incluye ejercicios que se muestran en

el capítulo de 6, por una parte, se realiza la verificación de la implementación mediante el

estudio de la consolidación en material arcilloso alrededor de un dren en condiciones

axisimétricas y por otra, se construye la curva de consolidación para un ensayo edométrico

y se analiza el tiempo que toma el proceso consolidación.

La interfaz planteada en este apartado se maneja de manera similar a la adoptada en el

análisis triaxial, de esta manera también incluye una sección de ayuda que informa sobre

los datos de entrada y los pasos a seguir durante el análisis.

Luego de aplicada una carga y disipadas las presiones de poros se busca que sea posible

aplicar el siguiente incremento de carga sobre la geometría ya deformada. Mientras que la

interpretación de resultados se logra mediante la construcción de la curva de consolidación

para una carga de análisis, de manera adicional la distribución de la presión de poros al

interior de esta y el tiempo de análisis se puede observar en la terminal de Python, un

ejemplo de esto último se muestra en la Figura 4-8.

Page 89: Desarrollo de un laboratorio virtual de geotecnia enfocado

Modelo acoplado de consolidación 69

Figura 4-8: Ejemplo de distribución de presión de poros para el ensayo edométrico.

Nombre de la fuente: elaboración propia.

De manera complementaria a la curva de consolidación se provee la disminución de la

presión de poros en el centro de la muestra en función del factor tiempo adimensional, este

valor adimensional es utilizado para realizar la discretización del tiempo, esta figura hace

parte de los datos que se presentan en la interfaz de consolidación (Figura 4-9). El proyecto

ejemplo de estudio para la simulación del ensayo edométrico también tiene el formato

“.mqb”, es decir, también es una cadena de bytes, el nombre de este archivo es

”ApruebaCons.mqb”.

La Figura 4-9 da cuenta del efecto Mandel – Cryer, es decir, la disipación de presión de

poros no es dominante en todo el proceso, sino que, puede haber un aumento debido a la

respuesta no monotónica del sistema (Holzbecher, 2016). Este efecto es común a todos

análisis de este tipo y puede observarse de nuevo en el numeral 6.2.2.

Page 90: Desarrollo de un laboratorio virtual de geotecnia enfocado

70 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 4-9: Disminución de la presión de poros al interior de la muestra.

Nombre de la fuente: elaboración propia.

4.2.4 Grado promedio de consolidación

Esta definición es usada en los análisis de la condición axisimétrica respecto al problema

del dren central, el grado de consolidación (𝑈𝑎𝑣) es calculado en cualquier elevación 𝑧, 𝑈𝑎𝑣

se puede realizar haciendo la integral desde el radio del dren 𝑟𝑤 hasta el radio exterior 𝑟𝑒

de acuerdo a la ecuación (4.9):

𝑈𝑎𝑣(𝑧) =1

𝜋(𝑟𝑒2 − 𝑟𝑤

2)∫

𝑢𝑜(𝑟, 𝑧) − 𝑢(𝑟, 𝑧)

𝑢𝑜(𝑟, 𝑧)2𝜋𝑟𝑑𝑟

𝑟𝑒

𝑟𝑤(4.9)

En donde 𝑢𝑜(𝑟, 𝑧) y 𝑢(𝑟, 𝑧) son la presión de poros ambiente y la presión de poros calculada

en un punto (𝑟, 𝑧), respectivamente. A su vez, el grado promedio de consolidación (𝑈𝑝) es

calculado usando los valores de 𝑈𝑎𝑣 en diferentes puntos a lo largo de la altura de la

columna de suelo, esta operación se hace de acuerdo con la ecuación (4.10).

𝑈𝑝(𝑡) =1

𝐻∫ 𝑈𝑎𝑣(𝑧)𝑑𝑧𝐻

0(4.10)

Page 91: Desarrollo de un laboratorio virtual de geotecnia enfocado

5. Desarrollo y organización de los códigos computacionales

A continuación, se explica de manera general la organización de los códigos

computacionales implementados en la elaboración de este trabajo de grado. En primer

lugar, se muestra la estructura del modelo acoplado y su interfaz. Por otra parte, se expone

el alcance de las interfaces de usuario para el ensayo triaxial, estas interfaces se

diferencian ya que una está enfocada en la construcción del modelo por parte del docente,

y la otra, en la interpretación y el cálculo de los parámetros de resistencia a partir de los

resultados, esta última va dirigida a los estudiantes. Finalmente, se proponen los ejercicios

para los alumnos.

5.1 Estructura para el modelo acoplado de consolidación

Para lograr la discretización de la geometría de manera que la numeración de los nodos

sea óptima en cuanto al ancho de banda de la matriz de rigidez global [𝐾𝐺], se hace uso

de la API pycalculix de Python que a su vez utiliza el módulo de discretización (meshing)

del software libre Gmsh realizado bajo los lineamientos de la GNU ‘General Public License’

GPL.

De la Figura 5-1 se permite conocer que la estructura1 de más alta jerarquía en cuanto al

modelo de análisis se refiere es la clase ‘Multiple_times’ del módulo ‘multiple_times.py’ y

puede entenderse como el núcleo de funcionamiento del programa:

1 Refiérase a la definición de ‘class’ en el lenguaje Python

Page 92: Desarrollo de un laboratorio virtual de geotecnia enfocado

72 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 5-1: Estructura adoptada para realizar el análisis incremental mediante las ecuaciones de Biot.

Nombre de la fuente: elaboración propia.

▪ multiple_times, en primera medida está encargado de hacer llamadas a los

módulos global_stiffness_matrix y global_force_vector para la construcción de las

Programa:

Luego de ejecutado el programa y al crear un nuevo proyecto se le pide al usuario que ingrese los datos característicos del modelo a analizar; estas variables se dividen en geométricas, físicas, mecánicas e hidráulicas, además se incluye un parámetro clave para la discretización de la geometría que consiste en el tamaño deseado y posible de los elementos que componen la malla.

El softwarese encarga

de almacenar los datos y resultados

pertinentes al nuevo

proyecto, mediante el

módulo 'container.py'

Discretización, haciendo

uso de gmsh como una función de

'feamodel.py'

Una vez realizado el mallado de la geometría del problema se procede a ejecutar el análisis mediante la formulación por elementos finitos de las ecuaciones de Biot.

'multiple_times.py' es

invocado

Las tareas de 'multiple_times.py' consisten en ejecutar y recibir los resultados en su respectivo orden de:

1. global_stiffness_matrix .py

2. global_force_vector.py

3. a. modified_matrix.py y b. modified_vector.py

4. solve_in_time.py

5. calc_quanities.py (se explica más adelante)

6. plot.py (se explica más adelante)

1 y 2 construyen las

matrices y vectores

generales según la ecuación

( 2.5 )

3. a y b leen las condiciones de

frontera y modifican las

matrices y vectores

generales del sistema

4 encuentra la solución para

un paso dentro del sistema incremental.

Page 93: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 73

distintas matrices globales, como segundo atributo invoca a los módulos que las

editan de acuerdo con las condiciones de frontera, en tercera instancia mediante el

uso de solve_in_time adquiere los resultados de determinado paso de la marcha

en el tiempo y modifica las coordenadas de los nodos luego de saber dichos datos.

Por último, tiene la habilidad de generar las gráficas de los diferentes campos

calculados, entre ellos las deformaciones y esfuerzos en las diferentes direcciones

y las presiones de poros.

▪ solve_in_time, recibe las matrices modificadas de multiple_times, ensambla la

matriz y el vector del sistema general2 que se muestra en la ecuación (B.3) y

resuelve un paso en particular.

En la Figura 5-2, Figura 5-3, Figura 5-4, Figura 5-5, Figura 5-6 se examina la expansión de

las características y operación de ‘multiple_times.py’.

Figura 5-2: Módulo encargado de la construcción de las matrices globales de la forma

débil del problema analizado.

Nombre de la fuente: elaboración propia.

2 Para este problema la matriz de rigidez del sistema acoplado es denominada matriz general.

glo

ba

l_stiff

ne

ss_

ma

trix

.py

Para todos los elementos determina las matrices elementales [KE], [ΦE] y

[LE] invocando a 'element_matrix.py'

'element_matrix.py' para cada elemento en particular hace

uso de 'jacobian.py' y 'element_shape_matrices.py'

'jacobiano.py' determina la matriz jacobiana de

transformación de coordenadas globlales a

naturales (L1, L2)

'element_shape_matrices.py' genera las matrices

[B] y [E].

Para contruir [E] se utiliza además el módulo

'integration_points.py' que permite realizar la

integración numérica en el sistema coordenado (L1, L2). Con el mismo objetivo 'ccw_format.py' organiza los nodos del elemento de manera

contrahoraria.

Ensambla las matrices globales [KG], [ΦG] y [LG] a partir de los valores de las matrices elementales usando el método directo

de la rigidez

Page 94: Desarrollo de un laboratorio virtual de geotecnia enfocado

74 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Siguiendo con este desarrollo:

▪ global_stiffness_matrix, al igual que global_force_vector, es decir, de

acuerdo con la cantidad total de grados de libertad, tiene como tarea la

construcción de las matrices globales [𝐾𝐺], [𝐿𝐺] y [Φ𝐺].

▪ element_matrix, encargado de construir las matrices [𝐾𝐸], [𝐿𝐸] y [Φ𝐸] para

cada uno de los elementos según las ecuaciones (A.22), (A.23), (A.34) y (A.35).

▪ jacobiano, dadas las coordenadas globales, es decir,(𝑥, 𝑦)de los nodos de un

elemento, devuelve la matriz jacobiana de transformación de coordenadas

hacia el sistema coordenado natural (𝐿1, 𝐿2).

▪ element_shape_matrices, responsable de ensamblar las matrices [𝐵] y [𝐸], al

recibir el llamado de los módulos element_matrix y element_force_vector

▪ integration_points, indica los puntos de integración en coordenadas naturales

(𝐿1, 𝐿2) para el elemento triangular lineal, sobre dichos puntos se realizan

algunos procesos de integración.

▪ ccw_format, en diferentes pasos del proceso es necesario que los nodos de

cada uno de los elementos sean organizados en forma contra horaria (ccw:

‘counterclockwise’).

Page 95: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 75

Figura 5-3: Módulos encargados de la construcción de los vectores globales de la forma

débil del problema de consolidación acoplado.

Nombre de la fuente: elaboración propia.

▪ global_force_vector, según la totalidad de grados de libertad, sumados

desplazamientos y presiones poros, construye el vector global de fuerzas, en

este se incluye la componente dada por {𝑛𝐺}

▪ element_force_vector, genera el vector de fuerzas, al igual que la parte

correspondiente a la presión de poros para cada uno de los elementos, es decir,

el vector {𝑛𝐸} con el cual se ensambla el vector general {𝑛𝐺}, especificado en

la ecuación (A.35).

glo

ba

l_fo

rce

_ve

cto

r.p

y

Para todos los elementos determina los vectores elementales {∆RE} y {nE}

invocando a 'element_force_vector.py'

'element_force_vector.py' para un elemento cualquiera.

Su funcionamiento es similar al de 'element_matrix.py'

Ensambla los vectores globales {∆RG} y {nG} a partir de los valores de las

vectores elementales usando el método directo de la rigidez

Page 96: Desarrollo de un laboratorio virtual de geotecnia enfocado

76 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 5-4: Módulos responsables de incluir las condiciones de frontera.

Nombre de la fuente: elaboración propia.

▪ modified_matrix, modifica las matrices globales [𝐾𝐺], [𝐿𝐺] y [Φ𝐺] obedeciendo

a los desplazamientos y presiones de poros preestablecidos (o prescritos). Para

esto genera un diccionario3 de cargas en las que se tienen en cuenta estos

desplazamientos preestablecidos. Otras modificaciones que realiza

corresponden a la consideración de cargas sobre placas rígidas que obligan a

los desplazamientos bajo ellas a tener la misma magnitud, por ejemplo, para el

ensayo drenado triaxial de compresión axial la carga axial viene dada por un

aditamento rígido que comparado con el suelo se supone indeformable

3 En Python la estructura de datos ‘dict’ referida como un diccionario permite asignar un valor (value) a una llave (key). Los datos que puede contener una llave pueden ser cadenas de texto y números mientras que el valor asignado puede ser cualquiera de las otras estructuras de datos soportados por este lenguaje. Para dar claridad, en un vector ordinario se puede acceder a los valores guardados (value) en cada uno de los índices mediante un índice en particular (key) que no puede ser alterado, por esto se puede entrever que los diccionarios aumentan en gran parte las potencialidades de los vectores ordinarios (list) al poder asignar llaves sin las restricciones de estos últimos.

mo

difie

d_

matr

ix.p

y y

mo

difie

d_

ve

cto

r.py

modified_matrix.py recibe las matrices globales y las modifica de acuerdo a las condiciones de frontera indicadas

en el modelo de elementos finitos 'feamodel.py'

modified_vector.py recibe los vectores globales y los modifica de acuerdo a las condiciones de frontera indicadas

en el modelo de elementos finitos 'feamodel.py'

Page 97: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 77

mientras que, la presión lateral de confinamiento aplicada mediante agua no

genera esta condición cinemática.

▪ modified_vector, teniendo el diccionario generado en modified_matrix, este

módulo edita el vector global de fuerzas.

Figura 5-5: Módulo que posibilita la estimación de deformaciones y esfuerzos.

Nombre de la fuente: elaboración propia.

▪ calc_quantities, dados los cambios en desplazamientos y presiones de poros

para un paso de carga dado, este módulo (o script) permite el cálculo de las

deformaciones y esfuerzos que se asumen constantes a lo largo de cada uno

de los elementos, dado que se hace uso del elemento triangular lineal.

ca

lc_

qu

an

titie

s.p

y

Una vez resuelto el sistema general para un paso particular de la marcha

en el tiempo, esta clase se encarga de calcular las deformaciones y a partir

de estos últimos los esfuerzos en cada una de las direcciones del sistema

coordenado particular del problema. También devuelve estos resultados en un formato que permite ser graficado

por 'plot.py'

Page 98: Desarrollo de un laboratorio virtual de geotecnia enfocado

78 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 5-6: Módulo utilizado para graficar los resultados.

Nombre de la fuente: elaboración propia.

▪ plot genera una gráfica de los resultados pedidos por multiple_times a

solve_in_time

5.1.1 Funcionalidad e interfaz gráfica de la simulación edométrica

Esta formulación busca optimizar el tiempo de cómputo al almacenar las matrices [𝐵] de

cada uno de los elementos para su reutilización en la determinación de los variables de

esfuerzos y deformaciones, por otra parte, debido a la reformulación de la matriz general

de rigidez para un incremento que sobrescribe la del paso anterior; de esta manera no se

presenta estancamiento debido al aumento en el requerimiento de memoria física del

hardware en el que se ejecuta el análisis.

De acuerdo con la estructura general de operación la Figura 5-7 muestra la interfaz gráfica

para la ejecución del modelo acoplado de consolidación para el ensayo edométrico.

plo

t.p

y

Genera las gráficas de los resultados pertienentes al modelo desarrollado

Page 99: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 79

Figura 5-7: Vista principal del programa de consolidación.

Nombre de la fuente: elaboración propia.

De igual manera, en la Figura 5-8 se detalla el ingreso de las variables de entrada del

modelo. En la pestaña “avanzado” se puede ingresar el tamaño del lado de los elementos

triangulares para la discretización de la geometría.

Page 100: Desarrollo de un laboratorio virtual de geotecnia enfocado

80 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 5-8: Interfaz para el ingreso de variables de consolidación poro-elástica.

Nombre de la fuente: elaboración propia.

Finalmente, la descripción del problema y las instrucciones para realizar los análisis

correspondientes a la sección “Ayuda” puede verificarse en lo dispuesto en la Figura 5-9.

Page 101: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 81

Figura 5-9: Documentación y ayuda de la aplicación de consolidación.

Nombre de la fuente: elaboración propia

5.1.2 Tiempos de ejecución del modelo acoplado de consolidación:

Los análisis han sido ejecutados teniendo en cuenta el tamaño de búsqueda del elemento,

así el número de elementos puede rondar los 300 para los tamaños de las muestras en

base a los tamaños manejados en laboratorio, así pues, los análisis toman un tiempo de

ejecución de entre 4 a 5 minutos.

Tabla 5-1: Tiempo de análisis para el modelo acoplado.

# elementos triangulares

lineales

# Nodos

Tiempo de ejecución del análisis H:M:S

100 66 00:01:53

238 143 00:03:39

900 496 00:19:12

Nombre de la fuente: elaboración propia.

Page 102: Desarrollo de un laboratorio virtual de geotecnia enfocado

82 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

5.2 Estructura del modelo de falla en condición drenada

Para discretizar la geometría en este apartado también se utiliza la API pycalculix. A

grandes rasgos la organización de este código se rige bajo el esquema presentado en la

Figura 5-10.

Algunos de los módulos que hacen parte de esta formulación se encuentran descritos en

el subtítulo correspondiente al módulo de consolidación, las diferencias que pueden

observarse consisten en los módulos nonLinear_analisis.py y

updated_lagrangean_analysis.py (Figura 5-10). El primero de ellos introduce el script

triaxial_interpretation.py que permite el cálculo de las variables macro, es decir,

deformación volumétrica, axial, cortante, etc, mientras que el segundo hace las veces de

multiple_times.py.

Dado que este es un análisis elastoplástico, tanto el cálculo de la matriz de rigidez como

la determinación de los estados de esfuerzos provisto por los códigos

global_stiffness_matrix.py y calc_quantities.py respectivamente, hacen uso de las

facultades de failure_criterion.py y matrix_Dep.py. Así pues, en la Figura 5-11 se describe

brevemente la organización de calc_quantities.py para el elemento triangular cuadrático.

La evolución en cada uno de los pasos del problema ejecutado, es decir, tanto la geometría

deformada como las gráficas de las variables 𝑝, 𝑞, 휀𝑠, 휀𝑣 y 𝑣, (por ejemplo, la Figura 4-3),

pueden verificarse fácilmente en la terminal de Python o consola de Spyder4.

4 Se recomienda el uso de este intérprete por la interfaz y ayuda gráfica que provee.

Page 103: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 83

Figura 5-10: Estructura adoptada para realizar el análisis incremental mediante para el ensayo de compresión triaxial.

Nombre de la fuente: elaboración propia.

Programa:

Luego de ejecutado el programa y al crear un nuevo proyecto se le pide al usuario que ingrese los datos característicos del modelo a analizar; estas variables se dividen en geométricas, físicas, mecánicas y de resistencia, además se incluye un parámetro clave para la discretización de la geometría que consiste en el tamaño deseado y posible de los elementos que componen la malla.

El softwarese encarga

de almacenar los datos y resultados

pertinentes al nuevo

proyecto, mediante el

módulo 'container2.p

y'

Discretización, haciendo

uso de gmsh como una función de

'feamodel.py'

Una vez realizado el mallado de la geometría del problema se procede a ejecutar el análisis mediante la formulación por elementos finitos.

'nonLinear_Problem.py' es

invocado, tiene

jerarquía sobre:

1. triaxial_interpr

etation (se detalla más adelante)

2. updated_lagrangean_analy

sis.py

Las tareas de 'updated_lagrangean_analysis.py' consisten en ejecutar y recibir los resultados en su respectivo orden de:

1. global_stiffness_matrix .py y matrix_Dep (matriz elastoplástica)

2. global_force_vector.py

3. a. modified_matrix.py y b. modified_vector.py

4. calc_quanities.py (se explica más adelante)

5. plot.py (se explica más adelante)

1 y 2 construyen las

matrices y vectores

generales según la ecuación

( 2.5 )

3. a y b leen las condiciones de

frontera y modifican las

matrices y vectores

generales del sistema

4 encuentra la solución para

un paso dentro del sistema incremental.

Page 104: Desarrollo de un laboratorio virtual de geotecnia enfocado

84 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 5-11: Módulo que posibilita la estimación de deformaciones y esfuerzos.

Nombre de la fuente: elaboración propia.

5.2.1 Funcionalidad e interfaz gráfica de la simulación triaxial

De acuerdo con el diagrama de operación de la Figura 5-10, en la Figura 5-12 se muestra

la pantalla principal para la ejecución de análisis de compresión triaxial. En este apartado

se ofrecen dos programas complementarios, el primero de ellos enfocado en los docentes,

en este se puede establecer el proyecto, es decir, ingresar la totalidad de variables del

problema, asimismo, el segundo programa está pensado para los estudiantes, en este se

permite abrir los proyectos construidos en la aplicación del docente, cambiar las

condiciones de carga del ensayo, ejecutar los análisis y con los resultados obtenidos se le

solicita al estudiante la determinación de los parámetros de resistencia del material.

ca

lc_

qu

an

titie

s.p

y

Una vez resuelto el sistema general para un

paso particular, esta clase se encarga de calcular las deformaciones y a partir de estos últimos los esfuerzos

en cada una de las direcciones del sistema

coordenado particular del problema. También

devuelve estos resultados en un formato que permite ser graficado por 'plot.py'

failure_criterion.py se encarga de calcular si el estado de esfuerzos se

encuentra en fluencia, en el caso de detallar un

estado ilegal de esfuerzos apela al algoritmo de

subpasos modificado de Euler para estimar

esfuerzos que cumplan con el criterio de fluencia

de Drucker y Prager.

matrizDep.py facilita la matriz constitutiva [Dep]

para el análisis en failure_criterion.py

Page 105: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 85

Figura 5-12: Vista principal del programa de compresión triaxial.

Nombre de la fuente: elaboración propia.

Para el ingreso de las variables del problema por parte del docente se facilita el editor de

la Figura 5-13; la tabla provista y sus herramientas permiten el ingreso del parámetro de

plasticidad 𝐻’.

Page 106: Desarrollo de un laboratorio virtual de geotecnia enfocado

86 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 5-13: Interfaz para el docente para el ingreso de variables de compresión triaxial.

Nombre de la fuente: elaboración propia.

Para el análisis por parte de los estudiantes se ofrece una interfaz limitada similar a la de

la Figura 5-13, es decir, con una cantidad menor de datos iniciales, estos permiten variar

algunas características del ensayo. En síntesis, después de ejecutado el análisis, a partir

de los resultados típicos de la prueba triaxial, se permite calcular los parámetros de

resistencia de la muestra. Esta interfaz se muestra en la Figura 5-14.

Por último, la descripción del problema y las instrucciones para realizar los análisis

correspondientes a la sección “Ayuda” puede verificarse en lo dispuesto en la Figura 5-15.

Page 107: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 87

Figura 5-14: Interfaz del estudiante para la manipulación de variables.

Nombre de la fuente: elaboración propia.

Figura 5-15: Documentación y ayuda de la aplicación de compresión triaxial.

Nombre de la fuente: elaboración propia.

Page 108: Desarrollo de un laboratorio virtual de geotecnia enfocado

88 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

5.2.2 Tiempos de ejecución del modelo no lineal:

Los análisis han sido ejecutados teniendo en cuenta el tamaño de búsqueda del elemento,

así el número puede rondar cerca de los 250 elementos para los tamaños de las muestras

manejados en laboratorio, entretanto, los análisis toman un tiempo de ejecución de entre

3 a 4 minutos.

Tabla 5-2: Tiempos de análisis para el modelo no lineal.

# elementos triangulares cuadráticos

# Nodos

Tiempo de ejecución del análisis H:M:S

168 377 00:02:34

672 1425 00:12:31

1050 2201 00:23:39

Nombre de la fuente: elaboración propia

5.2.3 Ejercicios didácticos de operación de la prueba triaxial

Estos ejercicios se basan en la idea básica de calibración del modelo, es decir en la

variación de los parámetros de entrada y en el análisis de la respuesta ante el incremento

de la carga axial con esos valores iniciales.

En primera medida se busca operar los parámetros de resistencia 𝑐′ y 𝜙′ en términos de

combinaciones con un valor menor y un valor mayor para cada uno de ellos, la propuesta

se resume en la Tabla 5-3. El valor menor se denota con el signo menos (-) y el valor mayor

se denota con el signo (+). Esta combinación de valores define un rango de variación de

los parámetros para que el estudiante detalle la diferencia en los resultados que resulta en

el cambio de la resistencia del material.

Tabla 5-3: Variación de los parámetros de resistencia de la superficie de fluencia.

𝒄’+ (kPa) 𝝓′+ (°) 𝒄′- (kPa) 𝝓′- (°)

15 15 5 5

Nombre de la fuente: elaboración propia.

Los ejercicios se detallan mediante todas las combinaciones posibles de los valores de la

Tabla 5-3, las condiciones de los ejercicios se detallan a continuación:

Page 109: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 89

1) c'=15kPa y 𝜙=15°.

2) c’=15kPa y 𝜙=5°

3) c’=5kPa y 𝜙=15°

4) c’=5kPa y 𝜙=5°

Asimismo, en el ejercicio de variación de la malla los datos se detallan en la Tabla 5-4_

Tabla 5-4: Tamaño promedio de los elementos finitos para la identificación de la dependencia de los resultados.

Malla finaMalla

media

Malla

grande

Tamaño de búsqueda de

elementos(m)0.005 0.008 0.012

Nombre de la fuente: elaboración propia

Mientras que, en el caso de los parámetros elásticos, la propuesta queda definida en la

Tabla 5-5

Tabla 5-5: Datos para la variación de los parámetros elásticos del modelo.

E+ (kPa) ν+ E- (kPa) ν-

10000 0.4 6000 0.1

Nombre de la fuente: elaboración propia

Nuevamente los casos provienen de la combinación de los valores, en este caso para los

datos de la Tabla 5-5 se generan los siguientes casos:

1) E=10.000kPa y ν=0.4

2) E=10.000kPa y ν=0.1

3) E=6.000kPa y ν=0.4

4) E=6.000kPa y ν=0.1

Asimismo, se dejan los archivos configurados para la ejecución de estos análisis, el

proceso debe ir de la de la mano con las instrucciones del panel de ayuda, en este panel

se explica el funcionamiento del criterio de discretización y las unidades en que deben

ingresarse las unidades, así como de dónde deben obtenerse dichos datos. Asimismo, se

Page 110: Desarrollo de un laboratorio virtual de geotecnia enfocado

90 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

da un apartado que explica el carácter de los resultados obtenidos, estos se resumen en

las gráficas de deformaciones, esfuerzos 𝑝’ y 𝑞’ y volumen.

Todos los casos mencionados anteriormente se encuentran guardados en el formato de

archivo “. mqb” tal como se detalla en la Figura 5-16

Figura 5-16: Archivos suministrados para realizar los análisis didácticos.

Nombre de la fuente: elaboración propia.

Luego de ejecutados estos ejercicios el usuario puede tener un acercamiento al

comportamiento de un material en función de estos parámetros de entrada en tiempos que

no son extensos. Por otra parte, para todas las combinaciones puede experimentarse la

cedencia de resistencia del material dado que la carga puede ser aumentada hasta

encontrar este punto.

A continuación, se plantea la estrategia pedagógica para la utilización de la herramienta

virtual triaxial, esta se acompaña de un formato que de preferencia debe ser diligenciado

por parte del estudiante:

Page 111: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 91

Ejercicios y ejecución de los análisis.

En este apartado se plantea el paso a paso para implementar la simulación de la

compresión triaxial captando el desempeño de los estudiantes. Para estos

ejercicios las siguientes gráficas de esfuerzo deformación son generadas por el

software:

Estas gráficas pueden usarse en análisis comparativos al variar los parámetros de

entrada en una misma geometría, también permiten realizar el proceso estándar

calcularlos (retrocálculo); además de ello, se propone una serie de preguntas que

buscan ayudar al estudiante a comprender las relaciones entre las variables de

resistencia y las deformaciones resultantes.

Por último, se muestra la plantilla de análisis que debe ser diligenciada por el

estudiante:

p

ma a

de ensa

Page 112: Desarrollo de un laboratorio virtual de geotecnia enfocado

92 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Formulario del ensayo de compresión triaxial

Tipo de Ensayo: *Compresión triaxial a esfuerzo controlado.Etapa del ensayo: *falla.Forma de aplicación de la carga: *Incremental

Carga de ensayo: __Ensayo: #__ de: 8Dimensiones de la muestra.-Altura (cm): __, Diámetro (cm): __

Parámetros de resistencia.c(kPa): __, φ′(°): __Forma de aplicación de la carga:Cantidad de incrementos: __kPaIncremento de: __ kPa

Resultados: en el siguiente recuadro inserte los resultados provistos por el

programa:

p

ma a

de ensa

Page 113: Desarrollo de un laboratorio virtual de geotecnia enfocado

Organización del código 93

Preguntas de retroalimentación:

1. ¿Cuáles son las variables con mayor dependencia del intercepto de

cohesión?, explique a qué se debe este efecto.

_________________________________________________________________

_________________________________________________________________

__________________________________________________

2. ¿Cuál es la influencia de la variación de la relación de Poisson?

_________________________________________________________________

_________________________________________________________________

__________________________________________________

3. ¿Cuál es la influencia de la variación del ángulo de fricción del suelo?

_________________________________________________________________

_________________________________________________________________

__________________________________________________

4. ¿Cómo incide el cambio del módulo de Young en las deformaciones

calculadas?

_________________________________________________________________

_________________________________________________________________

__________________________________________________

5. ¿Cómo incide el número de incrementos de carga en las deformaciones

resultantes?

_________________________________________________________________

_________________________________________________________________

__________________________________________________

6. Cambie las dimensiones de la geometría y describa los resultados.

_________________________________________________________________

_________________________________________________________________

__________________________________________________

Page 114: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 115: Desarrollo de un laboratorio virtual de geotecnia enfocado

6. Calibración y validación de los modelos

En cualquier procedimiento de cálculo que incluya métodos computacionales es importante

que la formulación matemática y su implementación mediante el código de programación

sea corroborada con cierto grado de rigurosidad mediante comparación con problemas con

soluciones conocidas (Burd, 1986). En este contexto se opta por realizar una serie de

comparaciones tanto para el análisis no lineal como para la implementación acoplada de

consolidación divididas en ejemplos tal como se denota a continuación.

6.1 Análisis del modelo triaxial

6.1.1 Descripción del ejemplo de estudio N° 1.

Para estudiar el modelo no lineal bajo el cual opera el ensayo de compresión triaxial el

ejemplo discutido consiste en un ensayo sobre una muestra de “arcilla gris” (Desai, Reese,

1970). En la Tabla 6-1, y en la Figura 6-1 y Figura 6-2 se detallan las propiedades índice,

los parámetros de plasticidad y las curvas esfuerzo deformación del material en cuestión.

Tabla 6-1: Propiedades índice y parámetros elásticos del ejemplo N°1.

Variable Valor

𝛾𝑡(𝑘𝑁/𝑚3) 20.4

𝑤(%) 21

𝑐(𝑘𝑃𝑎) 34.47

∅(°) 0.0

𝜈 0.4

𝐸(𝑘𝑃𝑎) 3233.6

Nombre de la fuente: Zeevaert, A., (1980).

La Figura 6-1 detalla la variación del parámetro de plasticidad 𝐻′.

Page 116: Desarrollo de un laboratorio virtual de geotecnia enfocado

96 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 6-1: Variación del parámetro de plasticidad 𝐻’ para el ejemplo N° 1.

Nombre de la fuente: adaptado de Dessai & Reese (1970)

En primera medida se opta por encontrar el tamaño de malla a partir del cual se obtienen

valores aceptables que se acercan a los resultados experimentales recopilados en la

Figura 6-2.

Figura 6-2: Datos experimentales para el ejemplo N° 1.

Nombre de la fuente: adaptado de Dessai & Reese, (1970).

0.000.00

10.0010.00

20.0020.00

30.0030.00

40.00 0.00

50.0050.00

60.0060.00

0.000.00 500.00500.00 1000.001000.00 1500.001500.00 2000.002000.00

σσzz(

kP

a)

(kPa)

H(kPa) (kPa)

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(k

Pa

)

εa

Resultados para el ensayo qu

Ensayo 1

Ensayo 2

Ensayo 3

Page 117: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 97

En la Figura 6-3 y Figura 6-4 se muestran las cargas y las restricciones de movimiento del

modelo por elementos finitos adoptado para analizar el ejemplo N°1, en esta figuras se

presenta la discretización para un tamaño de elementos de la malla de 0.01𝑚.

Figura 6-3: Ejemplo de modelo por elementos finitos para el ejemplo N°1 (cargas)

Nombre de la fuente: Dessai & Reese (1970), discretización propia. Unidades en Pa.

Figura 6-4: Ejemplo de modelo por elementos finitos para el ejemplo N°1 (desplazamientos preestablecidos).

Nombre de la fuente: datos tomados de Dessai & Reese (1970), discretización propia. Unidades en metros.

Discretización de la geometría y de la de carga.

La influencia del tamaño de los elementos utilizados se puede verificar en la Figura 6-5,

Figura 6-6 y Figura 6-7. Entretanto el algoritmo de discretización tiene como variable de

entrada el tamaño deseado para la construcción de los elementos en función de la longitud

de sus lados, así pues, en estas gráficas la letra T hace referencia al argumento que toma

Page 118: Desarrollo de un laboratorio virtual de geotecnia enfocado

98 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

el algoritmo de búsqueda-discretización, mientras que, el carácter P hace alusión al

número de pasos realizado en cada caso.

Figura 6-5: Resultados para el tamaño de búsqueda de 0.02𝑚.

Nombre de la fuente: elaboración propia

Figura 6-6: Resultados para el tamaño de búsqueda de 0.015𝑚.

Nombre de le fuente: elaboración propia.

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(

kP

a)

εa

Resultados para el ensayo qu

Ensayo 1

Ensayo 2

Ensayo 3

T: 0.020 P: 4

T: 0.020 P: 8

T: 0.020 P: 15

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(

kP

a)

εa

Resultados para el ensayo qu

Ensayo 1

Ensayo 2

Ensayo 3

T: 0.015 P: 4

T: 0.015 P: 8

T: 0.015 P: 15

Page 119: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 99

Figura 6-7: Resultados para el tamaño de búsqueda de 0.01𝑚.

Nombre de la fuente: elaboración propia

En la Figura 6-5, Figura 6-6 y Figura 6-7 se puede apreciar que tiene mayor influencia en

los resultados el número de pasos en los que se divide la carga respecto al tamaño de los

elementos, esto se debe a que, cuando la matriz de rigidez del sistema se calcula una

mayor cantidad de veces se tiene en cuenta una mayor variación en la resistencia del

material a medida que se deforma.

En consecuencia para el incremento de carga y discretización más exigente (Figura 6-7)

la Tabla 6-2 muestra que para 4 incrementos de carga no se obtienen resultados

aceptables, es decir, se evidencia cerca del 70% de la deformación axial estimada

experimentalmente.

De igual manera, en la misma tabla se detalla que al aumentar de 4 a 8 pasos, la estimación

de las deformaciones experimentales mejora aproximadamente en un 19.3%, a la vez que

al aumentarse de 8 a 15 pasos el resultado mejora en menor medida, es decir, en un 3.3%.

Así pues, un aumento de inversión de recursos de análisis no es proporcional a la mejora

en las predicciones, sino que, debe encontrarse un punto óptimo en donde el tiempo de

análisis no sea una limitante.

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(

kP

a)

εa

Resultados para el ensayo qu

Ensayo 1

Ensayo 2

Ensayo 3

T: 0.010 P: 4

T: 0.010 P: 8

T: 0.010 P: 15

Page 120: Desarrollo de un laboratorio virtual de geotecnia enfocado

100 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Tabla 6-2: Resultados en función del número de incrementos de carga para el ejemplo N°1.

Número de incrementos de carga

Deformación para 40.0kPa

% del resultado experimental

4 0.022 70.8

8 0.028 90.1

15 0.029 93.4Nombre de la fuente: elaboración propia.

6.1.2 Análisis de sensibilidad para el modelo no lineal en el ensayo triaxial

Luego de conocer los valores que rigen el tamaño de los elementos y del fraccionamiento

de la carga del numeral 6.1.1, se busca examinar la variación de los resultados en términos

de la curva esfuerzo desviador vs deformación axial al introducir cambios en algunas de

las propiedades de entrada.

▪ Análisis de sensibilidad de cada parámetro

A lo largo de este documento se ha venido dando cuenta de las propiedades y parámetros

que conforman el modelo aquí implementado. En los siguientes apartes se estudia la

influencia cambio de cada uno de ellos en los resultados.

Variación de 𝒄′

La variación de la cohesión influye directamente en el estado de esfuerzos al cual ocurre

fluencia en los puntos de integración y es previsible puesto que es el factor que tiene mayor

peso en el criterio de fluencia adoptado (ecuación (3.49)), además controla a la pendiente

de la curva esfuerzo – deformación después de presentarse dicha fluencia (Figura 6-8).

Estos resultados muestran que para una cohesión de aproximadamente la mitad de la de

la muestra del ejemplo N°1, es decir, 0.5 ∗ 34.47𝑘𝑃𝑎 = 17.24𝑘𝑃𝑎, el punto de cedencia se

da en 𝑞 ≈ 20𝑘𝑃𝑎 con una pendiente después de la cedencia de aproximadamente

735.5𝑘𝑃𝑎, esto se debe a que algunos elementos entran en fluencia a un nivel más bajo

de esfuerzos, por otro lado, para una cohesión 20% más grande, o sea, 1.2 ∗ 34.47𝑘𝑃𝑎 =

Page 121: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 101

41.36𝑘𝑃𝑎, el punto evidente de cambio de pendiente aparece en 𝑞 ≈ 40𝑘𝑃𝑎, a un nivel de

deformación mucho mayor, es decir, 0.02 > 0.01 con una pendiente cercana a 408.6𝑘𝑃𝑎.

Por último, se resalta que para la totalidad de carga de este ensayo el valor final de

deformación axial se acerca al 6% para los valores real de cohesión y para el 50% de la

misma, mientras que, para el 120% esta deformación es de 5.6%, esto se debe a que el

punto de cedencia del material se alcanza a un mayor nivel de carga para los valores más

grandes de cohesión.

Figura 6-8: Influencia de 𝑐′ en los resultados de deformación axial.

Nombre de la fuente: elaboración propia.

A partir de la Figura 6-8 se reconoce que la mejor aproximación se da con el valor de

cohesión real de la muestra.

Variación de Փ’

En la Tabla 6-3 y la Figura 6-9 la variación del ángulo de fricción interna influye de manera

similar a la cohesión, aunque en menor medida ya que esta cantidad es el argumento de

las funciones seno y coseno en el criterio de fluencia Drucker-Prager, así pues, a mayor

ángulo de fricción las deformaciones decrecen, y en conclusión la mejor estimación se da

con el valor real del ángulo de fricción del material.

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(

kP

a)

εa

Variación de c'

Ensayo 1

Ensayo 2

Ensayo 3

c'(kPa): 34.47

c'(kPa): 17.24

c'(kPa): 41.36

Page 122: Desarrollo de un laboratorio virtual de geotecnia enfocado

102 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Tabla 6-3: Variación de las deformaciones en función del ángulo de fricción para el ejemplo N°1.

Փ’ (°)Deformación para

55.2 kPa

0 0.060

10 0.058

20 0.046

25 0.035

Nombre de la fuente: elaboración propia.

Figura 6-9: Influencia de Փ’ en los resultados de deformación axial.

Nombre de la fuente: elaboración propia.

Variación del módulo de Young 𝑬′

El cambio de este parámetro influye directamente en la pendiente inicial de la curva

esfuerzo deformación axial, luego de la cedencia del material todas las relaciones siguen

una tendencia paralela (Figura 6-10). En síntesis, la mejor estimación se da por el valor

real del módulo de Young.

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(

kP

a)

εa

Variación de Փ'

Ensayo 1

Ensayo 2

Ensayo 3

Φ'(°): 0.0

Φ'(°): 10.0

Φ'(°): 20.0

Φ'(°): 25.0

Page 123: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 103

Figura 6-10: Influencia de 𝐸′ en los resultados de deformación axial.

Nombre de la fuente: elaboración propia.

Variación de la relación de Poisson 𝝂

La influencia de la relación de Poisson en la deformación axial es ínfima tal como se

muestra en la Figura 6-11, por esto las conclusiones no pueden basarse en dicho

resultado.

Figura 6-11: Influencia de 𝜈 en los resultados de deformación axial.

Nombre de la fuente: elaboración propia.

Así pues se opta por retratar otras tendencias que exhibe el ejemplo de estudio, entre ellas

las deformaciones cortante y volumétrica (Figura 6-12 y Figura 6-13). La principal influencia

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(

kP

a)

εa

Variación de E

Ensayo 1

Ensayo 2

Ensayo 3

E(kPa) 3233.6

E(kPa) 4000.0

E(kPa) 5000.0

E(kPa) 5500.0

E(kPa) 6000.0

0.00

10.00

20.00

30.00

40.00

50.00

60.00

0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07

q'(

kP

a)

εa

Variación de ν

Ensayo 1

Ensayo 2

Ensayo 3

ν 0.01

ν 0.1

ν 0.2

ν 0.3

ν 0.

ν 0. 9

Page 124: Desarrollo de un laboratorio virtual de geotecnia enfocado

104 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

de la relación de Poisson se da en el volumen de la muestra, y por supuesto su deformación

volumétrica, de esta manera, sobre una misma geometría, se tiene que para valores

mayores en la relación de Poisson se tienen menores cambios volumétricos, por otro lado,

estos valores altos determinan mayores cambios de forma, es decir, estiman mayores

deformaciones cortantes. Así pues, los resultados de la Figura 6-12 y la Figura 6-13 se

encuentran en concordancia con este hecho teórico.

En estas gráficas la deformación volumétrica para 𝜈 = 0.49 es aproximadamente el 33.3%

de la encontrada para 𝜈 = 0.01, lo cual contrasta con la deformación cortante que para 𝜈 =

0.01 es cerca del 91.4% de la estimada para 𝜈 = 0.49. Se destaca que estas figuras son

provistas de manera automática por el código implementado.

Figura 6-12: Influencia de 𝜈 en los resultados, estimación para 𝜈 = 0.01.

Nombre de la fuente: elaboración propia.

Page 125: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 105

Figura 6-13: Influencia de 𝜈 en los resultados estimación para 𝜈 = 0.49.

Nombre de la fuente: elaboración propia.

Comentario final

A partir de las observaciones del apartado 6.1.2 se reconoce que las variables del modelo

que mejor aproximan la respuesta esfuerzo-deformación, son los datos originales de

entrada del modelo, así pues, se reconoce una capacidad predictiva aceptable del modelo.

6.2 Análisis del modelo acoplado de consolidación

En este apartado, para corroborar los resultados provistos por el código se toman valores

del estudio del modelo acoplado con flujo no darciano de Ing & Xiaoyan (2002), a la vez

que se discuten algunas cuestiones relacionadas con el método. Uno de los casos de

análisis del trabajo de Ing & Xiaoyan (2002) es tomado de los estudios precursores de Hird,

et al (1992), consiste en el problema de drenes verticales embebidos en suelo blando bajo

condiciones axisimétricas, dicho problema también tiene una solución propuesta por

Rendulic (1935) y, es tomado como base para la verificación de los resultados del modelo

implementado de consolidación.

Page 126: Desarrollo de un laboratorio virtual de geotecnia enfocado

106 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

6.2.1 Consideraciones sobre el modelo acoplado de consolidación.

En el modelo trabajado no se considera la consolidación inicial, es decir, se ignora la

reducción de volumen de la masa de suelo debida a la expulsión y compresión del aire de

la muestra, debido a que esta se asume completamente saturada.

Para cada uno de los grados de libertad relacionados con la presión de poros presentes

en la frontera del dominio de la geometría debe especificarse una cantidad conocida, para

ello se tienen dos opciones mutuamente excluyentes, la primera consiste en indicar el

incremento de presión de poros y la segunda requiere conocer el posible flujo nodal

preestablecido. En el ejemplo de la Figura 6-14 puede verse que este criterio se cumple

para el problema planteado.

Para verificar los resultados del modelo se construye la curva de grado promedio de

consolidación del proceso de consolidación, el problema tratado es la consolidación

alrededor de un dren ideal embebido en un estrato homogéneo de suelo blando en

condiciones axisimétricas. Las propiedades del material y la geometría se detallan en la

Tabla 6-4 y Figura 6-14 respectivamente.

Tabla 6-4: Parámetros para el ejemplo N°2:

Variable Valor

𝜈 0.0

𝐸(𝑘𝑃𝑎) 10000

𝑘ℎ(𝑚/𝑠) 10−8

𝑘𝑣(𝑚/𝑠) 2.5 ∗ 10−9

Nombre de la fuente: Ing & Xiaoyan, (2002).

Page 127: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 107

Figura 6-14: Geometría y condiciones de frontera del modelo.

(No está a escala)Nombre de la fuente: Ing & Xiaoyan, (2002).

El dren central ideal puede ser modelado mediante una frontera libre drenante o por

elementos finitos caracterizados por un coeficiente de permeabilidad muy grande, en este

documento se aborda la primera aproximación. Asimismo, para el manejo del modelo de

presentado en la Figura 6-14 se discretiza esa misma geometría en 400 elementos

triangulares lineales, esta nueva discretización se presenta en la Figura 6-15.

Page 128: Desarrollo de un laboratorio virtual de geotecnia enfocado

108 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 6-15: Discretización de la geometría para el ejemplo N°2.

Nota: (El radio 𝒓𝒘 = 𝟎. 𝟎𝟓𝒎 del dren no puede detallarse debido a la escala).Nombre de la fuente: elaboración propia.

Los resultados teóricos mencionados en la introducción se resumen mediante el grado

promedio de consolidación vs factor tiempo horizontal (𝑇ℎ) de la ecuación (6.1) y se

muestran en la Figura 6-16, en ella se detallan los resultados de Ing & Xiaoyan (2002),

Rendulic (1935) y los calculados con el código de este documento para un dren central

“ideal”. Los resultados de la presente modelación se comparan con la literatura en la Figura

6-17.

𝑇ℎ =𝑐ℎ𝑡

𝐷𝑒2 con 𝑐ℎ =

2𝐺𝑘ℎ

𝛾𝑓 (6.1)

Page 129: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 109

Figura 6-16: Resultados del modelo para el “Grado promedio de consolidación vs factor tiempo para la consolidación alrededor de un dren ideal”.

Nombre de la fuente: adaptado de Ing & Xiaoyan, (2002).

Figura 6-17: Datos para la corroboración del problema de consolidación.

Nombre de la fuente: elaboración propia.

Los resultados para el dren ideal de la Figura 6-16 y la Figura 6-17indican que la

codificación del modelo acoplado es correcta, sin embargo, esta teoría tiene diversas

limitaciones, por esta razón, los autores buscan adaptar el modelo para que pueda predecir

0

20

40

60

80

100

0 1 2 3 4 5 6 7 8

Gra

do

pro

med

io d

e co

nso

lidac

ión

(%

)

Th

Grado de consolidación FEM (elemento triangular lineal)

Ing & Xiaoyan, (2001)

Page 130: Desarrollo de un laboratorio virtual de geotecnia enfocado

110 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

mediciones en campo, en específico, la disipación de la presión de poros para la

permeabilidad del problema toma un tiempo muy corto, a continuación, se detallan algunas

de estas discusiones.

Discusión relacionada.

Como se ha dicho, el tratado realizado por Ing & Xiaoyan se aborda el tema de retrasar la

disipación de poros para que los resultados concuerden con mediciones de campo, para

ello incluyen:

1) Un dren con buena resistencia entendido como un conjunto de elementos finitos

emplazados en la frontera izquierda con un valor controlado de permeabilidad,

2) Una zona de remoldeo caracterizada por el aumento o la disminución de la

permeabilidad debida a la perturbación en la inclusión del dren.

3) La inclusión del modelo Cam-clay modificado para representar de mejor manera el

comportamiento plástico del suelo.

4) La inclusión de la historia de esfuerzos, es decir incluir un esfuerzo de

preconsolidación y un estado de esfuerzos al inicio del análisis.

A partir de los anteriores numerales se logra retrasar la tasa de consolidación. Asimismo,

estos autores concluyen que esta tasa de disipación se ve afectada de manera significativa

por la historia de esfuerzos. Con esto en mente, se puede entrever que los resultados

suministrados por el modelo aquí implementado tienen limitaciones, en específico, porque

se ignora la historia de esfuerzos y se sigue un comportamiento lineal elástico. Si bien,

esto limita la aplicabilidad del modelo, se decide presentarlo ya que presupone un avance

en la modelación de la consolidación acoplada en el presente laboratorio virtual.

Por otra parte, dadas las dificultades para en la interpretación e implementación del modelo

acoplado de consolidación, se opta por presentar en el Anexo A y B algunas cuestiones

teóricas y prácticas que clarifican pasos importantes en la codificación; entre ellas la

aplicación de las condiciones de frontera.

6.2.2 Relación con el ensayo edométrico

Para el ensayo edométrico, como criterio de discretización del tiempo se usa la cantidad

adimensional de la ecuación (6.2), esta es conocida como factor tiempo, y es utilizada en

Page 131: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 111

diferentes simulaciones acopladas de varios autores (Potts & Zdravkovic,1999; Booker &

Small, 1975).

∆𝑇𝑉 =1

3

𝑘

𝛾𝑤𝐸

1 − 𝜈

(1 + 𝜈)(1 − 2𝜈)

∆𝑡

𝑎2 (6.2)

Donde 𝑎 es la mitad de la altura de la muestra y ∆𝑡 es el valor a usar para la disipación de

la presión intersticial provocada por cada carga y es calculado al darle valores a 𝑇 en el

rango de [0.001, 0.0070] y mediante incrementos ∆𝑇 iguales a 0.00005.

Caso de análisis

Se toma en consideración el estudio de una muestra de material según los parámetros y

propiedades de la Tabla 6-5 donde 𝜎𝑎 es el esfuerzo de ensayo cuya geometría se aparece

en la Figura 6-18:

Tabla 6-5: Propiedades y parámetros del material de estudio en la configuración edométrica.

Variable Valor

𝜈 0.0

𝐸(𝑘𝑃𝑎) 7200

𝛾𝑡(𝑘𝑁/𝑚3) 16.0

𝛾𝑤(𝑘𝑁/𝑚3) 9.81

𝑘ℎ(𝑚/𝑠) 0

𝑘𝑣(𝑚/𝑠) 10−8

𝜎𝑎(𝑘𝑃𝑎) 12.6

Nombre de la fuente: Datos propios.

La discretización consiste en 283 elementos triangulares lineales y 143 nodos, las

condiciones de frontera se muestran en la Figura 6-18.

Page 132: Desarrollo de un laboratorio virtual de geotecnia enfocado

112 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura 6-18: Discretización, carga y condiciones de frontera para el estudio de la configuración edométrica.

Nombre de la fuente: elaboración propia.

La deformación total calculada, y por tanto, la disipación de presión de poros se da en un

intervalo de tiempo de 20 segundos, como se evidencia en Figura 6-19, estos resultados

se destacan dado que la permeabilidad tuvo un valor bajo (𝑘𝑣(𝑚/𝑠) = 10−8). Este proceso

también puede observarse en la Figura 6-20, donde la razón de presión de poros en el

centro de la muestra (𝑝) y la presión aplicada (𝑞), se grafican contra el criterio de

discretización del tiempo definido en la ecuación (6.2).

Page 133: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 113

Figura 6-19: Curva de consolidación estimada mediante el modelo acoplado de consolidación

Nombre de la fuente: elaboración propia

Figura 6-20: Disminución de la presión de poros en el centro de la muestra.

Nombre de la fuente: elaboración propia

Seguimiento de resultados.

La implementación del modelo acoplado fue corroborada con base al ejemplo tomado de

Ing & Xiaoyan (2001), aunque los resultados en términos de la curva de grado promedio

de consolidación concuerdan con ese ejemplo, para la modelación del ensayo edométrico

el modelo arroja curvas de consolidación que aunque cumplen con su forma típica tienen

baja capacidad predictiva, esto puede deberse al modelo reológico simple adoptado que

Page 134: Desarrollo de un laboratorio virtual de geotecnia enfocado

114 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

asume comportamiento elástico e ignora por completo los efectos debidos a la historia de

esfuerzos, este último tópico es de gran importancia en el problema de consolidación (Ma

et al., 2013).

Algunos aspectos del modelo a destacar son:

• Con la finalidad de no encontrar inconsistencias en la respuesta calculada para la

presión de poros, la geometría del espécimen modelado debe dibujarse

enteramente en el cuadrante 1 del sistema coordenado global, esto es debido a

que el cálculo de los términos tangenciales de la matriz [𝐵], es decir 1/𝑟 en los

puntos de cálculo se desestabilizan ya que la variable 𝑟 tiende a cero (𝑟 → 0).

• Puede asumirse que el proceso de integración en el tiempo es completamente

explícito al tomar un valor de 𝛽 = 1, que además de brindar estabilidad en el

proceso, consiste en una aproximación hacia adelante.

• En la Figura 6-20 puede observarse lo demarcado en el capítulo 4 referente al

efecto Mandel – Cryer, es decir, la disipación de presión de poros no es dominante

en todo el proceso, sino que puede haber un aumento debido a la respuesta no

monotónica del sistema. En síntesis, este efecto describe el pico inicial observado

en la Figura 6-20.

• Con valores de 𝛽 ≥ 0.5 el proceso no presenta desbordamiento en el cálculo de las

presiones de poros, aunque, si el mallado no es lo suficientemente fino, es decir, si

el tamaño general de los elementos finitos no se especifica lo suficientemente

pequeño, se presentan vibraciones alrededor de la respuesta, estas vibraciones se

detallan debido a que las presiones de poros aumentan y disminuyen cada vez en

menor medida respecto a la anterior variación.

• En análisis provee el desplazamiento del cabezal consistente en los

desplazamientos verticales del grado de libertad en contacto con este, así pues, se

ofrece la facultad de construir la curva de compresibilidad al correr sucesivos

escenarios de carga sobre el mismo modelo anteriormente deformado.

Page 135: Desarrollo de un laboratorio virtual de geotecnia enfocado

7. Conclusiones y recomendaciones

7.1 Conclusiones

• Se planteó un modelo para realizar un laboratorio virtual de ensayo triaxial

consolidado drenado (CD) en su etapa de falla mediante la técnica de los elementos

finitos, este permite reproducir de manera satisfactoria procesos de carga

controlada en términos de la curva de deformación axial vs esfuerzo desviador (𝑞).

• Se realizó el prototipo para la modelación numérica de un ensayo de consolidación

unidimensional, usando una formulación acoplada basada en el modelo de Biot. La

implementación acoplada se corroboró para el caso de la consolidación alrededor

de un dren vertical en condiciones axisimétricas para un material ideal poroso

elástico (Ing & Xiaoyan, 2001). A pesar de ello, la aplicación de este modelo para

la simulación del ensayo edométrico tiene tasas de consolidación muy grandes por

lo que no refleja de forma adecuada los tiempos largos del ensayo en materiales

poco permeables, esto se debe a que el modelo trabaja como un material lineal

elástico sin criterio de falla.

• Para evitar el cálculo de estados ilegales de esfuerzos, en el modelo triaxial se hizo

uso del algoritmo de subpasos modificado de Euler junto al criterio de fluencia de

Drucker-Prager y se evidencia que esta unión refleja ciertas características del

comportamiento esfuerzo deformación de los suelos que endurecen por

deformación.

• Las interfaces de usuario para el ensayo triaxial comprenden dos programas que

manejan el mismo tipo de formato de archivos, en el primero de ellos se permite la

construcción del proyecto por parte del docente o educador, mientras que el

segundo se encuentra enfocado en los estudiantes, este hace posible que ellos

Page 136: Desarrollo de un laboratorio virtual de geotecnia enfocado

116 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

cambien las condiciones de ensayo, la discretización de la geometría y de la carga.

Así mismo, el prototipo didáctico posibilita que los estudiantes decidan cuestiones

como las condiciones de carga del ensayo y el tamaño de la muestra, de esta

manera, se hace que ellos cumplan un rol participativo en las decisiones que atañen

a la ejecución de ensayo triaxial.

• Esta formulación representa un avance respecto a los modelos de laboratorio virtual

que son principalmente ilustrativos de las condiciones de laboratorio, esto se

explica porque el presente usa un modelo constitutivo que busca captar algunas

características esfuerzo deformación de los materiales que endurecen por

deformación.

• El código desarrollado en este trabajo es abierto y puede servir de base, no solo

para el ajuste de los ensayos antes mencionados, sino que posibilita la generación

de un programa o laboratorio de comportamiento geotécnico propio de la

Universidad Nacional, lo cual, sin duda brinda autonomía y mayores posibilidades

de desarrollo investigativo.

Recomendaciones

• Este es un primer paso para el desarrollo de un programa más elaborado de un

laboratorio virtual, en este se dejan las bases de la formulación conceptual y

numérica que constituyen lo más importante del todo el desarrollo ya que

comprende la modelación de algunas de las características esfuerzo deformación

de los suelos reales. Como aporte importante de la investigación se desarrolló el

código de programación en lenguaje Python. Este código se anexa al presente

documento y puede servir de base para futuros desarrollos e investigaciones

(anexo D).

• Se recomienda complementar la modelación triaxial con el desarrollo de la etapa

de consolidación axisimétrica y con formulaciones de ensayos consolidados no

drenados.

Page 137: Desarrollo de un laboratorio virtual de geotecnia enfocado

Conclusiones y recomendaciones 117

• Se recomienda realizar una interfaz gráfica que permita visualizar y recrear en

tiempo real los ensayos, de forma que sean más interactivos con el usuario.

• Para el análisis no lineal los parámetros de entrada deben cumplir con la

formulación, es decir, deben provenir de un ensayo de compresión axial. Asimismo,

la condición de equilibrio debe chequearse mirando la variación de los resultados

en términos del número de pasos y así evitar errores significativos.

• Es posible que para el primer paso de cómputo del análisis no lineal se obtengan

errores del tipo división entre cero, esto se genera ya que algunos puntos de

muestreo entran en fluencia y la integración de las relaciones constitutivas a lo largo

de la trayectoria de deformaciones requiere un estado de esfuerzos diferente de

cero para la estimación de la matriz elastoplástica [𝐷𝑒𝑝] así pues, una solución

simple para este inconveniente consiste en dividir la carga en un número mayor de

pasos de cálculo.

• Ocurren variaciones no reales de la presión de poros en los primeros pasos de

cálculo de la primera carga, estos son superados una vez generada una distribución

espacial loable de esta variable, por ello es deseable que se mantenga esta

distribución final con excesos despreciables en la aplicación de posteriores cargas

de ensayo, de no ser así, se pueden experimentar variaciones debido al efecto

Mandel – Cryer similares a las observadas en la primera carga. En los análisis

propuestos por Potts se advierte sobre esta respuesta a partir de lo cual se

concluye que el primer incremento de carga debe darse en un intervalo de tiempo

lo suficientemente pequeño como para que la respuesta sea no drenada. En

resumen, en el primer incremento de carga se busca que la respuesta sea no

drenada, ergo ésta no se presenta en la respuesta dado que los valores que

presentan no tienen valor en el análisis (Potts & Zdravkovic,1999).

• Para la construcción de la matriz de acoplamiento elemental [𝐿𝐸] las contribuciones

de los componentes cortantes deben ser ignoradas, para este fin el vector de

acoplamiento debe tomar la forma {𝑚} = {1,1,0,1}; esta configuración se

corresponde con la definición de la matriz de interpolación de desplazamientos [𝐵]

Page 138: Desarrollo de un laboratorio virtual de geotecnia enfocado

118 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

(ecuaciones (3.34) y (3.35)). Este comentario es importante y los autores

consultados no hacen este hincapié por lo que la interpretación de la teoría se

vuelve dispendiosa.

Page 139: Desarrollo de un laboratorio virtual de geotecnia enfocado

A. Anexo: Formulación del modelo acoplado mediante elementos finitos

Las definiciones dadas a continuación siguen lo descrito en el capítulo 10 de la referencia

“Finite Element Analysis in Geotechnical Engineering” (Potts & Zdravkovic, 1999). Aunque

en primera instancia en la formulación se utiliza el mismo orden del texto consultado, en el

presente documento se intenta abordar la formulación paso a paso de las ecuaciones de

elementos finitos, asimismo en el subtítulo referente a su implementación se hace un

desarrollo que sigue los lineamientos de la organización de la matriz general del sistema

que permite calcular tanto las reacciones en los apoyos, el cual es un procedimiento que

posibilita establecer la carga en análisis a deformación controlada.

El comportamiento constitutivo puede ser escrito en términos de los incrementos de

esfuerzo totales y las deformaciones (ecuación (A.1)).

{𝛥𝜎} = [𝐷]{𝛥휀} (A.1)

En donde el comportamiento del material en términos de esfuerzos totales puede definirse

mediante el modelo Tresca. Por otra parte, para considerar la relación entre fuerzas y

deformaciones en términos de esfuerzos efectivos y la dependencia de los cambios en las

presiones de poros, se pueden aplicar los siguientes conceptos (ecuación (A.2)).

{Δ𝜎} = [𝐷′]{Δ휀} + {Δ𝜎𝑓} (A.2)

De acuerdo con el principio de los esfuerzos efectivos, donde el cambio en la presión de

poros es {Δ𝜎𝑓}𝑇= {Δ𝑝𝑓 , Δ𝑝𝑓 , Δ𝑝𝑓 , 0, 0, 0}.

Generalmente en el método de los elementos finitos las variables desconocidas de primer

orden son los desplazamientos nodales y las presiones de poros nodales. De igual manera,

como se expresan los incrementos de desplazamiento en función de los valores nodales

Page 140: Desarrollo de un laboratorio virtual de geotecnia enfocado

120 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

se pueden escribir las presiones de poros como variables dependientes de sus grados de

libertad respectivos, ecuaciones (A.3) y (A.4).

{Δ𝑑} = [𝑁]{Δ𝑑}𝑛 (A.3)

{Δ𝑝𝑓} = [𝑁𝑝]{Δ𝑝𝑓}𝑛 (A.4)

En donde [𝑁] es la matriz de interpolación de desplazamientos y [𝑁𝑝] es la matriz de

interpolación de presiones de poros. Aunque estas matrices pueden tener las mismas

funciones de forma; en cuanto a los nodos a los cuales estás últimas apunten, su

distribución puede ser diferente debido a la existencia de diversos grados de libertad de

los desplazamientos, mientras que, para las presiones de poros solamente hay uno, en

otras palabras, la organización de [N] y [𝑁𝑝] las hacen diferir. A continuación, se listan las

partes que comprenden el modelo acoplado en consideración:

Ecuaciones de equilibrio, (ecuaciones (A.5)).

𝜕𝜎′𝑥𝜕𝑥

+𝜕𝑝𝑓

𝜕𝑥+𝜕𝜏𝑥𝑦

𝜕𝑦+𝜕𝜏𝑥𝑧𝜕𝑧

+ 𝛾𝑥 = 0

𝜕𝜎′𝑦

𝜕𝑦+𝜕𝑝𝑓

𝜕𝑦+𝜕𝜏𝑥𝑦

𝜕𝑥+𝜕𝜏𝑦𝑧

𝜕𝑧+ 𝛾𝑦 = 0

𝜕𝜎′𝑧𝜕𝑧

+𝜕𝑝𝑓

𝜕𝑧+𝜕𝜏𝑧𝑥𝜕𝑥

+𝜕𝜏𝑦𝑧

𝜕𝑦+ 𝛾𝑧 = 0

(A.5)

Donde 𝛾𝑥, 𝛾𝑦 y 𝛾𝑧 son las componentes del peso unitario total actuando en las direcciones

𝑥, 𝑦, y 𝑧 respectivamente.

Las relaciones constitutivas expresadas en términos de esfuerzos efectivos (ecuación

(A.6)).

{Δ𝜎′} = [𝐷′]{Δ휀} (A.6)

La ecuación de continuidad.

𝜕𝑣𝑥𝜕𝑥

+𝜕𝑣𝑦

𝜕𝑦+𝜕𝑣𝑧𝜕𝑧

− 𝑄 =𝜕휀𝑣𝜕𝑡

(A.7)

En la ecuación (A.7) 𝑣𝑥, 𝑣𝑦 y 𝑣𝑧 son las componentes de la velocidad superficial del fluido

de poros y 𝑄 representa la posible existencia de fuentes o sumideros de fluido.

Ley generalizada de Darcy:

Page 141: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo A. Formulación del modelo acoplado mediante elementos finitos 121

{

𝑣𝑥𝑣𝑦𝑣𝑧} = − [

𝑘𝑥𝑥 𝑘𝑥𝑦 𝑘𝑥𝑧𝑘𝑥𝑦 𝑘𝑦𝑦 𝑘𝑦𝑧𝑘𝑥𝑧 𝑘𝑦𝑧 𝑘𝑧𝑧

]

{

𝜕ℎ

𝜕𝑥𝜕ℎ

𝜕𝑦𝜕ℎ

𝜕𝑧}

(A.8)

La ecuación (A.8) se puede escribir de manera compacta como la ecuación (A.9).

{𝑣} = −[𝑘]{∇ℎ} (A.9)

En donde ℎ es la cabeza hidráulica (la ecuación (A.10) no tiene en cuenta el aporte de

velocidad):

ℎ =𝑝𝑓

𝛾𝑓+ (𝑥𝑖𝐺𝑥 + 𝑦𝑖𝐺𝑦 + 𝑧𝑖𝐺𝑧) (A.10)

Aquí se debe destacar que el vector {𝑖𝐺} = {𝑖𝐺𝑥, 𝑖𝐺𝑦, 𝑖𝐺𝑧}𝑇, es el vector unitario paralelo,

pero con sentido opuesto a la gravedad, 𝑘𝑖𝑗 son los coeficientes de la matriz de

permeabilidad [𝑘]. La influencia de pérdida de cabeza de energía en las otras direcciones

sobre una dirección dada se tiene en cuenta mediante los términos 𝑘𝑖𝑗 con 𝑖 ≠ 𝑗. En la

aplicación desarrollada en el presente trabajo es posible tomar un suelo anisotrópico con

𝑘𝑥𝑥 diferente de 𝑘𝑦𝑦 y 𝑘𝑖𝑗 = 0.

El principio de la mínima energía potencial se establece en la ecuación (A.11).

𝛿Δ𝐸 = 𝛿ΔW− 𝛿Δ𝐿 = 0 (A.11)

en donde 𝛥𝐸 es el incremento de energía potencial total, 𝛥𝑊 es el incremento de energía

de deformación y 𝛥𝐿 es incremento de trabajo debido a las cargas aplicadas 𝛥𝑊 es definida

por la ecuación (A.12).

Δ𝑊 =1

2∫{Δ휀}𝑇{Δ𝜎}𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

(A.12)

Haciendo uso del principio de esfuerzos efectivos en la ecuación (A.13).

Δ𝑊 =1

2∫[{Δ휀}𝑇[𝐷′]{Δ휀} + {Δ𝜎𝑓}{Δ휀}]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

(A.13)

Según la notación de {Δ𝜎𝑓} se puede cambiar la ecuación (A.13) a la ecuación (A.14).

Δ𝑊 =1

2∫[{Δ휀}𝑇[𝐷′]{Δ휀} + Δ𝑝𝑓Δ휀𝑣]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

(A.14)

Page 142: Desarrollo de un laboratorio virtual de geotecnia enfocado

122 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Por otro lado, el trabajo realizado por las cargas aplicadas de manera incremental ΔL

pueden dividirse en el trabajo realizado por las fuerzas de cuerpo y el realizado por los

esfuerzos en superficie según la ecuación (A.15).

Δ𝐿 = ∫[{Δ𝑑}𝑇{Δ𝐹}]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

+ ∫ [{Δ𝑑}𝑇{Δ𝑇}]𝑑𝑆𝑢𝑟𝑓

𝑆𝑢𝑟𝑓

(A.15)

Reemplazando las ecuaciones (A.14) y (A.15) en (A.11) se obtiene (A.16).

Δ𝐸 =1

2∫[{Δ휀}𝑇[𝐷′]{Δ휀} + Δ𝑝𝑓Δ휀𝑣]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

− ∫[{Δ𝑑}𝑇{Δ𝐹}]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

− ∫ [{Δ𝑑}𝑇{Δ𝑇}]𝑑𝑆𝑢𝑟𝑓

𝑆𝑢𝑟𝑓

(A.16)

Discretizando en N elementos, es decir, reemplazando la energía potencial por la suma de

las energías potenciales de los elementos por separado según la ecuación (A.17).

Δ𝐸 =∑Δ𝐸𝑖

𝑁

𝑖=1

(A.17)

Y desarrollando en función de la variación de los desplazamientos nodales se obtiene la

ecuación (A.18).

Δ𝐸 =∑[1

2∫ [{Δ𝑑}𝑛

𝑇[𝐵]𝑇[𝐷′][𝐵]{Δ𝑑}𝑛 − 2{Δ𝑑}𝑛𝑇[𝑁]𝑇{Δ𝐹}

𝑉𝑜𝑙

𝑁

𝑖=1

+ {𝑚}{Δ𝑑}𝑛𝑇[𝐵]𝑇[𝑁𝑝]{Δ𝑝𝑓}𝑛] 𝑑𝑉𝑜𝑙

− ∫ [{Δ𝑑}𝑛𝑇[𝑁]𝑇{Δ𝑇}]𝑑𝑆𝑢𝑟𝑓

𝑆𝑢𝑟𝑓

]

𝑖

(A.18)

Donde la integral de volumen se redefine en el sobre el volumen de un elemento ‘𝑖’ y la

integral de superficie se desarrolla sobre una porción de los bordes del mismo elemento.

Seguidamente se procede a minimizar la energía potencial respecto a los incrementos de

desplazamiento nodales en la ecuación (A.19).

Page 143: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo A. Formulación del modelo acoplado mediante elementos finitos 123

δΔ𝐸 =∑(𝛿{Δ𝑑}𝑛𝑇)𝑖 [ ∫ [[𝐵]𝑇[𝐷′][𝐵]{Δ𝑑}𝑛 − [𝑁]

𝑇{Δ𝐹}

𝑉𝑜𝑙

𝑁

𝑖=1

+ {𝑚}[𝐵]𝑇[𝑁𝑝]{Δ𝑝𝑓}𝑛]𝑑𝑉𝑜𝑙 − ∫ [[𝑁]𝑇{Δ𝑇}]𝑑𝑆𝑢𝑟𝑓

𝑆𝑢𝑟𝑓

]

𝑖

= {0}

(A.19)

Reorganizando se encuentra la ecuación (A.20).

δΔ𝐸 =∑(𝛿{Δ𝑑}𝑛𝑇)𝑖 [ ∫[[𝐵]

𝑇[𝐷′][𝐵]]𝑑𝑉𝑜𝑙{Δ𝑑}𝑛𝑉𝑜𝑙

𝑁

𝑖=1

+ ∫ [{𝑚}[𝐵]𝑇[𝑁𝑝]] 𝑑𝑉𝑜𝑙{Δ𝑝𝑓}𝑛𝑉𝑜𝑙

− ∫[[𝑁]𝑇{Δ𝐹}]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

− ∫ [[𝑁]𝑇{Δ𝑇}]𝑑𝑆𝑢𝑟𝑓

𝑆𝑢𝑟𝑓

]

𝑖

= {0}

(A.20)

Lo que se puede expresar como las ecuaciones por elementos finitos asociadas al principio

de mínima energía potencial según la ecuación (A.21).

[𝐾𝐺]{Δ𝑑}𝑛𝐺 + [𝐿𝐺]{Δ𝑝𝑓}𝑛𝐺= {∆𝑅𝐺} (A.21)

Sus componentes se detallan en las ecuaciones (A.22), (A.23), (A.24) y (A.25).

[𝐾𝐺] =∑[𝐾𝐸]𝑖

𝑁

𝑖=1

=∑( ∫ [[𝐵]𝑇[𝐷′][𝐵]] 𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

)

𝑖

𝑁

𝑖=1

(A.22)

[𝐿𝐺] =∑[𝐿𝐸]𝑖

𝑁

𝑖=1

=∑( ∫ [{𝑚}[𝐵]𝑇[𝑁𝑝]]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

)

𝑖

𝑁

𝑖=1

(A.23)

{∆𝑅𝐺} =∑{∆𝑅𝐸}𝑖

𝑁

𝑖=1

=∑[( ∫[[𝑁]𝑇{Δ𝐹}]𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

)

𝑖

+ ( ∫ [[𝑁]𝑇{Δ𝑇}]𝑑𝑆𝑢𝑟𝑓

𝑆𝑢𝑟𝑓

)

𝑖

]

𝑁

𝑖=1

(A.24)

Page 144: Desarrollo de un laboratorio virtual de geotecnia enfocado

124 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

{𝑚}𝑇 = {1, 1,0,1} (A.25)1

El término [𝐿𝐺] es conocido como la matriz global de acoplamiento. Mediante el principio

del trabajo virtual se puede escribir la ecuación de continuidad (A.7) como la ecuación

(A.26).

∫ [{𝑣}𝑇{∇(𝑝𝑓)} +𝜕휀𝑣𝜕𝑡

∆𝑝𝑓] 𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

− 𝑄∆𝑝𝑓 = 0 (A.26)

Sustituyendo la componente de velocidad por lo establecido en la ley de Darcy se obtiene

la ecuación (A.27).

∫ [−{𝛻ℎ}𝑇[𝑘]{∇(𝑝𝑓)} +𝜕휀𝑣𝜕𝑡

∆𝑝𝑓] 𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

− 𝑄∆𝑝𝑓 = 0 (A.27)

Dado que {𝛻ℎ} = (1

𝛾𝑓) {∇(𝑝𝑓)} + {𝑖𝐺}, mientras que se opta por estimar

𝜕𝜀𝑣

𝜕𝑡 como un cambio

finito ∆𝜀𝑣

∆𝑡, se obtiene (A.28).

∫ [∆휀𝑣∆𝑡

∆𝑝𝑓 − (1

𝛾𝑓) {𝛻(𝑝𝑓)}

𝑇[𝑘]{𝛻(𝑝𝑓)} − {𝑖𝐺}

𝑇[𝑘]{𝛻(𝑝𝑓)}] 𝑑𝑉𝑜𝑙

𝑉𝑜𝑙

− 𝑄∆𝑝𝑓 = 0

(A.28)

En donde {𝑖𝐺}𝑇[𝑘]{𝛻(𝑝𝑓)} = {𝛻(𝑝𝑓)}

𝑇[𝑘]{𝑖𝐺}, ya que [𝑘] es una matriz simétrica. Por otra

parte, discretizando en 𝑁 elementos según la ecuación (A.29).

∑[ ∫ [1

∆𝑡{𝑚} [{Δ𝑑}𝑛

𝑇[𝐵]𝑇[𝑁𝑝]{Δ𝑝𝑓}𝑛]

𝑉𝑜𝑙

𝑁

𝑖=1

− (1

𝛾𝑓) {∆𝑝𝑓}𝑛

𝑇[𝐸]𝑇[𝑘][𝐸]{Δ𝑝𝑓}𝑛

− {∆𝑝𝑓}𝑛𝑇[𝐸]𝑇[𝑘]{𝑖𝐺}] 𝑑𝑉𝑜𝑙 − 𝑄[𝑁𝑝]{Δ𝑝𝑓}𝑛]

𝑖

= {0}

(A.29)

Desarrollando se obtiene la ecuación (A.30).

1Forma del vector de acoplamiento {𝑚} necesaria para la condición plana de deformación

y axisimétrica es {𝑚} = {1,1,0,1}.

Page 145: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo A. Formulación del modelo acoplado mediante elementos finitos 125

∑[ ∫ [1

∆𝑡{Δ𝑝𝑓}𝑛

𝑇[𝑁𝑝]

𝑇[𝐵]{Δ𝑑}𝑛{𝑚}

𝑇 − (1

𝛾𝑓) {∆𝑝𝑓}𝑛

𝑇[𝐸]𝑇[𝑘][𝐸]{Δ𝑝𝑓}𝑛

𝑉𝑜𝑙

𝑁

𝑖=1

− {∆𝑝𝑓}𝑛𝑇[𝐸]𝑇[𝑘]{𝑖𝐺}] 𝑑𝑉𝑜𝑙 − 𝑄{∆𝑝𝑓}𝑛

𝑇[𝑁𝑝]]

𝑖

= {0}

(A.30)

Factorizando {Δ𝑝𝑓}𝑛𝑇 se obtiene la ecuación (A.31).

∑({Δ𝑝𝑓}𝑛𝑇)𝑖[ ∫ [

1

∆𝑡[𝑁𝑝]

𝑇[𝐵]{Δ𝑑}𝑛{𝑚}

𝑇 − (1

𝛾𝑓) [𝐸]𝑇[𝑘][𝐸]{Δ𝑝𝑓}𝑛

𝑉𝑜𝑙

𝑁

𝑖=1

− [𝐸]𝑇[𝑘]{𝑖𝐺}] 𝑑𝑉𝑜𝑙 − 𝑄[𝑁𝑝]]

𝑖

= {0}

(A.31)

Reorganizando en la ecuación (A.32).

∑[ ∫ [1

∆𝑡{𝑚}[𝐵]𝑇[𝑁𝑝]{Δ𝑑}𝑛 − (

1

𝛾𝑓) [𝐸]𝑇[𝑘][𝐸]{Δ𝑝𝑓}𝑛

𝑉𝑜𝑙

𝑁

𝑖=1

− [𝐸]𝑇[𝑘]{𝑖𝐺}] 𝑑𝑉𝑜𝑙 − 𝑄[𝑁𝑝]]

𝑖

= {0}

(A.32)

Lo que resulta en la ecuación (A.33) para elementos finitos.

[𝐿𝐺]𝑇 ({Δ𝑑}𝑛𝐺∆𝑡

) − [Φ𝐺]{𝑝𝑓}𝑛𝐺 ={𝑛𝐺} + 𝑄 (A.33)

En donde 𝑄 no es afectado por las funciones de forma; como se detalla en la ecuación

(A.32) dado que es preferible que su valor sea aplicado directamente en el vector general

de “fuerzas”. Por otra parte, las demás componentes se establecen en las ecuaciones

(A.34), (A.35) y (A.36).

[Φ𝐺] =∑[Φ𝐸]𝑖

𝑁

𝑖=1

=∑( ∫(1

𝛾𝑓) [[𝐸]𝑇[𝑘][𝐸]]𝑑𝑉𝑜𝑙

.

𝑉𝑜𝑙

)

𝑖

𝑁

𝑖=1(A.34)

{𝑛𝐺} =∑{𝑛𝐸}𝑖

𝑁

𝑖=1

=∑( ∫[[𝐸]𝑇[𝑘]{𝑖𝐺}]𝑑𝑉𝑜𝑙

.

𝑉𝑜𝑙

)

𝑖

𝑁

𝑖=1

(A.35)

Page 146: Desarrollo de un laboratorio virtual de geotecnia enfocado

126 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

[𝐸] = [𝜕𝑁𝑝𝜕𝑥

,𝜕𝑁𝑝𝜕𝑦

,𝜕𝑁𝑝𝜕𝑧

]

𝑇

(A.36)

Para el caso que compete a este documento para la configuración plana de deformación

para el elemento triangular lineal la forma explícita para la matriz [𝐸] es [

𝜕𝑁1

𝜕𝑥,𝜕𝑁2

𝜕𝑥,𝜕𝑁3

𝜕𝑥𝜕𝑁1

𝜕𝑦,𝜕𝑁2

𝜕𝑦,𝜕𝑁3

𝜕𝑦

].

El término [Φ𝐺] es conocido como la matriz de conductividad de fluido de poros. En orden

de resolver las ecuaciones (A.21) y (A.33), debe realizarse un proceso conocido como

“marchar en el tiempo”, en donde las incógnitas desplazamiento y cambio en la presión de

poros son conocidas en un tiempo 𝑡 y se busca su valor en un tiempo 𝑡 + 1, para ello se

asume que la magnitud del promedio de la presión de poros durante un paso está

relacionada linealmente a los valores inicial y final de cada paso, de acuerdo a la ecuación

(A.37).

∫ [Φ𝐺]{𝑝𝑓}𝑛𝐺𝑑𝑡

𝑡+1

𝑡

= [Φ𝐺] [𝛽 ({𝑝𝑓}𝑛𝐺)𝑡+1+ (1 − 𝛽) ({𝑝𝑓}𝑛𝐺)𝑡

] ∆𝑡 (A.37)

De esta manera, la ecuación (A.33) queda definida como la ecuación (A.38).

[𝐿𝐺]𝑇{Δ𝑑}𝑛𝐺 − 𝛽∆𝑡[Φ𝐺]{∆𝑝𝑓}𝑛𝐺

= {𝑛𝐺}∆𝑡 + 𝑄∆𝑡 + [Φ𝐺] ({∆𝑝𝑓}𝑛𝐺)𝑡∆𝑡

(A.38)

Así pues, la forma incremental del sistema de ecuaciones es definida por la ecuación

(A.39).

[𝐿𝐺]𝑇{Δ𝑑}𝑛𝐺 − 𝛽∆𝑡[Φ𝐺]{∆𝑝𝑓}𝑛𝐺

= {𝑛𝐺}∆𝑡 + 𝑄∆𝑡 + [Φ𝐺] ({∆𝑝𝑓}𝑛𝐺)𝑡∆𝑡

(A.39)

Así pues, la forma incremental del sistema de ecuaciones se establece por la formulación

de (A.40):

[[𝐾𝐺] [𝐿𝐺]

[𝐿𝐺]𝑇 −𝛽∆𝑡[Φ𝐺]

] {{Δ𝑑}𝑛𝐺{∆𝑝𝑓}𝑛𝐺

} = {{∆𝑅𝐺}

[{𝑛𝐺} + 𝑄 + [Φ𝐺] ({∆𝑝𝑓}𝑛𝐺)𝑡] ∆𝑡

} (A.40)

Page 147: Desarrollo de un laboratorio virtual de geotecnia enfocado

B. Anexo: Anotaciones sobre la implementación del modelo acoplado

Para tener en cuenta los grados de libertad con valores prescritos existen diversos

procedimientos dentro de los cuales a continuación se detallan tres y pueden ser aplicados

una vez armada la matriz general del sistema.

En el primero de ellos se cambian los coeficientes de la matriz general de acuerdo con los

grados de libertad conocidos, es decir, los valores de la diagonal principal se cambian por

1 mientras que los demás valores del mismo renglón se modifican por un 0, como es de

esperarse, el valor del grado de libertad en el vector de incógnitas queda definido por la

cantidad preestablecida. El principal inconveniente de este proceso reside en las

reacciones no pueden ser calculadas. Otro procedimiento consiste en multiplicar en el

término de la diagonal principal de un grado de libertad restringido a movimiento por una

cantidad lo suficientemente grande, (1 ∗ 1011) que haga que los desplazamientos

calculados para esos grados de libertad sean despreciables.

El tercer esquema es el utilizado en este documento y se explica brevemente en los

próximos párrafos. Para la solución del sistema planteado en la ecuación (A.40) se opta

por organizar a la matriz general de rigidez según la ecuación (B.1).

[ [𝐾𝑢] [𝐾𝑢𝑝] [𝐿𝑢] [𝐿𝑢𝑝1]

[𝐾𝑢𝑝]𝑇

[𝐾𝑝] [𝐿𝑢𝑝2] [𝐿𝑝]

[𝐿𝑢]𝑇 [𝐿𝑢𝑝2]

𝑇−𝛽∆𝑡[Φ𝑢] −𝛽∆𝑡[Φ𝑢𝑝]

[𝐿𝑢𝑝1]𝑇

[𝐿𝑝]𝑇

−𝛽∆𝑡[Φ𝑢𝑝]𝑇

−𝛽∆𝑡[Φ𝑝] ]

{

Δ𝑑𝑢Δ𝑑𝑝Δ𝑝𝑢Δ𝑝𝑝}

=

{

Δ𝑅𝑢Δ𝑅𝑝Δ𝑈𝑢Δ𝑈𝑝}

(B.1)1

1 Nota: la matriz [𝐿𝐺] es de tamaño 𝑚 ∗ 𝑛 , con 𝑚 ≠ 𝑛, m igual al número de grados de libertad de los desplazamientos y n igual a la cantidad de grados de libertad de las presiones de poros; en

otras palabras, las ‘sub-matrices’ [𝐿𝑢𝑝1] y [𝐿𝑢𝑝2] no son traspuestas una de la otra.

Page 148: Desarrollo de un laboratorio virtual de geotecnia enfocado

128 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Donde el subíndice 𝑢 indica que la cantidad es desconocida mientras que 𝑝 señala a los

grados de libertad conocidos (preestablecidos). Por otra parte, en la ecuación (A.40) 𝛥𝑈

es determinado de manera general para los grados de la presión de poros por (B.2).

{Δ𝑈} = [{𝑛𝐺} + {𝑄} + [Φ𝐺] ({∆𝑝𝑓}𝑛𝐺)𝑡] ∆𝑡 (B.2)

Reorganizando los renglones 1 y 3 de la ecuación (B.1), y dejando de lado los otros dos,

en especial el 2 que sirve para hallar las reacciones en los apoyos del modelo se obtiene

(B.3).

[[𝐾𝑢] [𝐿𝑢]

[𝐿𝑢]𝑇 −𝛽∆𝑡[Φ𝑢]

] {{Δ𝑑𝑢}

{Δ𝑝𝑢}}

= {{Δ𝑅𝑢} − [𝐾𝑢𝑝]{Δ𝑑𝑝} − [𝐿𝑢𝑝1]{Δ𝑝𝑝}

{Δ𝑈𝑢} − [𝐿𝑢𝑝2]𝑇{Δ𝑑𝑝} + 𝛽∆𝑡[Φ𝑢𝑝]{Δ𝑝𝑝}

}(B.3)

Donde es la ecuación (B.3) la adoptada para marchar en el tiempo. Cabe aclarar que las

cantidades buscadas en cada paso son los cambios tanto en las posiciones de los nodos

como en la presión de poros en los mismos y se definen en la ecuación (B.4).

{Δ𝑈} = [{𝑛𝐺} + {𝑄} + [Φ𝐺] ({∆𝑝𝑓}𝑛𝐺)𝑡] ∆𝑡 (B.4)

Con la formulación descrita se advierte que para las fronteras en donde no se especifican

presiones de poros se debe establecer el caudal nodal en dicho punto.

En anteriores renglones se menciona el hecho de poder determinar las reacciones del

sistema mediante la ecuación matricial que se plantea en el segunda fila de la ecuación

(B.1), por lo que una vez resuelto para los grados de libertad desconocidos se pueden

encontrar las reacciones de acuerdo a lo detallado en la ecuación (B.5).

{Δ𝑅𝑝} = [𝐾𝑢𝑝]𝑇{Δ𝑑𝑢} + [𝐾𝑝]{Δ𝑑𝑝} + [𝐿𝑢𝑝2]{Δ𝑝𝑢} + [𝐿𝑝]{Δ𝑝𝑝} (B.5)

Siguiendo un procedimiento similar, la cuarta fila de la ecuación (B.1) plantea la posibilidad

de determinar el caudal en los nodos en donde se encuentra los cambios prescritos en la

presión de poros, es decir: (igualdad (B.6))

{Δ𝑈𝑝} = [{𝑛𝐺𝑝} + {𝑄} + [Φ𝐺𝑝] ({∆𝑝𝑓}𝑛𝐺𝑝)𝑡] ∆𝑡 (B.6)

Reescribiendo el ya mencionado cuarto renglón, en la ecuación (B.7).

{Δ𝑈𝑝} = [𝐿𝑢𝑝1]𝑇{Δ𝑑𝑢} + [𝐿𝑝]

𝑇{Δ𝑑𝑝} − 𝛽∆𝑡[Φ𝑢𝑝]

𝑇{Δ𝑝𝑢}

− 𝛽∆𝑡[Φ𝑝]{Δ𝑝𝑝}(B.7)

De donde la expresión para determinar el caudal es la ecuación (B.8).

Page 149: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo B. Anotaciones sobre la implementación del modelo acoplado 129

{𝑄} =1

∆𝑡([𝐿𝑢𝑝1]

𝑇{Δ𝑑𝑢} + [𝐿𝑝]

𝑇{Δ𝑑𝑝} − 𝛽∆𝑡[Φ𝑢𝑝]

𝑇{Δ𝑝𝑢}

− 𝛽∆𝑡[Φ𝑝]{Δ𝑝𝑝}) − [{𝑛𝐺𝑝} + [Φ𝐺𝑝] ({∆𝑝𝑓}𝑛𝐺𝑝)𝑡] ∆𝑡

(B.8)

Page 150: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 151: Desarrollo de un laboratorio virtual de geotecnia enfocado

C. Manual, instalación y ejecución

Herramientas necesarias para la ejecución de los análisis.

En primera instancia debe instalarse Anaconda 3 este incluye Python en su versión 3.x. Al

igual que pycalculix que puede encontrarse en el repositorio online:

https://pypi.org/project/pycalculix/

Luego de tener estos archivos se debe ejecutar la interfaz de Spyder; esta viene incluida

en todas las distribuciones de Anaconda, en seguida se debe abrir el archivos que

constituye el núcleo de cada uno de los programas, estos son:

• consolidation_1D.pyw para el ensayo edométrico

• compresion_trx.pyw para el ensayo triaxial

Aunque las instrucciones de ejecución para cada uno de los ensayos anteriores se pueden

acceder desde el menú ayuda en la ventana principal a continuación se describe el

procedimiento para realizar una ejecución satisfactorio de los análisis.

Análisis edométrico

En la ejecución inicial de las rutinas y subrutinas se debe dar un nombre al proyecto en la

ruta "Archivo" > "Nuevo", por otro lado, también se disponen de las funciones “Guardar” y

“Guardar como” con su comportamiento usual en programas de uso cotidiano (Figura (C.

1).

Page 152: Desarrollo de un laboratorio virtual de geotecnia enfocado

132 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura (C. 1): Vista principal del programa de consolidación.

Nombre de la fuente: elaboración propia

Seguidamente en la ruta “Análisis " > "Propiedades" se pueden ingresar las variables tanto

mecánicas como geométricas del problema a analizar. Luego de ingresar estas variables

se procede a realizar la discretización de la geometría en la ruta “Análisis " >

"Discretización" (Figura (C. 2)). Finalmente, para la ejecución de las rutinas se debe

acceder a la barra de menú en “Análisis " > "Ejecutar", terminado el proceso los resultados

se muestran automáticamente en las ventanas “Presión de poros" y "Deformación vertical”

del panel principal del programa.

Page 153: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo C. Manual, instalación y ejecución 133

Figura (C. 2): Interfaz para el ingreso de variables de consolidación poro-elástica.

Nombre de la fuente: elaboración propia

Análisis de compresión triaxial

En primera medida se debe dar un nombre al proyecto en la ruta "Archivo" > "Nuevo", la

interfaz también dispone de las funciones “Guardar”, “Guardar como” y de la función

“Cargar” para recuperar los datos de un proyecto anteriormente guardados Figura (C. 3).

Page 154: Desarrollo de un laboratorio virtual de geotecnia enfocado

134 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Figura (C. 3): Vista principal del programa de compresión triaxial.

Nombre de la fuente: elaboración propia.

Seguidamente en la ruta “Análisis " > "Propiedades" se pueden ingresar las variables tanto

mecánicas como geométricas del problema a analizar Figura (C. 5).; es importante resaltar

que el parámetro H debe obtenerse de una prueba de compresión esta es la pendiente de

la curva de esfuerzo axial versus deformación axial, esta variable se esquematiza en la

Figura (C. 4), Luego de ingresar estas variables se procede a realizar la discretización de

la geometría en la ruta “Análisis " > "Discretización". Finalmente, para la ejecución de las

rutinas se debe acceder a la barra de menú en “Análisis " > "Ejecutar", terminado el proceso

los resultados se muestran automáticamente en la ventana “Resultados” del panel principal

del programa.

Page 155: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo C. Manual, instalación y ejecución 135

Figura (C. 4): Deformaciones elásticas, plásticas y la definición de 𝑯’.

Nombre de la fuente: elaboración propia.

Figura (C. 5): Interfaz para el ingreso de variables de compresión triaxial.

Nombre de la fuente: elaboración propia

Page 156: Desarrollo de un laboratorio virtual de geotecnia enfocado
Page 157: Desarrollo de un laboratorio virtual de geotecnia enfocado

D. Anexo: código desarrollado

A continuación, se provee tanto el título del cada uno de las bibliotecas desarrolladas

como sus contenidos en términos de funciones, clases y llamados a otras rutinas.

calc_quantities.py"""This module calculates the strains in the centroid of the element,the equation {delta_epsilon} = [matriz_B]{delta_displacements}is used""" #JOscarfrom copy import deepcopyfrom numpy.linalg import invimport numpy as npimport time

import failure_criterionimport ccw_formatimport inv_coordimport integration_pointsimport element_shape_matricesimport jacobianoimport linear_mapping

class Quantities(): def __init__(self, model, degrees_freedom_d, degrees_freedom_p): """A class tha states the strains and stresses vectors: {delta_epsil_x, delta_epsil_y, delta_gamma_xy, delta_epsil_z}T in plane strain conditions or: {delta_epsil_r, delta_epsil_z, delta_gamma_rz, delta_epsil_theta}T in axi-symmetric conditions """

self._model = model if degrees_freedom_p != None: self.degrees_freedom = degrees_freedom_d + degrees_freedom_p

Page 158: Desarrollo de un laboratorio virtual de geotecnia enfocado

138 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

else: self.degrees_freedom = degrees_freedom_d self._results = {} self._results['element'] = {} self._results['node'] = {} self.integration_points = integration_points.Integration_points().integration_points for element in self._model.elements: for nodo in element.nodes: self._results['node'][nodo.id] = {} def invert_coordinates(self, element): inv_coord.Inv_coord(element) def element_strain_stress(self, modified_M, global_stiffness_matrix, presiones, resp, step, global_force_vector = None, first = False, c = None, phi = None, e = None, nu = None, H = None, resultado_anterior = None, usingSecondPiolaKirchhoff = None, desbalanceadasDeZeevaert = True, inSitu = 0): """This function calculates the incremental strains and stresses due to the incremental displacements in the nodes of the element. For the linear triangular element this function stimates the average of this quantities. In the case of quadratic element this function can stimate the value of strains and stresses in the sampling points (i.e. integration points) In this last element the stresses update uses the second Piola Kirchhoff stress tensor and verified the yield condition F<0 with the procedure known as modified Euler with error control. args: modified_M: np.array, modified matrix according to the prescribed, tied degrees of freedom (i.e. boundary conditions) global_stiffness_matrix: global_stiffness_matrix, contains the B and D matrices presiones: dict, stores the constant load applied in the model resp: np.array, contains the incremental displacement in the same order as modified_M global_force_vector: global_force_vector, contains elements force vectors first: boolean, verified the first step in the analysis c: float, defines the material cohesion phi: float, defines the material friction angle e: float, Young's modulus nu: float, Poisson's ratio slope_H: float, slope of the uniaxial stress-plastic strain curve resultado_anterior: dict, this argument has the same structure of _results it is _results obtained from an earlier step attributes: _model: feamodel degrees_freedom: list, ubication of the degrees of freedom in the modified

Page 159: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 139

matrix """ displacements_matrix = resp displ_vector = np.zeros((6, 1)) displ_vector = np.array([[0.99], [0.99], [0.99], [0.99], [0.99], [0.99]]) displ_X, displ_Y = modified_M.desplazamientos_X, modified_M.desplazamientos_Y dict_field = {} for element in self._model.elements: if element.ccxtype in ['CPS3', 'CAX3', 'CPE3']: self.invert_coordinates(element) formato = ccw_format.Ccw(element) nodei, nodej, nodek = formato.counterclockwise_format(element) self.invert_coordinates(element) # Writing the calculated displacements for degree in self.degrees_freedom: displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodei, displ_vector, 0, step) displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodej, displ_vector, 2, step) displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodek, displ_vector, 4, step) # Writing the tied displacements for signlinea in presiones: lista_amarrados = [] if presiones[signlinea]['rigid']: for node in presiones[signlinea]['nodes']: if presiones[signlinea]['vect_perp'][0, 0] == 1 and presiones[signlinea]['vect_perp'][0, 1] == 0: lista_amarrados.append({node.id: 'uy'}) elif presiones[signlinea]['vect_perp'][0, 0] == 0 and presiones[signlinea]['vect_perp'][0, 1] == 1: lista_amarrados.append({node.id: 'ux'}) else: lista_amarrados.append({node.id: 'uy'}) lista_amarrados.append({node.id: 'ux'}) # pendiente cargas inclinadas for degree in lista_amarrados: if nodei.id in degree.keys(): if degree[nodei.id] in ['uy']: displ_vector[0, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step]

Page 160: Desarrollo de un laboratorio virtual de geotecnia enfocado

140 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self._results['node'][nodei.id]['uy'] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] if degree[nodei.id] in ['ux']: displ_vector[1, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] self._results['node'][nodei.id]['ux'] = displacements_matrix[

self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] if nodej.id in degree.keys(): if degree[nodej.id] in ['uy']: displ_vector[2, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] self._results['node'][nodej.id]['uy'] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] if degree[nodej.id] in ['ux']: displ_vector[3, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] self._results['node'][nodej.id]['ux'] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] if nodek.id in degree.keys(): if degree[nodek.id] in ['uy']: displ_vector[4, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] self._results['node'][nodek.id]['uy'] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] if degree[nodek.id] in ['ux']: displ_vector[5, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step] self._results['node'][nodek.id]['ux'] = displacements_matrix[ self.degrees_freedom.index({'carga': presiones[signlinea]['id']}), step]

Page 161: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 141

# Prescribed displacements displ_vector = self.write_prescribed_displacement(nodei, displ_Y, displ_X, displ_vector, 0) displ_vector = self.write_prescribed_displacement(nodej, displ_Y, displ_X, displ_vector, 2) displ_vector = self.write_prescribed_displacement(nodek, displ_Y, displ_X, displ_vector, 4) m_B = global_stiffness_matrix.dict_element_matrices[element.id].matrix_B m_D = global_stiffness_matrix.dict_element_matrices[element.id].matrix_D strain_element_vector = np.matmul(m_B, displ_vector) stress_element_vector = np.matmul(m_D, strain_element_vector) if element.ccxtype in ['CPS3', 'CPE3']: dict_field['ey'] = deepcopy(strain_element_vector[0, 0]) dict_field['ex'] = deepcopy(strain_element_vector[1, 0]) dict_field['exy'] = deepcopy(strain_element_vector[2, 0]) dict_field['ez'] = deepcopy(strain_element_vector[3, 0]) dict_field['Sy'] = deepcopy(stress_element_vector[0, 0]) dict_field['Sx'] = deepcopy(stress_element_vector[1, 0]) dict_field['Sxy'] = deepcopy(stress_element_vector[2, 0]) dict_field['Sz'] = deepcopy(stress_element_vector[3, 0]) # Cambiar por convención de nomenclatura de condiciones # axisimétricas elif element.ccxtype in ['CAX3']: dict_field['ey'] = deepcopy(strain_element_vector[0, 0]) dict_field['ex'] = deepcopy(strain_element_vector[1, 0]) dict_field['exy'] = deepcopy(strain_element_vector[2, 0]) dict_field['ez'] = deepcopy(strain_element_vector[3, 0]) dict_field['Sy'] = deepcopy(stress_element_vector[0, 0]) dict_field['Sx'] = deepcopy(stress_element_vector[1, 0]) dict_field['Sxy'] = deepcopy(stress_element_vector[2, 0]) dict_field['Sz'] = deepcopy(stress_element_vector[3, 0]) # dict_field['er'] = deepcopy(strain_element_vector[0, 0]) # dict_field['ez'] = deepcopy(strain_element_vector[1, 0]) # dict_field['erz'] = deepcopy(strain_element_vector[2, 0]) # dict_field['etheta'] = deepcopy(strain_element_vector[3, 0]) # # dict_field['Sr'] = deepcopy(stress_element_vector[0, 0]) # dict_field['Sz'] = deepcopy(stress_element_vector[1, 0]) # dict_field['Srz'] = deepcopy(stress_element_vector[2, 0]) # dict_field['Stheta'] = deepcopy(stress_element_vector[3, 0]) np.set_printoptions(precision=8) self._results['element'][element.id] = {} self._results['element'][element.id]['avg'] = deepcopy(dict_field)

Page 162: Desarrollo de un laboratorio virtual de geotecnia enfocado

142 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

if element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: self.invert_coordinates(element)

formato = ccw_format.Ccw(element) nodei, nodej, nodek, nodel, nodem, noden = formato.counterclockwise_format(element) self.invert_coordinates(element) displ_vector = np.zeros((12, 1))# displ_vector = np.array([[0.99], [0.99], [0.99], [0.99], [0.99], [0.99], # [0.99], [0.99], [0.99], [0.99], [0.99], [0.99]]) # Writing the calculated displacements for degree in self.degrees_freedom: displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodei, displ_vector, 0, step) displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodej, displ_vector, 2, step) displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodek, displ_vector, 4, step) displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodel, displ_vector, 6, step) displ_vector = self.write_calculated_displacement( degree, displacements_matrix, nodem, displ_vector, 8, step) displ_vector = self.write_calculated_displacement( degree, displacements_matrix, noden, displ_vector, 10, step) # Writing the tied displacements for signlinea in presiones: lista_amarrados = [] if presiones[signlinea]['rigid']: for node in presiones[signlinea]['nodes']: if presiones[signlinea]['vect_perp'][0, 0] == 1 and presiones[signlinea]['vect_perp'][0, 1] == 0: lista_amarrados.append({node.id: 'uy'}) elif presiones[signlinea]['vect_perp'][0, 0] == 0 and presiones[signlinea]['vect_perp'][0, 1] == 1: lista_amarrados.append({node.id: 'ux'}) else: lista_amarrados.append({node.id: 'uy'}) lista_amarrados.append({node.id: 'ux'}) # pendiente cargas inclinadas for degree in lista_amarrados: displ_vector = self.write_tied_displacement( presiones[signlinea], displacements_matrix, nodei, displ_vector, 0, step) displ_vector = self.write_tied_displacement( presiones[signlinea], displacements_matrix, nodej, displ_vector, 2, step) displ_vector = self.write_tied_displacement(

Page 163: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 143

presiones[signlinea], displacements_matrix, nodek, displ_vector, 4, step) displ_vector = self.write_tied_displacement( presiones[signlinea], displacements_matrix, nodel, displ_vector, 6, step) displ_vector = self.write_tied_displacement( presiones[signlinea], displacements_matrix, nodem, displ_vector, 8, step) displ_vector = self.write_tied_displacement( presiones[signlinea], displacements_matrix, noden, displ_vector, 10, step) # Prescribed displacements displ_vector = self.write_prescribed_displacement(nodei, displ_Y, displ_X, displ_vector, 0) displ_vector = self.write_prescribed_displacement(nodej, displ_Y, displ_X, displ_vector, 2) displ_vector = self.write_prescribed_displacement(nodek, displ_Y, displ_X, displ_vector, 4) displ_vector = self.write_prescribed_displacement(nodel, displ_Y, displ_X, displ_vector, 6) displ_vector = self.write_prescribed_displacement(nodem, displ_Y, displ_X, displ_vector, 8) displ_vector = self.write_prescribed_displacement(noden, displ_Y, displ_X, displ_vector, 10) # Here the matrix B is the total strian-displacement matrix # It is store in the next dict and can be used to compute the # increase of strain for large displacements condicionalDeDeformacionesInfinitesimales = True if condicionalDeDeformacionesInfinitesimales: m_B = global_stiffness_matrix.dict_element_matrices[element.id].matrix_B else: m_B = global_stiffness_matrix.dict_element_matrices[element.id].matrix_B_total

#Esta es la matriz B promedio para todo el elemento m_D = global_stiffness_matrix.dict_element_matrices[element.id].matrix_D matricesEnPuntosIntegracion = global_stiffness_matrix.dict_element_matrices[ element.id].matricesEnPuntosIntegracion # ^ es un diccionario que contiene las matrices strain_element_vector = np.matmul(m_B, displ_vector) stress_element_vector = np.matmul(m_D, strain_element_vector) # Las siguientes cantidades se pueden tomar como el valor de la # variable esfuerzo o deformación en el centroide del elemento # en cuestión if element.ccxtype in ['CPS6', 'CPE6']: dict_field['ey'] = deepcopy(strain_element_vector[0, 0])

Page 164: Desarrollo de un laboratorio virtual de geotecnia enfocado

144 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

dict_field['ex'] = deepcopy(strain_element_vector[1, 0]) dict_field['exy'] = deepcopy(strain_element_vector[2, 0]) dict_field['ez'] = deepcopy(strain_element_vector[3, 0])

dict_field['Sy'] = deepcopy(stress_element_vector[0, 0]) dict_field['Sx'] = deepcopy(stress_element_vector[1, 0]) dict_field['Sxy'] = deepcopy(stress_element_vector[2, 0]) dict_field['Sz'] = deepcopy(stress_element_vector[3, 0]) # cambiar por convención de nomenclatura de condiciones # axisimétricas elif element.ccxtype in ['CAX6']: dict_field['ey'] = deepcopy(strain_element_vector[0, 0]) dict_field['ex'] = deepcopy(strain_element_vector[1, 0]) dict_field['exy'] = deepcopy(strain_element_vector[2, 0]) dict_field['ez'] = deepcopy(strain_element_vector[3, 0]) dict_field['Sy'] = deepcopy(stress_element_vector[0, 0]) dict_field['Sx'] = deepcopy(stress_element_vector[1, 0]) dict_field['Sxy'] = deepcopy(stress_element_vector[2, 0]) dict_field['Sz'] = deepcopy(stress_element_vector[3, 0]) if first: cauchyInSitu = np.array([[inSitu, 0, 0], [0, inSitu, 0], [0, 0, inSitu]]) else: cauchyInSitu = np.zeros((3, 3)) cauchy = np.array([[dict_field['Sy'], dict_field['Sxy'], 0], [dict_field['Sxy'], dict_field['Sx'], 0], [0, 0, dict_field['Sz']]]) cauchy = cauchy + cauchyInSitu inf_strain_tensor = np.array([[dict_field['ey'], dict_field['exy'], 0], [dict_field['exy'], dict_field['ex'], 0], [0, 0, dict_field['ez']]]) self._results['element'][element.id] = {} self._results['element'][element.id]['avg'] = deepcopy(dict_field) self._results['element'][element.id]['vect_u'] = deepcopy(displ_vector) # average Chauchy (delta) self._results['element'][element.id]['cauchy'] = deepcopy(cauchy) #error # average Strain tensor (delta) self._results['element'][element.id]['epsilon'] = deepcopy(inf_strain_tensor) self._results['element'][element.id]['B'] = deepcopy(m_B) # It is B_Total # matricesEnPuntosIntegracion is a dictionary self._results['element'][element.id]['points'] = deepcopy( matricesEnPuntosIntegracion) self._results['element'][element.id]['D'] = deepcopy(m_D)

Page 165: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 145

# Verificar si los esfuerzos de la entidad 'element' son legales # CALCULAR LOS ESFUERZOS PARA CADA PUNTO DE INTEGRACIÓN for point in self.integration_points.values(): B = self._results['element'][element.id]['points'][point['id']]['matrix_B'] if condicionalDeDeformacionesInfinitesimales or first: BT = B else: BL = self._results['element'][element.id]['points'][point['id']]['matrix_BL'] BT = B + BL u = displ_vector delta_epsilon = np.matmul(BT, -u) delta_strain = np.array( [[delta_epsilon[1-1][1-1], delta_epsilon[3-1][1-1], 0], [delta_epsilon[3-1][1-1], delta_epsilon[2-1][1-1], 0], [0, 0, delta_epsilon[4-1][1-1]]]) D = self._results['element'][element.id]['points'][point['id']]['matrix_D'] delta_sigma = np.matmul(D, delta_epsilon) delta_cauchy = np.array( [[delta_sigma[1-1][1-1], delta_sigma[3-1][1-1], 0], [delta_sigma[3-1][1-1], delta_sigma[2-1][1-1], 0], [0, 0, delta_sigma[4-1][1-1]]]) #time.sleep(3.5) jacobian = jacobiano.Jacobiano(element, l1 = point['l1'], l2 = point['l2']).matrix_J inv_jacobian = inv(jacobian) fN1 = point['l1']*(2*point['l1'] - 1) fN2 = 4*point['l1']*point['l2'] fN3 = point['l2']*(2*point['l2'] - 1) fN4 = 4*point['l2']*(1 - point['l1'] - point['l2']) fN5 = 1 - 3*(point['l1'] + point['l2']) + 2*(point['l1'] + point['l2'])**2 fN6 = 4*point['l1']*(1 - point['l1'] - point['l2']) # not using invert_coordinates(element) xc = fN1*nodei.y + fN2*nodej.y + fN3*nodek.y + fN4*nodel.y + fN5*nodem.y + fN6*noden.y matrices = element_shape_matrices.Shape_matrices( inv_jacobian, element.ccxtype, point['l1'], point['l2'], xc, displ_vector, cauchy) # m_FT no depende de cauchy m_FT = matrices.gradient_matrix_FT # estimating alpha if first: # The first step in the calculation cauchy_inicial = np.array([[inSitu, 0, 0],

Page 166: Desarrollo de un laboratorio virtual de geotecnia enfocado

146 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

[0, inSitu, 0], [0, 0, inSitu]]) cauchy_inicial_pi = cauchy_inicial # punto de integración pi else: cauchy_inicial_pi = resultado_anterior['element'][element.id]['points'][ point['id']]['cauchy'] # poner lo referente al segundo tensor de esfuerzos de Piola Kirchhoff # Resultado anterior tiene la misma estructura de self._results if usingSecondPiolaKirchhoff == False and usingSecondPiolaKirchhoff != None: delta_cauchy = delta_cauchy elif usingSecondPiolaKirchhoff == True and usingSecondPiolaKirchhoff != None: cauchy_final_pi = linear_mapping.second_Piola_Kirchhoff(m_FT, cauchy_inicial_pi, delta_cauchy) delta_cauchy = cauchy_final_pi - cauchy_inicial_pi else: raise ValueError('A very specific bad thing happened, usingSecondPiolaKirchhoff = None') # Si el punto está en fluencia en un paso anterior no calcular alpha # porque de antemano se sabe que es cero, pero hace falta integrar # los esfuerzos a lo largo de (1-α){Δσ} si el incremento es # si α = 0 el incremento es totalmente elastoplástico if not first: if resultado_anterior['element'][element.id]['points'][point['id']]['yield']: alpha = 0 else: alpha = failure_criterion.set_alpha(cauchy_inicial_pi, delta_cauchy, c, phi) else: alpha = failure_criterion.set_alpha(cauchy_inicial_pi, delta_cauchy, c, phi) if alpha == 1: 1 # elastic response self._results['element'][element.id]['points'][point['id']]['yield'] = False else: 1 # estimar los esfuerzos con el algoritmo substep self._results['element'][element.id]['points'][point['id']]['yield'] = True deltica = failure_criterion.euler_integration_scheme( cauchy_inicial_pi, delta_cauchy, delta_epsilon, e, nu, c, phi, H, alpha) delta_cauchy = deltica cauchy_final_pi = cauchy_inicial_pi + delta_cauchy self._results['element'][element.id]['points'][ point['id']]['delta_strain'] = delta_strain self._results['element'][element.id]['points'][ point['id']]['delta_cauchy'] = delta_cauchy

Page 167: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 147

self._results['element'][element.id]['points'][ point['id']]['cauchy'] = cauchy_final_pi if global_force_vector != None and desbalanceadasDeZeevaert == True: vfe = global_force_vector.dict_element_matrices[element.id].body_force_vector self._results['element'][element.id]['force_vector'] = deepcopy(vfe) return self._results def write_calculated_displacement(self, degree, displacements_matrix, node, displ_vector, ubication, step): """ This function can write the calculated displacements in a vector [u] for a particular element. The objetive is calculate [Ɛ] = [B][u] args: degree: dict {node.id, str} with str as 'uy' or 'ux' displacements_matrix: equal to _resp node: mesh.node displ_vector: np.array, [u] for each element ubication: ubication of the degree in the displ_vector step: in updated lagrangean analysis is cero in consolidation takes the value of the step analyzed in the procedure attributes: degrees_freedom: list """ if node.id in degree.keys():# print('chequeado') if degree[node.id] in ['uy']: displ_vector[ubication, 0] = displacements_matrix[ self.degrees_freedom.index(degree), step] self._results['node'][node.id]['uy'] = displacements_matrix[ self.degrees_freedom.index(degree), step] if degree[node.id] in ['ux']: displ_vector[ubication+1, 0] = displacements_matrix[ self.degrees_freedom.index(degree), step] self._results['node'][node.id]['ux'] = displacements_matrix[ self.degrees_freedom.index(degree), step] return displ_vector def write_tied_displacement(self, degree, displacements_matrix, node, displ_vector, ubication, step): """ This function can write the calculated tied displacements in a vector [u] for a particular element. The objetive is calculate [Ɛ] = [B][u] args: degree: presiones[signlinea] displacements_matrix: equal to _resp node: mesh.node

Page 168: Desarrollo de un laboratorio virtual de geotecnia enfocado

148 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

displ_vector: np.array, [u] for each element ubication: ubication of the degree in the displ_vector step: in updated lagrangean analysis is cero in consolidation takes the value of the step analyzed in the procedure attributes: degrees_freedom: list """

if node in degree['nodes']:# print('check') if degree['vect_perp'][0, 0] == 1 and degree['vect_perp'][0, 1] == 0: displ_vector[ubication, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': degree['id']}), step] self._results['node'][node.id]['uy'] = displacements_matrix[ self.degrees_freedom.index({'carga': degree['id']}), step] if degree['vect_perp'][0, 0] == 0 and degree['vect_perp'][0, 1] == 1: displ_vector[ubication+1, 0] = displacements_matrix[ self.degrees_freedom.index({'carga': degree['id']}), step] self._results['node'][node.id]['ux'] = displacements_matrix[ self.degrees_freedom.index({'carga': degree['id']}), step] return displ_vector def write_prescribed_displacement(self, node, displ_Y, displ_X, displ_vector, ubication): """ This function can write the prescribed displacements in a vector [u] for a particular element. The objetive is calculate [Ɛ] = [B][u] args: node: mesh.node displ_Y: modified_M.desplazamientos_Y displ_X: modified_M.desplazamientos_X displ_vector: np.array, [u] for each element ubication: ubication of the degree in the displ_vector attributes: degrees_freedom: list """ if node.id in displ_Y.keys(): displ_vector[ubication, 0] = displ_Y[node.id]['val'] self._results['node'][node.id]['uy'] = displ_Y[node.id]['val'] if node.id in displ_X.keys(): displ_vector[ubication+1, 0] = displ_X[node.id]['val'] self._results['node'][node.id]['ux'] = displ_X[node.id]['val'] return displ_vector def element_pore_pressure(self, modified_M, global_stiffness_matrix, presiones, resp, step):

Page 169: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 149

displacements_matrix = resp pore_press = modified_M.pore_press for element in self._model.elements: self.invert_coordinates(element) formato = ccw_format.Ccw(element) nodei, nodej, nodek = formato.counterclockwise_format(element) self.invert_coordinates(element) fp_node = np.array([[99], [99], [99]]) # writing the calculated pore pressures for degree in self.degrees_freedom: if nodei.id in degree.keys(): if degree[nodei.id] in ['fluid_press']: self._results['node'][nodei.id]['fluid_press'] = displacements_matrix[ self.degrees_freedom.index(degree), step] fp_node[1-1][1-1] = displacements_matrix[self.degrees_freedom.index(degree), step] if nodej.id in degree.keys(): if degree[nodej.id] in ['fluid_press']: self._results['node'][nodej.id]['fluid_press'] = displacements_matrix[ self.degrees_freedom.index(degree), step] fp_node[2-1][1-1] = displacements_matrix[self.degrees_freedom.index(degree), step] if nodek.id in degree.keys(): if degree[nodek.id] in ['fluid_press']: self._results['node'][nodek.id]['fluid_press'] = displacements_matrix[ self.degrees_freedom.index(degree), step] fp_node[3-1][1-1] = displacements_matrix[self.degrees_freedom.index(degree), step] # Precribed pore pressure if nodei.id in pore_press.keys(): self._results['node'][nodei.id]['fluid_press'] = pore_press[nodei.id]['val'] fp_node[1-1][1-1] = pore_press[nodei.id]['val'] if nodej.id in pore_press.keys(): self._results['node'][nodej.id]['fluid_press'] = pore_press[nodej.id]['val'] fp_node[2-1][1-1] = pore_press[nodej.id]['val'] if nodek.id in pore_press.keys(): self._results['node'][nodek.id]['fluid_press'] = pore_press[nodek.id]['val'] fp_node[3-1][1-1] = pore_press[nodek.id]['val'] return self._results

ccw_format.py"""This module organizes the nodes of the element in a counterclockwise (ccw)

Page 170: Desarrollo de un laboratorio virtual de geotecnia enfocado

150 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

way""" #JOscar

from math import sqrt

class Ccw(): def __init__(self, element): self.counterclockwise_format(element) def counterclockwise_format(self, element): """Organizes the nodes of the element in a counterclockwise format 'i, j and k'. A linear triangular element is used""" if element.ccxtype in ['CPS3', 'CAX3', 'CPE3']: #print(element.id) __res = element.get_tris() for node in element.nodes: if node.id == __res[0][0]: self.nodei = node elif node.id == __res[0][1]: self.nodej = node elif node.id == __res[0][2]: self.nodek = node # calcular las distacias al origen coordenado global y # organizarlos siendo i el más cercano a este origen distNodei = sqrt(self.nodei.x**2 + self.nodei.y**2) distNodej = sqrt(self.nodej.x**2 + self.nodej.y**2) distNodek = sqrt(self.nodek.x**2 + self.nodek.y**2)

if distNodei <= distNodej and distNodei <= distNodek: nodei = self.nodei nodej = self.nodej nodek = self.nodek elif distNodej <= distNodei and distNodej <= distNodek: nodei = self.nodej nodej = self.nodek nodek = self.nodei elif distNodek <= distNodei and distNodek <= distNodej: nodei = self.nodek nodej = self.nodei nodek = self.nodej self.nodei = nodei self.nodej = nodej self.nodek = nodek

Page 171: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 151

return self.nodei, self.nodej, self.nodek elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: __res = element.get_tris() for node in element.nodes: if node.id == __res[0][0]: self.nodei = node elif node.id == __res[0][1]: self.nodej = node elif node.id == __res[2][1]: self.nodek = node elif node.id == __res[1][1]: self.nodel = node elif node.id == __res[1][2]: self.nodem = node elif node.id == __res[1][0]: self.noden = node return self.nodei, self.nodej, self.nodek, self.nodel, self.nodem, self.noden

compression_trx.pyw# -*- coding: utf-8 -*-"""Created on Fri Aug 2 21:42:23 2019

@author: JOscar"""from __future__ import divisionimport sys

import numpy as npfrom math import radiansfrom PyQt5 import QtCore, QtGui, QtWidgetsimport matplotlib.pyplot as pltfrom datetime import datetime

from matplotlib.figure import Figurefrom matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas

from trx_interface import Ui_MainWindowfrom dialog_input_trx_class import Input_Dlgfrom dialog_file_name_class import FilenameDlgfrom dialog_help_trx_class import HelpDlg

import container2import feamodelimport partmoduleimport nonLinear_Problem

__version__ = "1.0.0"

Page 172: Desarrollo de un laboratorio virtual de geotecnia enfocado

152 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

class MiAp(QtWidgets.QMainWindow): def __init__(self, parent = None): QtGui.QGuiApplication.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.filename = None self.container = container2.ResultByLoadContainer() self.dirty = self.container._dirty # The container's __dirty supplies this one? # Status bar self.sizeLabel = QtWidgets.QLabel() self.sizeLabel.setFrameStyle(QtWidgets.QFrame.StyledPanel|QtWidgets.QFrame.Sunken) self.status = self.statusBar() self.status.setSizeGripEnabled(False) self.status.addPermanentWidget(self.sizeLabel) self.status.showMessage('Preparado', 5000) # Graphics scene # Geometry self.geometry_scene = QtWidgets.QGraphicsScene(self) self.ui.graphicsView_geometry.setScene(self.geometry_scene) # Elements self.element_scene = QtWidgets.QGraphicsScene(self) self.ui.graphicsView_elements.setScene(self.element_scene)

# Pendiente las demás graphicsView # Resultados self.resultados_scene = QtWidgets.QGraphicsScene(self) self.ui.graphicsView_resultados.setScene(self.resultados_scene) # Project options # 'verification' si el usuario ha ingresado propiedades al proyecto # 'flag' si se ha corrido el modelo # Actions and Key sequences #fileNewAction = QtWidgets.QAction('&Nuevo', self) self.ui.fileNewAction.setShortcut(QtGui.QKeySequence.New) helpTextNewfile = 'Crear nuevo archivo' self.ui.fileNewAction.setToolTip(helpTextNewfile) self.ui.fileNewAction.setStatusTip(helpTextNewfile) self.ui.fileNewAction.triggered.connect(self.fileNew) #propertiesAction = QtWidgets.QAction('&Propiedades', self) self.ui.propertiesAction.setShortcut('Ctrl+M') helpTextProperties = 'Propiedades del proyecto' self.ui.propertiesAction.setToolTip(helpTextProperties)

Page 173: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 153

self.ui.propertiesAction.setStatusTip(helpTextProperties) self.ui.propertiesAction.triggered.connect(self.set_input_parameters) # discretizeAction = QtWidgets.QAction('&Discretizar', self) self.ui.discretizeAction.setShortcut('Ctrl+D') helpTextDiscretize = 'Discretizar la geometría' self.ui.discretizeAction.setToolTip(helpTextDiscretize) self.ui.discretizeAction.setStatusTip(helpTextDiscretize) self.ui.discretizeAction.triggered.connect(self.discretize) # 'execute' action self.ui.executeAction.setShortcut('Ctrl+E') helpTextExecute = 'Ejecutar el proceso para todas las cargas' self.ui.executeAction.setToolTip(helpTextExecute) self.ui.executeAction.setStatusTip(helpTextExecute) self.ui.executeAction.triggered.connect(self.run_process) # 'save' action self.ui.saveAction.setShortcut('Ctrl+S') helpTextSave = 'Guardar proyecto'# Def qué parámetrs guardar self.ui.saveAction.setToolTip(helpTextSave) self.ui.saveAction.setStatusTip(helpTextSave) self.ui.saveAction.triggered.connect(self.fileSave) # 'saveAs' action self.ui.saveAsAction.setShortcut('Ctrl+G') helpTextSaveAs = 'Guardar en nuevo proyecto' self.ui.saveAsAction.setToolTip(helpTextSaveAs) self.ui.saveAsAction.setStatusTip(helpTextSaveAs) self.ui.saveAsAction.triggered.connect(self.fileSaveAs) # 'load' action self.ui.loadAction.setShortcut('Ctrl+L') helpTextLoad = 'Cargar proyecto' self.ui.loadAction.setToolTip(helpTextLoad) self.ui.loadAction.setStatusTip(helpTextLoad) self.ui.loadAction.triggered.connect(self.fileOpen)

# 'Instrucciones' action self.ui.action_Instrucciones.setShortcut('Ctrl+H') helpTextHelp = 'Ayuda' self.ui.action_Instrucciones.setToolTip(helpTextHelp) self.ui.action_Instrucciones.setStatusTip(helpTextHelp) self.ui.action_Instrucciones.triggered.connect(self.helpDialog)

# Las siguientes líneas son obsoletas runProcessAction = QtWidgets.QAction('&Run', self) runProcessAction.setShortcut('Ctrl+R') helpTextRun = 'Ejecutar proceso de consolidación 1D'

Page 174: Desarrollo de un laboratorio virtual de geotecnia enfocado

154 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# Pendiente cómo analizar las dif. cargas runProcessAction.setToolTip(helpTextRun) runProcessAction.setStatusTip(helpTextRun) runProcessAction.triggered.connect(self.run_process) # Signals and Slots self.ui.pushButton_ejecutar.clicked.connect(self.run_process) def closeEvent(self, event): if self.okToContinue(): 1 else: event.ignore() def okToContinue(self): """Asks is the user wants to save the changes""" if self.dirty: reply = QtWidgets.QMessageBox.question(self, 'Consolidación 1-D - cambios no guardados', '¿Guardar ediciones no guardadas?', QtWidgets.QMessageBox.Yes| QtWidgets.QMessageBox.No| QtWidgets.QMessageBox.Cancel) if reply == QtWidgets.QMessageBox.Cancel: return False elif reply == QtWidgets.QMessageBox.Yes: self.fileSave() return True # Pendiente fileNew method def fileNew(self): print('probando archivo nuevo') if not self.okToContinue(): return

self.filename = None self.container.clear() self.status.clearMessage() # cleaning the images of QGRAFICSWVIEW self.geometry_scene.clear() self.element_scene.clear() self.dirty = False stringsito = 'σ1: ' + '0.0' + ' kPa, ' + 'σ3: ' + '0.0' + ' kPa' self.ui.labelMostrarCarga.setText(stringsito)

def fileOpen(self): if not self.okToContinue(): return path = QtCore.QFileInfo(self.container.filename()).path() if not self.container.filename() == str() else '.'

Page 175: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 155

fname, formato = QtWidgets.QFileDialog.getOpenFileName(self, 'Consolidación - Cargar datos', path, 'formato de archivos (%s)' %self.container.formats()) if not fname == str(): ok, msg = self.container.load(fname) self.status.showMessage(msg, 5000) ruta = fname.split('/') file = ruta[-1] aux = file.split('.') name = aux[0] if ok: self.filename = name self.discretize()

def fileSave(self): if self.filename == None: self.fileSaveAs() else: if not self.filename.endswith(".mqb"): self.filename += ".mqb" ok, msg = self.container.save(self.filename) if ok: self.dirty = False self.status.showMessage(msg, 5000)

def fileSaveAs(self): fname = self.filename if self.filename is not None else "." fname, otro = QtWidgets.QFileDialog.getSaveFileName(self, 'Consolidación - Guardar como', fname, 'formato de archivos (%s)' %self.container.formats()) fname = str(fname) if fname: if ".mqb" not in fname: fname += ".mqb" self.filename = fname self.fileSave() def helpDialog(self): helpDlg = HelpDlg(self) if helpDlg.exec_(): 1 def set_input_parameters(self): dialog_inputs = Input_Dlg(self) # Para que el diálogo muestre los datos ya guardados en el proyecto dialog_inputs.lineEdit_S1.setText(str(self.container.dict_project['s1'])) dialog_inputs.lineEdit_S3.setText(str(self.container.dict_project['s3']))

Page 176: Desarrollo de un laboratorio virtual de geotecnia enfocado

156 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

dialog_inputs.lineEdit_altura.setText(str(self.container.dict_project['h'])) dialog_inputs.lineEdit_radio.setText(str(self.container.dict_project['r'])) dialog_inputs.lineEdit_tot_unit_weight.setText( str(self.container.dict_project['total_unit_weight'])) dialog_inputs.lineEdit_nu.setText(str(self.container.dict_project['nu'])) dialog_inputs.lineEdit_e.setText(str(self.container.dict_project['e'])) dialog_inputs.lineEdit_c.setText(str(self.container.dict_project['c'])) dialog_inputs.lineEdit_phi.setText(str(self.container.dict_project['phi'])) dialog_inputs.adv_Dlg.lineEdit_criterium.setText(str(self.container.dict_project['size'])) dialog_inputs.lineEdit_n.setText(str(self.container.dict_project['n'])) # Cargando los datos en la tabla tableWidgetH listH = self.container.listH listSigma = self.container.listSigma dialog_inputs.tableWidgetH.setColumnCount(2) dialog_inputs.tableWidgetH.setRowCount(len(listH)) for idx, H in enumerate(listH, start = 0): dialog_inputs.tableWidgetH.setItem(idx, 1, QtWidgets.QTableWidgetItem(str(H))) dialog_inputs.tableWidgetH.setItem(idx, 0, QtWidgets.QTableWidgetItem(str(listSigma[idx])))

# To get a filename if self.filename == None: dialog_file_name = FilenameDlg(self) if dialog_file_name.exec_(): if dialog_file_name.lineEdit_FileName.text() == '': return else: self.filename = dialog_file_name.lineEdit_FileName.text() # To save the input parameters if dialog_inputs.exec_(): # To show the dialog modally and return. True if 'Ok' is pressed self.container.dict_project['s1'] = float(dialog_inputs.lineEdit_S1.text()) self.container.dict_project['s3'] = float(dialog_inputs.lineEdit_S3.text()) self.container.dict_project['h'] = float(dialog_inputs.lineEdit_altura.text()) self.container.dict_project['r'] = float(dialog_inputs.lineEdit_radio.text()) self.container.dict_project['total_unit_weight'] = float( dialog_inputs.lineEdit_tot_unit_weight.text()) self.container.dict_project['nu'] = float(dialog_inputs.lineEdit_nu.text()) self.container.dict_project['e'] = float(dialog_inputs.lineEdit_e.text()) self.container.dict_project['c'] = float(dialog_inputs.lineEdit_c.text()) self.container.dict_project['phi'] = float(dialog_inputs.lineEdit_phi.text()) self.container.dict_project['n'] = float(dialog_inputs.lineEdit_n.text()) self.container.listH = dialog_inputs.listH self.container.listSigma = dialog_inputs.listSigma

Page 177: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 157

if dialog_inputs.criterium != None: self.container.dict_project['size'] = float(dialog_inputs.criterium) self.container.dict_project['verification'] = True self.dirty = True stringsito = 'σ1: ' + str(self.container.dict_project['s1']) + ' kPa, ' +\ 'σ3: ' + str(self.container.dict_project['s3']) + ' kPa' self.ui.labelMostrarCarga.setText(stringsito) return def discretize(self): print('probando discretización') print(self.container.dict_project) if self.container.dict_project['verification'] == False: self.status.showMessage('Geometría no especificada', 5000) QtWidgets.QMessageBox.information(self, 'Alerta', 'Geometría no especificada') return # To get a filename if self.filename == None: QtWidgets.QMessageBox.information(self, 'Nombre de proyecto', 'para continuar especifique un nombre al proyecto') dialog_file_name = FilenameDlg(self) if dialog_file_name.exec_(): if dialog_file_name.lineEdit_FileName.text() == '': QtWidgets.QMessageBox.warning(self, 'Nombre de proyecto', 'Discretizacion no realizada') return else: self.filename = dialog_file_name.lineEdit_FileName.text()

self.show_gui = True if '-nogui' in sys.argv: self.show_gui = False self.model = feamodel.FeaModel(self.filename) self.model.set_units('m') eshape = 'tri' if '-tri' in sys.argv: eshape = 'tri' desfase = 0.0 # Drawing the geometry self.part = partmodule.Part(self.model) self.part.goto(desfase, desfase) self.part.draw_line_to(desfase + self.container.dict_project['h'], desfase) self.part.draw_line_to(desfase + self.container.dict_project['h'], desfase + self.container.dict_project['r']) self.part.draw_line_to(desfase, desfase + self.container.dict_project['r']) self.part.draw_line_to(desfase, desfase)

Page 178: Desarrollo de un laboratorio virtual de geotecnia enfocado

158 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.model.set_eshape(eshape, 2) #plstrain #axisym self.model.set_etype('axisym', self.part, 0.1) try: self.status.showMessage('Discretizando...') self.model.mesh(size = self.container.dict_project['size'], meshmode = 'esize', mesher = 'gmsh') except: QtWidgets.QMessageBox.warning(self, 'Nombre de proyecto', 'Discretizacion no realizada')

self.status.showMessage('Discretización terminada', 25000) # Show geometry self.model.plot_geometry(self.filename + 'A0', display = self.show_gui) file_image_geometry = './' + self.filename + 'A0.png' geometry = QtGui.QPixmap(file_image_geometry) self.geometry_scene.addPixmap(geometry) # Show elements self.model.plot_elements(self.filename + 'elem', display = self.show_gui, title = 'Elements', enum = False, nshow = False, nnum = True) file_image_elements = './' + self.filename + 'elem.png' elements = QtGui.QPixmap(file_image_elements) self.element_scene.addPixmap(elements) #Show load stringsito = 'σ1: ' + str(self.container.dict_project['s1']) + ' kPa, ' +\ 'σ3: ' + str(self.container.dict_project['s3']) + ' kPa' self.ui.labelMostrarCarga.setText(stringsito) return def run_process(self): print('probando ejecutar proceso') now = datetime.now() current_time1 = now.strftime("%H:%M:%S") # try: self.status.showMessage('Ejecutando proceso...', 5000) # set constraints self.model.set_constr('fix', self.part.right, 'y') self.model.set_constr('fix', self.part.left, 'y') self.model.set_constr('fix', self.part.bottom, 'x') # x es el eje vertical

# self.model.plot_pressures(self.filename+'_press', display = self.show_gui)# self.model.plot_constraints(self.filename+'_constr', display = self.show_gui)

Page 179: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 159

total_unit_weight = self.container.dict_project['total_unit_weight'] nu = self.container.dict_project['nu'] e = self.container.dict_project['e'] c = self.container.dict_project['c'] phi = self.container.dict_project['phi'] pasosDeCarga = self.container.dict_project['n'] altura = self.container.dict_project['h'] dSigmaAxial = self.container.dict_project['s1'] dSigmaLateral = self.container.dict_project['s3'] self.model.set_load('press', self.part.top, dSigmaAxial, rigid = True) # Positivo es compresión en kPa self.model.set_load('press', 'L2', dSigmaLateral, rigid = False) # declarating the problem problema = nonLinear_Problem.nonLinearProblem(self.model, triaxial = True, dSigmaAxial=dSigmaAxial, dSigmaLateral=dSigmaLateral, altura=altura) listH = self.container.listH listSigma = self.container.listSigma H = (listH, listSigma) print('H', H) problema.solve(nu, e, total_unit_weight, pasosDeCarga, H, radians(phi), c)# print('criter', criter)# # Changing the GUI's load indicator figure = problema.triaxial_interpretation.fig canvas = FigureCanvas(figure) self.resultados_scene.addWidget(canvas) self.ui.graphicsView_resultados.show()

# except:# QtWidgets.QMessageBox.warning(self, 'Proyecto', 'Proyecto no especificado')# return

self.dirty = True self.status.showMessage('Proceso terminado', 25000) now = datetime.now() current_time2 = now.strftime("%H:%M:%S") print("Current Time =", current_time1, current_time2) return

if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = MiAp()

Page 180: Desarrollo de un laboratorio virtual de geotecnia enfocado

160 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

myapp.show() # sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys exit(app.exec_())

consolidation_1D.py# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'consolidation_1D_16May.ui'## Created by: PyQt5 UI code generator 5.11.3## WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(735, 549) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_13 = QtWidgets.QHBoxLayout() self.horizontalLayout_13.setObjectName("horizontalLayout_13") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_13.addItem(spacerItem) self.label_Titulo = QtWidgets.QLabel(self.centralwidget) self.label_Titulo.setObjectName("label_Titulo") self.horizontalLayout_13.addWidget(self.label_Titulo) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_13.addItem(spacerItem1) self.gridLayout.addLayout(self.horizontalLayout_13, 0, 0, 1, 2) spacerItem2 = QtWidgets.QSpacerItem(20, 397, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem2, 1, 1, 1, 1) self.scrollArea = QtWidgets.QScrollArea(self.centralwidget) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents = QtWidgets.QWidget() self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 197, 429)) self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")

Page 181: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 161

self.groupBox_Loads = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) self.groupBox_Loads.setGeometry(QtCore.QRect(40, 10, 113, 174)) self.groupBox_Loads.setObjectName("groupBox_Loads") self.labelMostrarCarga = QtWidgets.QLabel(self.groupBox_Loads) self.labelMostrarCarga.setGeometry(QtCore.QRect(10, 20, 47, 13)) self.labelMostrarCarga.setObjectName("labelMostrarCarga") self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.gridLayout.addWidget(self.scrollArea, 1, 0, 2, 2) self.horizontalLayout_12 = QtWidgets.QHBoxLayout() self.horizontalLayout_12.setObjectName("horizontalLayout_12") self.pushButton_ejecutar = QtWidgets.QPushButton(self.centralwidget) self.pushButton_ejecutar.setCheckable(False) self.pushButton_ejecutar.setObjectName("pushButton_ejecutar") self.horizontalLayout_12.addWidget(self.pushButton_ejecutar) self.gridLayout.addLayout(self.horizontalLayout_12, 3, 0, 1, 1) self.tabWidget_consolidation = QtWidgets.QTabWidget(self.centralwidget) self.tabWidget_consolidation.setTabPosition(QtWidgets.QTabWidget.North) self.tabWidget_consolidation.setTabShape(QtWidgets.QTabWidget.Rounded) self.tabWidget_consolidation.setObjectName("tabWidget_consolidation") self.tab_geometry = QtWidgets.QWidget() self.tab_geometry.setObjectName("tab_geometry") self.gridLayout_4 = QtWidgets.QGridLayout(self.tab_geometry) self.gridLayout_4.setObjectName("gridLayout_4") self.graphicsView_geometry = QtWidgets.QGraphicsView(self.tab_geometry) self.graphicsView_geometry.setObjectName("graphicsView_geometry") self.gridLayout_4.addWidget(self.graphicsView_geometry, 0, 0, 1, 1) self.tabWidget_consolidation.addTab(self.tab_geometry, "") self.tab_elements = QtWidgets.QWidget() self.tab_elements.setObjectName("tab_elements") self.gridLayout_2 = QtWidgets.QGridLayout(self.tab_elements) self.gridLayout_2.setObjectName("gridLayout_2") self.graphicsView_elements = QtWidgets.QGraphicsView(self.tab_elements) self.graphicsView_elements.setObjectName("graphicsView_elements") self.gridLayout_2.addWidget(self.graphicsView_elements, 0, 0, 1, 1) self.tabWidget_consolidation.addTab(self.tab_elements, "") self.tab_ppressure = QtWidgets.QWidget() self.tab_ppressure.setObjectName("tab_ppressure") self.gridLayout_8 = QtWidgets.QGridLayout(self.tab_ppressure) self.gridLayout_8.setObjectName("gridLayout_8") self.graphicsView_ppresure = QtWidgets.QGraphicsView(self.tab_ppressure) self.graphicsView_ppresure.setObjectName("graphicsView_ppresure") self.gridLayout_8.addWidget(self.graphicsView_ppresure, 0, 0, 1, 1) self.tabWidget_consolidation.addTab(self.tab_ppressure, "") self.tab_def_vertical = QtWidgets.QWidget() self.tab_def_vertical.setObjectName("tab_def_vertical") self.gridLayout_9 = QtWidgets.QGridLayout(self.tab_def_vertical) self.gridLayout_9.setObjectName("gridLayout_9") self.graphicsView_Def_Vert = QtWidgets.QGraphicsView(self.tab_def_vertical) self.graphicsView_Def_Vert.setObjectName("graphicsView_Def_Vert") self.gridLayout_9.addWidget(self.graphicsView_Def_Vert, 0, 0, 1, 1)

Page 182: Desarrollo de un laboratorio virtual de geotecnia enfocado

162 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.tabWidget_consolidation.addTab(self.tab_def_vertical, "") self.gridLayout.addWidget(self.tabWidget_consolidation, 0, 2, 4, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 735, 21)) self.menubar.setObjectName("menubar") self.menuArchivo = QtWidgets.QMenu(self.menubar) self.menuArchivo.setObjectName("menuArchivo") self.menu_Proyecto = QtWidgets.QMenu(self.menubar) self.menu_Proyecto.setObjectName("menu_Proyecto") self.menuA_yuda = QtWidgets.QMenu(self.menubar) self.menuA_yuda.setObjectName("menuA_yuda") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.propertiesAction = QtWidgets.QAction(MainWindow) self.propertiesAction.setObjectName("propertiesAction") self.discretizeAction = QtWidgets.QAction(MainWindow) self.discretizeAction.setObjectName("discretizeAction") self.fileNewAction = QtWidgets.QAction(MainWindow) self.fileNewAction.setObjectName("fileNewAction") self.action_Instrucciones = QtWidgets.QAction(MainWindow) self.action_Instrucciones.setObjectName("action_Instrucciones") self.saveAction = QtWidgets.QAction(MainWindow) self.saveAction.setObjectName("saveAction") self.loadAction = QtWidgets.QAction(MainWindow) self.loadAction.setObjectName("loadAction") self.executeAction = QtWidgets.QAction(MainWindow) self.executeAction.setObjectName("executeAction") self.saveAsAction = QtWidgets.QAction(MainWindow) self.saveAsAction.setObjectName("saveAsAction") self.menuArchivo.addAction(self.fileNewAction) self.menuArchivo.addSeparator() self.menuArchivo.addAction(self.saveAction) self.menuArchivo.addAction(self.saveAsAction) self.menuArchivo.addAction(self.loadAction) self.menu_Proyecto.addAction(self.propertiesAction) self.menu_Proyecto.addAction(self.discretizeAction) self.menu_Proyecto.addAction(self.executeAction) self.menuA_yuda.addAction(self.action_Instrucciones) self.menubar.addAction(self.menuArchivo.menuAction()) self.menubar.addAction(self.menu_Proyecto.menuAction()) self.menubar.addAction(self.menuA_yuda.menuAction())

self.retranslateUi(MainWindow) self.tabWidget_consolidation.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.graphicsView_ppresure, self.tabWidget_consolidation)

Page 183: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 163

MainWindow.setTabOrder(self.tabWidget_consolidation, self.graphicsView_geometry)

def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Consolidación_1D")) self.label_Titulo.setText(_translate("MainWindow", "CONSOLIDACIÓN 1-D")) self.groupBox_Loads.setTitle(_translate("MainWindow", "Carga de ensayo")) self.labelMostrarCarga.setText(_translate("MainWindow", "0.0 kPa")) self.pushButton_ejecutar.setText(_translate("MainWindow", "E&jecutar")) self.tabWidget_consolidation.setTabText(self.tabWidget_consolidation.indexOf(self.tab_geometry), _translate("MainWindow", "Geometría")) self.tabWidget_consolidation.setTabText(self.tabWidget_consolidation.indexOf(self.tab_elements), _translate("MainWindow", "Elementos")) self.tabWidget_consolidation.setTabText(self.tabWidget_consolidation.indexOf(self.tab_ppressure), _translate("MainWindow", "Presión de poros")) self.tabWidget_consolidation.setTabText(self.tabWidget_consolidation.indexOf(self.tab_def_vertical), _translate("MainWindow", "Def. Vertical")) self.menuArchivo.setTitle(_translate("MainWindow", "&Archivo")) self.menu_Proyecto.setTitle(_translate("MainWindow", "A&nálisis")) self.menuA_yuda.setTitle(_translate("MainWindow", "A&yuda")) self.propertiesAction.setText(_translate("MainWindow", "&Propiedades")) self.discretizeAction.setText(_translate("MainWindow", "&Discretización")) self.fileNewAction.setText(_translate("MainWindow", "&Nuevo")) self.action_Instrucciones.setText(_translate("MainWindow", "&Instrucciones")) self.saveAction.setText(_translate("MainWindow", "&Guardar")) self.loadAction.setText(_translate("MainWindow", "&Cargar")) self.executeAction.setText(_translate("MainWindow", "&Ejecutar")) self.saveAsAction.setText(_translate("MainWindow", "Guardar como..."))

consolidation.pyw# -*- coding: utf-8 -*-"""Created on Fri Aug 2 21:42:23 2019

@author: JOscar"""from __future__ import divisionimport sys

import timeimport numpy as npfrom copy import deepcopyfrom PyQt5 import QtCore, QtGui, QtWidgetsimport matplotlib.pyplot as pltfrom datetime import datetime

Page 184: Desarrollo de un laboratorio virtual de geotecnia enfocado

164 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

from matplotlib.figure import Figurefrom matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas

from consolidation_1D import Ui_MainWindowfrom dialog_input_class import Input_Dlgfrom dialog_file_name_class import FilenameDlgfrom dialog_help_class import HelpDlg

import container

import feamodelimport partmoduleimport multiple_times

__version__ = "1.0.0"

class MiAp(QtWidgets.QMainWindow): def __init__(self, parent = None): QtGui.QGuiApplication.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.filename = None self.container = container.ResultByLoadContainer() self.dirty = self.container._dirty # The container's __dirty supplies this one? # Status bar self.sizeLabel = QtWidgets.QLabel() self.sizeLabel.setFrameStyle(QtWidgets.QFrame.StyledPanel|QtWidgets.QFrame.Sunken) self.status = self.statusBar() self.status.setSizeGripEnabled(False) self.status.addPermanentWidget(self.sizeLabel) self.status.showMessage('Preparado', 5000) # Graphics scene # Geometry self.geometry_scene = QtWidgets.QGraphicsScene(self) self.ui.graphicsView_geometry.setScene(self.geometry_scene) # Elements self.element_scene = QtWidgets.QGraphicsScene(self) self.ui.graphicsView_elements.setScene(self.element_scene) # Pendiente las demás graphicsView # Presión de poros self.presion_scene = QtWidgets.QGraphicsScene(self) self.ui.graphicsView_ppresure.setScene(self.presion_scene)

Page 185: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 165

# Cuva de consolidación self.deformacion_scene = QtWidgets.QGraphicsScene(self) self.ui.graphicsView_Def_Vert.setScene(self.deformacion_scene) # Project options # 'verification' si el usuario ha ingresado propiedades al proyecto # 'flag' si se ha corrido el modelo # Actions and Key sequences #fileNewAction = QtWidgets.QAction('&Nuevo', self) self.ui.fileNewAction.setShortcut(QtGui.QKeySequence.New) helpTextNewfile = 'Crear nuevo archivo' self.ui.fileNewAction.setToolTip(helpTextNewfile) self.ui.fileNewAction.setStatusTip(helpTextNewfile) self.ui.fileNewAction.triggered.connect(self.fileNew) #propertiesAction = QtWidgets.QAction('&Propiedades', self) self.ui.propertiesAction.setShortcut('Ctrl+M') helpTextProperties = 'Propiedades del proyecto' self.ui.propertiesAction.setToolTip(helpTextProperties) self.ui.propertiesAction.setStatusTip(helpTextProperties) self.ui.propertiesAction.triggered.connect(self.set_input_parameters) # discretizeAction = QtWidgets.QAction('&Discretizar', self) self.ui.discretizeAction.setShortcut('Ctrl+D') helpTextDiscretize = 'Discretizar la geometría' self.ui.discretizeAction.setToolTip(helpTextDiscretize) self.ui.discretizeAction.setStatusTip(helpTextDiscretize) self.ui.discretizeAction.triggered.connect(self.discretize) # 'execute' action self.ui.executeAction.setShortcut('Ctrl+E') helpTextExecute = 'Ejecutar el proceso para todas las cargas' self.ui.executeAction.setToolTip(helpTextExecute) self.ui.executeAction.setStatusTip(helpTextExecute) self.ui.executeAction.triggered.connect(self.run_process) # 'save' action self.ui.saveAction.setShortcut('Ctrl+S') helpTextSave = 'Guardar proyecto'# Def qué parámetrs guardar self.ui.saveAction.setToolTip(helpTextSave) self.ui.saveAction.setStatusTip(helpTextSave) self.ui.saveAction.triggered.connect(self.fileSave) # 'saveAs' action self.ui.saveAsAction.setShortcut('Ctrl+G') helpTextSaveAs = 'Guardar en nuevo proyecto' self.ui.saveAsAction.setToolTip(helpTextSaveAs) self.ui.saveAsAction.setStatusTip(helpTextSaveAs) self.ui.saveAsAction.triggered.connect(self.fileSaveAs)

Page 186: Desarrollo de un laboratorio virtual de geotecnia enfocado

166 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# 'load' action self.ui.loadAction.setShortcut('Ctrl+L') helpTextLoad = 'Cargar proyecto' self.ui.loadAction.setToolTip(helpTextLoad) self.ui.loadAction.setStatusTip(helpTextLoad) self.ui.loadAction.triggered.connect(self.fileOpen) # 'Instrucciones' action self.ui.action_Instrucciones.setShortcut('Ctrl+H') helpTextHelp = 'Ayuda' self.ui.action_Instrucciones.setToolTip(helpTextHelp) self.ui.action_Instrucciones.setStatusTip(helpTextHelp) self.ui.action_Instrucciones.triggered.connect(self.helpDialog)

# Las siguientes líneas son obsoletas runProcessAction = QtWidgets.QAction('&Run', self) runProcessAction.setShortcut('Ctrl+R') helpTextRun = 'Ejecutar proceso de consolidación 1D' # Pendiente cómo analizar las dif. cargas runProcessAction.setToolTip(helpTextRun) runProcessAction.setStatusTip(helpTextRun) runProcessAction.triggered.connect(self.run_process) # Signals and Slots self.ui.pushButton_ejecutar.clicked.connect(self.run_process) def closeEvent(self, event): if self.okToContinue(): 1 else: event.ignore() def okToContinue(self): """Asks is the user wants to save the changes""" if self.dirty: reply = QtWidgets.QMessageBox.question(self, 'Consolidación 1-D - cambios no guardados', '¿Guardar ediciones no guardadas?', QtWidgets.QMessageBox.Yes| QtWidgets.QMessageBox.No| QtWidgets.QMessageBox.Cancel) if reply == QtWidgets.QMessageBox.Cancel:

return False elif reply == QtWidgets.QMessageBox.Yes: self.fileSave() return True # Pendiente fileNew method

Page 187: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 167

def fileNew(self): print('probando archivo nuevo') if not self.okToContinue(): return self.filename = None self.container.clear() self.status.clearMessage() # cleaning the images of QGRAFICSWVIEW self.geometry_scene.clear() self.element_scene.clear() self.dirty = False stringsito = '0.0' + ' kPa' self.ui.labelMostrarCarga.setText(stringsito) def fileOpen(self): print('probando fileOpen☺') if not self.okToContinue(): return path = QtCore.QFileInfo(self.container.filename()).path() if not self.container.filename() == str() else '.' fname, formato = QtWidgets.QFileDialog.getOpenFileName(self, 'Consolidación - Cargar datos', path, 'formato de archivos (%s)' %self.container.formats()) if not fname == str(): ok, msg = self.container.load(fname) self.status.showMessage(msg, 5000) ruta = fname.split('/') file = ruta[-1] aux = file.split('.') name = aux[0] print('ok', ok, '\n name', name, '\n formato', formato) if ok: self.filename = name self.discretize()

def fileSave(self): if self.filename == None: self.fileSaveAs() else: if not self.filename.endswith(".mqb"): self.filename += ".mqb" ok, msg = self.container.save(self.filename) if ok: self.dirty = False self.status.showMessage(msg, 5000)

def fileSaveAs(self): print('fileSaveAs') fname = self.filename if self.filename is not None else "." fname, otro = QtWidgets.QFileDialog.getSaveFileName(self,

Page 188: Desarrollo de un laboratorio virtual de geotecnia enfocado

168 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

'Consolidación - Guardar como', fname, 'formato de archivos (%s)' %self.container.formats()) fname = str(fname) if fname: if ".mqb" not in fname: fname += ".mqb" self.filename = fname self.fileSave() def helpDialog(self): helpDlg = HelpDlg(self) if helpDlg.exec_(): 1 def set_input_parameters(self): dialog_inputs = Input_Dlg(self) dialog_inputs.lineEdit_P.setText(str(self.container.dict_project['p'])) dialog_inputs.lineEdit_altura.setText(str(self.container.dict_project['h'])) dialog_inputs.lineEdit_radio.setText(str(self.container.dict_project['r'])) dialog_inputs.lineEdit_tot_unit_weight.setText( str(self.container.dict_project['total_unit_weight'])) dialog_inputs.lineEdit_fluid_unit_weight.setText( str(self.container.dict_project['fluid_unit_weight'])) dialog_inputs.lineEdit_nu.setText(str(self.container.dict_project['nu'])) dialog_inputs.lineEdit_e.setText(str(self.container.dict_project['e'])) dialog_inputs.lineEdit_kh.setText(str(self.container.dict_project['kh'])) dialog_inputs.lineEdit_kv.setText(str(self.container.dict_project['kv'])) dialog_inputs.adv_Dlg.lineEdit_criterium.setText(str(self.container.dict_project['size'])) # To get a filename if self.filename == None: dialog_file_name = FilenameDlg(self) if dialog_file_name.exec_(): if dialog_file_name.lineEdit_FileName.text() == '': return else: self.filename = dialog_file_name.lineEdit_FileName.text() # To save the input parameters if dialog_inputs.exec_(): # To show the dialog modally and return. True if 'Ok' is pressed self.container.dict_project['p'] = float(dialog_inputs.lineEdit_P.text()) self.container.dict_project['h'] = float(dialog_inputs.lineEdit_altura.text()) self.container.dict_project['r'] = float(dialog_inputs.lineEdit_radio.text()) self.container.dict_project['total_unit_weight'] = float( dialog_inputs.lineEdit_tot_unit_weight.text())

Page 189: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 169

self.container.dict_project['fluid_unit_weight'] = float( dialog_inputs.lineEdit_fluid_unit_weight.text()) self.container.dict_project['nu'] = float(dialog_inputs.lineEdit_nu.text()) self.container.dict_project['e'] = float(dialog_inputs.lineEdit_e.text()) self.container.dict_project['kh'] = float(dialog_inputs.lineEdit_kh.text()) self.container.dict_project['kv'] = float(dialog_inputs.lineEdit_kv.text()) if dialog_inputs.criterium != None: self.container.dict_project['size'] = float(dialog_inputs.criterium) self.container.dict_project['verification'] = True self.dirty = True stringsito = str(self.container.dict_project['p']) + ' kPa' self.ui.labelMostrarCarga.setText(stringsito) print(self.container.dict_project) return def discretize(self): print('probando discretización') if self.container.dict_project['verification'] == False: self.status.showMessage('Geometría no especificada', 5000) QtWidgets.QMessageBox.information(self, 'Alerta', 'Geometría no especificada') return # To get a filename if self.filename == None: QtWidgets.QMessageBox.information(self, 'Nombre de proyecto', 'para continuar especifique un nombre al proyecto') dialog_file_name = FilenameDlg(self) if dialog_file_name.exec_(): if dialog_file_name.lineEdit_FileName.text() == '': QtWidgets.QMessageBox.warning(self, 'Nombre de proyecto', 'Discretizacion no realizada') return else: self.filename = dialog_file_name.lineEdit_FileName.text()

self.show_gui = True if '-nogui' in sys.argv: self.show_gui = False self.model = feamodel.FeaModel(self.filename) self.model.set_units('m') eshape = 'tri' if '-tri' in sys.argv: eshape = 'tri' desfase = 0.0 # Drawing the geometry self.part = partmodule.Part(self.model)

Page 190: Desarrollo de un laboratorio virtual de geotecnia enfocado

170 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.part.goto(desfase, desfase) self.part.draw_line_to(desfase + self.container.dict_project['h'], desfase) self.part.draw_line_to(desfase + self.container.dict_project['h'], desfase + self.container.dict_project['r']) self.part.draw_line_to(desfase, desfase + self.container.dict_project['r']) self.part.draw_line_to(desfase, desfase) self.model.set_eshape(eshape, 1) #plstrain #axisym self.model.set_etype('axisym', self.part, 0.1) try: self.status.showMessage('Discretizando...') self.model.mesh(size = self.container.dict_project['size'], meshmode = 'esize', mesher = 'gmsh') except: QtWidgets.QMessageBox.warning(self, 'Nombre de proyecto', 'Discretizacion no realizada')

self.status.showMessage('Discretización terminada', 25000) # Show geometry self.model.plot_geometry(self.filename + 'A0', display = self.show_gui) file_image_geometry = './' + self.filename + 'A0.png' geometry = QtGui.QPixmap(file_image_geometry) self.geometry_scene.addPixmap(geometry) # Show elements self.model.plot_elements(self.filename + 'elem', display = self.show_gui, title = 'Elements', enum = False, nshow = False, nnum = True) file_image_elements = './' + self.filename + 'elem.png' elements = QtGui.QPixmap(file_image_elements) self.element_scene.addPixmap(elements) #Show load stringsito = str(self.container.dict_project['p']) + ' kPa' self.ui.labelMostrarCarga.setText(stringsito) return def run_process(self): print('probando ejecutar proceso') # try: self.status.showMessage('Ejecutando proceso...', 5000) # set constraints self.model.set_load('fluid_press', 'L1', 0) # Presión de poros #cero al iniciar el proceso de drenaje en las fronteras drenantes self.model.set_load('fluid_press', 'L3', 0)# self.model.set_load('fluid_press', 'L2', 0) # self.model.set_constr('fix', self.part.bottom, 'y')

Page 191: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 171

self.model.set_constr('fix', self.part.right, 'y')# self.model.set_constr('fix', self.part.top, 'y') self.model.set_constr('fix', self.part.left, 'y') self.model.set_constr('fix', self.part.bottom, 'x') # x es el eje vertical

# self.model.plot_pressures(self.filename+'_press', display = self.show_gui)# self.model.plot_constraints(self.filename+'_constr', display = self.show_gui)

nu = self.container.dict_project['nu'] kh = self.container.dict_project['kh'] kv = self.container.dict_project['kv'] gt = self.container.dict_project['total_unit_weight'] gf = self.container.dict_project['fluid_unit_weight'] e = self.container.dict_project['e'] h = self.container.dict_project['h'] a = (h/2) # dict_loads = {1: 12500, 2: 25000, 3: 50000}#, 4: 100000, 5: 200000, 6: 400000} # Pa# dict_loads = {1: 12.500, 2: 25.000, 3: 50.000, 4: 100.000, 5: 200.000, 6: 400.000} # kPa dict_loads = {1: self.container.dict_project['p']} # kPa # declarating the problem run_load = multiple_times.Multiple_times(self.model) load_acum = 0 criter_0 = np.arange(0.001, 0.0070, 0.00005)# criter_0 = np.arange(0.001, 0.0070, 0.001) criter_aux = np.array([0.001, 0.001]) criter_0 = np.append(criter_aux, criter_0, axis = 0) criter = np.array([]) for n in criter_0: if n <= 1: criter = np.append(criter, [n], axis = 0) else: criter = np.append(criter, [n**8], axis = 0) load_steps = np.arange(1, len(criter), 1) print('load_steps', load_steps) print('criter', criter)# input("Press Enter to continue...") now = datetime.now() current_time1 = now.strftime("%H:%M:%S") print("Current Time =", current_time1) for n_load, load in enumerate(dict_loads.values()): # set load()

Page 192: Desarrollo de un laboratorio virtual de geotecnia enfocado

172 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

print('load', load) self.model.set_load('press', self.part.top, load, rigid = True) # Positivo es compresión en kPa presion_poros_inicial = 0 # Initial conditions before load application # delta_T list_delta_T = [] run_load.ppress_max_vector = [] for delta_T in criter: #dict_criter.values(): print('delta_T', delta_T) delta_t = 3*gf/((kh+kv)/2)*(1+nu)*(1-2*nu)/(e*(1-nu))*delta_T*a**2 print('delta_t', delta_t)# time.sleep(3.5) run_load.run_multiple_times(presion_poros_inicial, nu, kh, kv, gt, gf, e, load, delta_t=delta_t, h=h) run_load.sistema.primero = 'falso' if list_delta_T == []: list_delta_T.append(delta_T) else: list_delta_T.append(list_delta_T[-1] + delta_T) run_load.sistema.primero = 'verdad' # Dictionary to store the data in a external format resp = np.transpose(run_load.sistema.resp_out) self.container.dict_results[load] = {} self.container.dict_results[load]['resp'] = deepcopy(resp) self.container.dict_results[load]['tamano'] = len(resp) self.container.dict_results[load]['indices'] = np.arange(0, len(resp[0])-1, 1) x = list_delta_T #y = run_load.ppress_max_vector y = run_load.listPresionEnElCentroDeLaMuestra print('load', load) for i, p in enumerate(y): y[i] = -p/(load) for w in [1,2,3]: del x[0] del x[0]

del y[0] del y[0]

print('x', x) print('y', y)# plt.title('Presión de poros')# plt.xscale('log')# plt.grid(True, which='both')# plt.xlabel('T=(λ+2μ)kt/3a²')

Page 193: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 173

# plt.ylabel('p/q')# plt.plot(x, y, 'k.-') # Show pore pressure in GUI figure = Figure() axes = figure.gca() axes.set_title("Presión de poros") axes.plot(x, y, "-k", label="p: presión en el centro de la muestra, q: carga aplicada") axes.set_xscale("log") axes.set_xlabel('T=(λ+2μ)kt/3a²') axes.set_ylabel('p/q') axes.legend() axes.grid(True)

canvas = FigureCanvas(figure) self.presion_scene.addWidget(canvas) self.ui.graphicsView_ppresure.show() # Show curva consolidación in GUI y = run_load.list_desplazamiento x = run_load.list_tiempo figure2 = Figure() axes2 = figure2.gca() axes2.set_title("Curva de consolidación") axes2.plot(x, y, "-k", label="") axes2.set_xscale("log") axes2.set_xlabel('tiempo (s)') axes2.set_ylabel('deformación (%)') axes2.legend() axes2.grid(True)

canvas2 = FigureCanvas(figure2) self.deformacion_scene.addWidget(canvas2) self.ui.graphicsView_Def_Vert.show() # Changing the GUI's load indicator # Show elements self.model.plot_elements(self.filename + 'elem', display = self.show_gui, title = 'Elements', enum = False, nshow = False, nnum = True) # except:# QtWidgets.QMessageBox.warning(self, 'Proyecto', 'Proyecto no especificado')# return dd = run_load._degrees_freedom_d dp = run_load._degrees_freedom_p self.container._degrees_freedom = dd + dp #print('self.container._degrees_freedom', self.container._degrees_freedom)

Page 194: Desarrollo de un laboratorio virtual de geotecnia enfocado

174 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

for id_load in dict_loads.keys(): if id_load != 1: resp_aux = self.container.dict_results[dict_loads[id_load]]['resp'] self.container.dict_results[dict_loads[id_load]]['resp'] = np.delete( resp_aux, self.container.dict_results[dict_loads[id_load-1]]['indices'], axis = 1) #self.container.dict_results = self.dict_results self.container.dict_project['flag'] = True self.dirty = True self.status.showMessage('Proceso terminado', 25000) now = datetime.now() current_time2 = now.strftime("%H:%M:%S") print("Current Time =", current_time1, current_time2) return

if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = MiAp() myapp.show()

# sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys exit(app.exec_())

container.py# -*- coding: utf-8 -*-"""Created on Tue Sep 3 12:00:15 2019

@author: JOscar"""

import bisectimport codecs#import copy_reg#import cPickleimport gzipfrom PyQt5 import QtCore from PyQt5 import QtGui, QtWidgetsfrom PyQt5 import QtXmlimport numpy as np

class ResultByLoad(object): def __init__(self, dict_project, carga_dict, carga): self._dict_project = dict_project self.carga_dict = carga_dict self.carga = carga

Page 195: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 175

class ResultByLoadContainer(object): MAGICNUMBER = 0x3051E FILEVERSION = 100

def __init__(self): self.__fname = str() self.__time = [] self._degrees_freedom = [] self.dict_project = {'p': 12.5, 'h': 0.015, 'r': 0.030, 'total_unit_weight': 16.0, 'fluid_unit_weight': 9.81, 'nu': 0.30, 'e': 6400, 'kh': 0.025, 'kv': 0.05, 'verification': False, 'size': 0.005, 'flag': False} self.dict_results = {} self._dirty = False

def clear(self, clearFilename = True): self.__time = [] self._degrees_freedom = [] self.dict_project = {'p': 12.5, 'h': 0.015, 'r': 0.030, 'total_unit_weight': 16.0, 'fluid_unit_weight': 9.81, 'nu': 0.30, 'e': 6400, 'kh': 0.025, 'kv': 0.05, 'verification': False, 'size': 0.005, 'flag': False} self.dict_results = {} if clearFilename: self.__fname = str() self._dirty = False def add(self): 1

@staticmethod def formats(): return "*.mqb"

def filename(self): if self.__fname == str(): return self.__fname elif self.__fname.endswith(".mqb"): return self.__fname else: self.__fname += (".mqb") return self.__fname

def save(self, fname = str()): if fname != '': self.__fname = fname if self.__fname.endswith(".mqb"): return self.saveQDataStream() return False, "No se pudo guardar: extensión de archivo inválida (se necesita *.mqb)"

Page 196: Desarrollo de un laboratorio virtual de geotecnia enfocado

176 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

def load(self, fname = str()): if fname != '': self.__fname = fname if self.__fname.endswith(".mqb"): return self.loadQDataStream() return False, "No se pudo cargar: extensión de archivo inválida (se necesita *.mqb)" def saveQDataStream(self): error = None fh = None try: fh = QtCore.QFile(self.__fname) if not fh.open(QtCore.QIODevice.WriteOnly): raise IOError(str(fh.errorString())) stream = QtCore.QDataStream(fh) stream.writeInt32(ResultByLoadContainer.MAGICNUMBER) stream.writeInt32(ResultByLoadContainer.FILEVERSION) stream.setVersion(QtCore.QDataStream.Qt_5_9) # guardar los datos requeridos # corroborar que existan las matrices de resultados para todas las cargas # guardar diccionario de proyecto # guardar diccionario de tiempos stream.writeBool(self.dict_project['verification']) if self.dict_project['verification'] == True: stream.writeDouble(self.dict_project['p']) stream.writeDouble(self.dict_project['h']) stream.writeDouble(self.dict_project['r']) stream.writeDouble(self.dict_project['total_unit_weight'])

stream.writeDouble(self.dict_project['fluid_unit_weight']) stream.writeDouble(self.dict_project['nu']) stream.writeDouble(self.dict_project['e']) stream.writeDouble(self.dict_project['kh']) stream.writeDouble(self.dict_project['kv']) stream.writeDouble(self.dict_project['size']) stream.writeBool(self.dict_project['flag']) self.dict_project['flag'] = False if self.dict_project['flag'] == True: # Guardar las matrices en otro formato print('self.dict_results.keys()', self.dict_results.keys()) resp = [np.array([]), np.array([]), np.array([]), np.array([]), np.array([]), np.array([])] for i, load in enumerate(self.dict_results.keys(), start=0): str_filename = self.filename() if str_filename.endswith('.mqb'): str_filename, b = str_filename.split('.', 2) str_load = load

Page 197: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 177

print('str_load', str_load) resp[i] = self.dict_results[load]['resp'] np.savez_compressed(str_filename, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5]) # Guardar las posiciones de los grados de libertad en la # matriz general del sistema for degree in self._degrees_freedom: for nodeid in degree.keys(): print('self._degrees_freedom:', self._degrees_freedom) if not isinstance(nodeid, str): stream.writeInt32(nodeid) if degree[nodeid] == 'uy': code = 1 elif degree[nodeid] == 'ux': code = 2 elif degree[nodeid] == 'fluid_press': code = 3 else: code = 100 stream.writeInt32(code) elif nodeid == 'list': lenlist = len(degree['list']) stream.writeInt32(ResultByLoadContainer.MAGICNUMBER) stream.writeInt32(lenlist) for nodei in degree['list']: stream.writeInt32(nodei)

except (IOError, OSError): error = "No se puede guardar el archivo" print('error', error)

finally: if fh is not None: fh.close() if error is not None: return False, error self._dirty = False return True, "Datos de %s guardados" %( QtCore.QFileInfo(fh).fileName()) def loadQDataStream(self): error = None fh = None try: fh = QtCore.QFile(self.__fname) if not fh.open(QtCore.QIODevice.ReadOnly): raise IOError(str(fh.errorString()))

Page 198: Desarrollo de un laboratorio virtual de geotecnia enfocado

178 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

stream = QtCore.QDataStream(fh) magic = stream.readInt32() if magic != ResultByLoadContainer.MAGICNUMBER: raise IOError("Tipo de archivo no reconocido") version = stream.readInt32() if version < ResultByLoadContainer.FILEVERSION: raise IOError("Formato de archivo obsoleto no legible") if version > ResultByLoadContainer.FILEVERSION: raise IOError("Formato de archivo nuevo no legible") stream.setVersion(QtCore.QDataStream.Qt_5_9) # Borra los datos guardados en una sesión pero no su nombre(filename) self.clear(False) verification = stream.readBool() print(verification, 'verification') flag = False if verification == True: p = stream.readDouble() h = stream.readDouble() r = stream.readDouble() total_unit_weight = stream.readDouble() fluid_unit_weight = stream.readDouble() nu = stream.readDouble() e = stream.readDouble() kh = stream.readDouble() kv = stream.readDouble() size = stream.readDouble() flag = stream.readBool()

self.dict_project = {'p': p, 'h': h, 'r': r, 'total_unit_weight': total_unit_weight, 'fluid_unit_weight': fluid_unit_weight, 'nu': nu, 'e': e, 'kh': kh, 'kv': kv, 'verification': verification, 'size': size, 'flag': flag} print('self.dict_project', self.dict_project) flag = False # Pendiente cargar resultados del análisis if flag: _fname = self.__fname if self.__fname.endswith('.mqb'): _fname, otro = _fname.split('.', 2) _fname += '.npz' loaded = np.load(_fname)

self.dict_results[12500] = loaded['arr_0'] self.dict_results[25000] = loaded['arr_1'] self.dict_results[50000] = loaded['arr_2'] self.dict_results[100000] = loaded['arr_3'] self.dict_results[200000] = loaded['arr_4'] self.dict_results[400000] = loaded['arr_5'] print('cargados resultados')

Page 199: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 179

while not stream.atEnd(): # Falta cargar lo datos guardados en saveQDataStream() nodeid = stream.readInt32() if nodeid != ResultByLoadContainer.MAGICNUMBER: dicc = {} print('nodeid', nodeid) code = stream.readInt32() print('code', code) if code == 1: component = 'uy' elif code == 2: component = 'ux' elif code == 3: component = 'fluid_press' else: component = 'error' dicc[nodeid] = component print('dicc', dicc) self._degrees_freedom.append(dicc) elif nodeid == ResultByLoadContainer.MAGICNUMBER: dicc = {} lenlist = stream.readInt32() lista = [] vector_aux = np.arange(0, lenlist, 1) for i in vector_aux: a = stream.readInt32() lista.append(a) dicc['list'] = lista print(dicc, dicc) self._degrees_freedom.append(dicc) print('self._degrees_freedom', self._degrees_freedom) except (IOError, OSError): error = "No se ha podido cargar el archivo" finally: if fh is not None: fh.close() if error is not None: return False, error self._dirty = False return True, "Datos de %s cargados" % ( QtCore.QFileInfo(self.__fname).fileName())

container2.py# -*- coding: utf-8 -*-"""

Page 200: Desarrollo de un laboratorio virtual de geotecnia enfocado

180 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Created on Tue Sep 3 12:00:15 2019

@author: JOscar"""

import bisectimport codecs#import copy_reg#import cPickleimport gzipfrom PyQt5 import QtCore from PyQt5 import QtGui, QtWidgetsfrom PyQt5 import QtXmlimport numpy as np

class ResultByLoad(object): def __init__(self, dict_project, carga_dict, carga): self._dict_project = dict_project self.carga_dict = carga_dict self.carga = carga self.listH = [] self.listSigma = [] class ResultByLoadContainer(object): MAGICNUMBER = 0x3052E FILEVERSION = 100

def __init__(self): self.__fname = str() self.__time = [] self._degrees_freedom = [] self.listH = [] self.listSigma = [] self.dict_project = {'s1': 12.5, 's3': 0,'h': 0.015, 'r': 0.030, 'total_unit_weight': 16.0, 'nu': 0.30, 'e': 6400, 'c': 0.025, 'phi': 0.05, 'verification': False, 'size': 0.005, 'flag': False, 'listH': self.listH, 'listSigma': self.listSigma, 'n': 30} self.dict_results = {} self._dirty = False

def clear(self, clearFilename = True): self.__time = [] self._degrees_freedom = [] self.listH = [] self.listSigma = [] self.dict_project = {'s1': 12.5, 's3': 0, 'h': 0.015, 'r': 0.030, 'total_unit_weight': 16.0, 'nu': 0.30, 'e': 6400,

Page 201: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 181

'c': 0.025, 'phi': 0.05, 'verification': False, 'size': 0.005, 'flag': False, 'listH': self.listH, 'listSigma': self.listSigma, 'n': 30} self.dict_results = {} if clearFilename: self.__fname = str() self._dirty = False def add(self): 1

@staticmethod def formats(): return "*.mqb"

def filename(self): if self.__fname == str(): return self.__fname elif self.__fname.endswith(".mqb"): return self.__fname else: self.__fname += (".mqb") return self.__fname

def save(self, fname = str()): if fname != '': self.__fname = fname if self.__fname.endswith(".mqb"): return self.saveQDataStream() return False, "No se pudo guardar: extensión de archivo inválida (se necesita *.mqb)" def load(self, fname = str()): if fname != '': self.__fname = fname if self.__fname.endswith(".mqb"): return self.loadQDataStream() return False, "No se pudo cargar: extensión de archivo inválida (se necesita *.mqb)" def saveQDataStream(self): error = None fh = None try: fh = QtCore.QFile(self.__fname) if not fh.open(QtCore.QIODevice.WriteOnly): raise IOError(str(fh.errorString())) stream = QtCore.QDataStream(fh) stream.writeInt32(ResultByLoadContainer.MAGICNUMBER) stream.writeInt32(ResultByLoadContainer.FILEVERSION)

Page 202: Desarrollo de un laboratorio virtual de geotecnia enfocado

182 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

stream.setVersion(QtCore.QDataStream.Qt_5_9) # Guardar los datos requeridos # corroborar que existan las matrices de resultados para todas las cargas # guardar diccionario de proyecto # guardar diccionario de tiempos

stream.writeBool(self.dict_project['verification']) if self.dict_project['verification'] == True: stream.writeDouble(self.dict_project['s1']) stream.writeDouble(self.dict_project['s3']) stream.writeDouble(self.dict_project['h']) stream.writeDouble(self.dict_project['r']) stream.writeDouble(self.dict_project['total_unit_weight']) stream.writeDouble(self.dict_project['nu']) stream.writeDouble(self.dict_project['e']) stream.writeDouble(self.dict_project['c']) stream.writeDouble(self.dict_project['phi'])

stream.writeDouble(self.dict_project['size']) stream.writeBool(self.dict_project['flag']) # escribir para guardar las listas H y Sigma m = len(self.listH) stream.writeInt32(m) for i in self.listH: stream.writeDouble(i) for i in self.listSigma: stream.writeDouble(i) # por último los pasos de análisis en que se divide la carga stream.writeInt32(self.dict_project['n'])

# Falta implementar para guardar respuestas (no implementado, código muerto) self.dict_project['flag'] = False if self.dict_project['flag'] == True: # Guardar las matrices en otro formato print('self.dict_results.keys()', self.dict_results.keys()) resp = [np.array([]), np.array([]), np.array([]), np.array([]), np.array([]), np.array([])] for i, load in enumerate(self.dict_results.keys(), start=0): str_filename = self.filename() if str_filename.endswith('.mqb'): str_filename, b = str_filename.split('.', 2) str_load = load print('str_load', str_load) resp[i] = self.dict_results[load]['resp'] np.savez_compressed(str_filename, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5])

Page 203: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 183

# Guardar las posiciones de los grados de libertad en la # matriz general del sistema for degree in self._degrees_freedom: for nodeid in degree.keys(): print('self._degrees_freedom:', self._degrees_freedom) if not isinstance(nodeid, str): stream.writeInt32(nodeid) if degree[nodeid] == 'uy': code = 1 elif degree[nodeid] == 'ux': code = 2 elif degree[nodeid] == 'fluid_press': code = 3 else: code = 100 stream.writeInt32(code) elif nodeid == 'list': lenlist = len(degree['list']) stream.writeInt32(ResultByLoadContainer.MAGICNUMBER) stream.writeInt32(lenlist) for nodei in degree['list']: stream.writeInt32(nodei)

except (IOError, OSError): error = "No se puede guardar el archivo" print('error', error)

finally: if fh is not None: fh.close() if error is not None: return False, error self._dirty = False return True, "Datos de %s guardados" %( QtCore.QFileInfo(fh).fileName())

def loadQDataStream(self): error = None fh = None try: fh = QtCore.QFile(self.__fname) if not fh.open(QtCore.QIODevice.ReadOnly): raise IOError(str(fh.errorString())) stream = QtCore.QDataStream(fh) magic = stream.readInt32()

if magic != ResultByLoadContainer.MAGICNUMBER: raise IOError("Tipo de archivo no reconocido")

Page 204: Desarrollo de un laboratorio virtual de geotecnia enfocado

184 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

version = stream.readInt32() if version < ResultByLoadContainer.FILEVERSION: raise IOError("Formato de archivo obsoleto no legible") if version > ResultByLoadContainer.FILEVERSION: raise IOError("Formato de archivo nuevo no legible") stream.setVersion(QtCore.QDataStream.Qt_5_9)

# Borra los datos guardados en una sesión pero no su nombre(filename) self.clear(False) verification = stream.readBool() print(verification, 'verification') flag = False if verification == True: s1 = stream.readDouble() s3 = stream.readDouble() h = stream.readDouble() r = stream.readDouble() total_unit_weight = stream.readDouble() nu = stream.readDouble() e = stream.readDouble() c = stream.readDouble() phi = stream.readDouble() size = stream.readDouble() flag = stream.readBool() # m es el tamaño de listH y listSigma m = stream.readInt32() tamano = np.arange(0, m, 1) for a in tamano: i = stream.readDouble() self.listH.append(i) for b in tamano: i = stream.readDouble() self.listSigma.append(i) # por último los pasos de análisis en que se divide la carga n = stream.readInt32() self.dict_project = {'s1': s1, 's3': s3,'h': h, 'r': r, 'total_unit_weight': total_unit_weight, 'nu': nu, 'e': e, 'c': c, 'phi': phi, 'verification': verification,

'size': size, 'flag': flag, 'listH': self.listH, 'listSigma': self.listSigma, 'n': n} # Lo siguiente es código muerto flag = False if flag: _fname = self.__fname if self.__fname.endswith('.mqb'): _fname, otro = _fname.split('.', 2)

Page 205: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 185

_fname += '.npz' loaded = np.load(_fname)

self.dict_results[12500] = loaded['arr_0'] self.dict_results[25000] = loaded['arr_1'] self.dict_results[50000] = loaded['arr_2'] self.dict_results[100000] = loaded['arr_3'] self.dict_results[200000] = loaded['arr_4'] self.dict_results[400000] = loaded['arr_5'] print('cargados resultados') while not stream.atEnd(): # Falta cargar lo datos guardados en saveQDataStream() nodeid = stream.readInt32() if nodeid != ResultByLoadContainer.MAGICNUMBER: dicc = {} print('nodeid', nodeid) code = stream.readInt32() print('code', code) if code == 1: component = 'uy' elif code == 2: component = 'ux' elif code == 3: component = 'fluid_press' else: component = 'error' dicc[nodeid] = component print('dicc', dicc) self._degrees_freedom.append(dicc) elif nodeid == ResultByLoadContainer.MAGICNUMBER: dicc = {} lenlist = stream.readInt32() lista = [] vector_aux = np.arange(0, lenlist, 1) for i in vector_aux: a = stream.readInt32() lista.append(a) dicc['list'] = lista print(dicc, dicc) self._degrees_freedom.append(dicc) print('self._degrees_freedom', self._degrees_freedom) except (IOError, OSError): error = "No se ha podido cargar el archivo" finally: if fh is not None:

Page 206: Desarrollo de un laboratorio virtual de geotecnia enfocado

186 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

fh.close() if error is not None: return False, error self._dirty = False return True, "Datos de %s cargados" % ( QtCore.QFileInfo(self.__fname).fileName())dialog_advanced_input_class.py# -*- coding: utf-8 -*-"""Created on Sun Aug 18 12:31:04 2019

@author: JOscar"""

import sysimport refrom math import inffrom PyQt5 import QtCore, QtGui, QtWidgetsfrom dialog_advanced_input_interface import Ui_Dialog_Advanced_Input

class Input_Adv_Dlg(QtWidgets.QDialog, Ui_Dialog_Advanced_Input): def __init__(self, parent = None): super(Input_Adv_Dlg, self).__init__(parent) self.setupUi(self) self.parent = parent if parent != None: self.h = float(parent.lineEdit_altura.text()) self.r = float(parent.lineEdit_radio.text()) else: self.h = inf self.r = inf # Signals and slots self.pushButton_Ok.clicked.connect(self.corroborate) self.pushButton_Cancel.clicked.connect(self.reject)

def corroborate(self): # raise error if self.parent != None: self.h = float(self.parent.lineEdit_altura.text()) self.r = float(self.parent.lineEdit_radio.text()) class N_error(Exception): pass # Negative value class G_error(Exception): pass # Value greater than geometry message = '' try: criterium = float(self.lineEdit_criterium.text()) c2 = 1/criterium try: if c2 < 0:

Page 207: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 187

raise N_error except N_error: message = message + 'Error valor ingresado: no se admiten # negativos \n' try: if criterium > self.h or criterium > self.r: raise G_error except G_error: message = message + 'Error valor ingresado: se requiere valor menor a la geometría ingresada\n' except: message = 'Valor no válido' if message != '': QtWidgets.QMessageBox.warning(self, "Error valor ingresado", message) return self.accept() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = Input_Adv_Dlg() myapp.show() # sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys exit(app.exec_())

dialog_advanced_input_interface.py# -*- coding: utf-8 -*-"""Created on Sun Aug 18 12:28:15 2019

@author: JOscar"""

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog_Advanced_Input(object): def setupUi(self, Dialog_Advanced_Input): Dialog_Advanced_Input.setObjectName("Dialog_Advanced_Input") Dialog_Advanced_Input.resize(182, 92) self.gridLayout = QtWidgets.QGridLayout(Dialog_Advanced_Input) self.gridLayout.setObjectName("gridLayout") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.label_criterium = QtWidgets.QLabel(Dialog_Advanced_Input) self.label_criterium.setObjectName("label_criterium") self.verticalLayout.addWidget(self.label_criterium) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout")

Page 208: Desarrollo de un laboratorio virtual de geotecnia enfocado

188 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.lineEdit_criterium = QtWidgets.QLineEdit(Dialog_Advanced_Input) self.lineEdit_criterium.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_criterium.setObjectName("lineEdit_criterium") self.horizontalLayout.addWidget(self.lineEdit_criterium) self.label = QtWidgets.QLabel(Dialog_Advanced_Input)

self.label.setWhatsThis("") self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.verticalLayout.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem2) self.pushButton_Ok = QtWidgets.QPushButton(Dialog_Advanced_Input) self.pushButton_Ok.setObjectName("pushButton_Ok") self.horizontalLayout_2.addWidget(self.pushButton_Ok) self.pushButton_Cancel = QtWidgets.QPushButton(Dialog_Advanced_Input) self.pushButton_Cancel.setObjectName("pushButton_Cancel") self.horizontalLayout_2.addWidget(self.pushButton_Cancel) self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1) self.label_criterium.setBuddy(self.lineEdit_criterium)

self.retranslateUi(Dialog_Advanced_Input) QtCore.QMetaObject.connectSlotsByName(Dialog_Advanced_Input) Dialog_Advanced_Input.setTabOrder(self.lineEdit_criterium, self.pushButton_Ok) Dialog_Advanced_Input.setTabOrder(self.pushButton_Ok, self.pushButton_Cancel)

def retranslateUi(self, Dialog_Advanced_Input): _translate = QtCore.QCoreApplication.translate Dialog_Advanced_Input.setWindowTitle(_translate("Dialog_Advanced_Input", "Dialog")) self.label_criterium.setText(_translate("Dialog_Advanced_Input", "&Criterio de discretización (metros)")) self.lineEdit_criterium.setText(_translate("Dialog_Advanced_Input", "0.005")) self.label.setToolTip(_translate("Dialog_Advanced_Input", "Valor utilizado como criterio para discretizar la geometría, depende de la geometría de la muestra (es el posible tamaño de los lados de los elementos triangulares)")) self.label.setText(_translate("Dialog_Advanced_Input", "?")) self.pushButton_Ok.setText(_translate("Dialog_Advanced_Input", "&Ok")) self.pushButton_Cancel.setText(_translate("Dialog_Advanced_Input", "&Cancelar"))

Page 209: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 189

dialog_file_name_class.py# -*- coding: utf-8 -*-"""Created on Thu Aug 8 22:01:07 2019

@author: JOscar"""

import sysimport refrom PyQt5 import QtCore, QtGui, QtWidgetsfrom dialog_file_name_interface import Ui_Dialog_File_Name

class FilenameDlg(QtWidgets.QDialog, Ui_Dialog_File_Name): def __init__(self, parent = None): super(FilenameDlg, self).__init__(parent) self.setupUi(self) self.pushButton_Ok.clicked.connect(self.accept) self.pushButton_Cancel.clicked.connect(self.reject)

if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = FilenameDlg() myapp.show() # sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys exit(app.exec_())

dialog_file_name_interface.py# -*- coding: utf-8 -*-"""Created on Thu Aug 8 21:59:50 2019

@author: JOscar"""

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog_File_Name(object): def setupUi(self, Dialog_File_Name): Dialog_File_Name.setObjectName("Dialog_File_Name") Dialog_File_Name.resize(220, 93) self.gridLayout = QtWidgets.QGridLayout(Dialog_File_Name) self.gridLayout.setObjectName("gridLayout") self.label_File_Name = QtWidgets.QLabel(Dialog_File_Name) self.label_File_Name.setObjectName("label_File_Name") self.gridLayout.addWidget(self.label_File_Name, 0, 0, 1, 1) self.lineEdit_FileName = QtWidgets.QLineEdit(Dialog_File_Name) self.lineEdit_FileName.setObjectName("lineEdit_FileName")

Page 210: Desarrollo de un laboratorio virtual de geotecnia enfocado

190 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.gridLayout.addWidget(self.lineEdit_FileName, 1, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.pushButton_Ok = QtWidgets.QPushButton(Dialog_File_Name) self.pushButton_Ok.setObjectName("pushButton_Ok") self.horizontalLayout.addWidget(self.pushButton_Ok) self.pushButton_Cancel = QtWidgets.QPushButton(Dialog_File_Name) self.pushButton_Cancel.setObjectName("pushButton_Cancel") self.horizontalLayout.addWidget(self.pushButton_Cancel) self.gridLayout.addLayout(self.horizontalLayout, 2, 0, 1, 1) self.label_File_Name.setBuddy(self.lineEdit_FileName)

self.retranslateUi(Dialog_File_Name) QtCore.QMetaObject.connectSlotsByName(Dialog_File_Name)

def retranslateUi(self, Dialog_File_Name): _translate = QtCore.QCoreApplication.translate Dialog_File_Name.setWindowTitle(_translate("Dialog_File_Name", "Dialog")) self.label_File_Name.setText(_translate("Dialog_File_Name", "&Dar nombre al proyecto:")) self.pushButton_Ok.setText(_translate("Dialog_File_Name", "&Ok")) self.pushButton_Cancel.setText(_translate("Dialog_File_Name", "&Cancelar"))

dialog_help.py# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'dialog_help.ui'## Created by: PyQt5 UI code generator 5.11.3## WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(687, 517) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.toolBox = QtWidgets.QToolBox(Dialog) self.toolBox.setObjectName("toolBox") self.pageDescripcionGeneral = QtWidgets.QWidget() self.pageDescripcionGeneral.setGeometry(QtCore.QRect(0, 0, 652, 757)) self.pageDescripcionGeneral.setObjectName("pageDescripcionGeneral") self.formLayout = QtWidgets.QFormLayout(self.pageDescripcionGeneral) self.formLayout.setObjectName("formLayout")

Page 211: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 191

self.labelDescripcion = QtWidgets.QLabel(self.pageDescripcionGeneral) self.labelDescripcion.setTextFormat(QtCore.Qt.RichText) self.labelDescripcion.setObjectName("labelDescripcion") self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.labelDescripcion) self.toolBox.addItem(self.pageDescripcionGeneral, "") self.pageVariablesEntrada = QtWidgets.QWidget() self.pageVariablesEntrada.setGeometry(QtCore.QRect(0, 0, 669, 418)) self.pageVariablesEntrada.setObjectName("pageVariablesEntrada") self.formLayout_2 = QtWidgets.QFormLayout(self.pageVariablesEntrada)

self.formLayout_2.setObjectName("formLayout_2") self.labelVariablesEntrada = QtWidgets.QLabel(self.pageVariablesEntrada) self.labelVariablesEntrada.setObjectName("labelVariablesEntrada") self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.labelVariablesEntrada) self.toolBox.addItem(self.pageVariablesEntrada, "") self.pageResultados = QtWidgets.QWidget() self.pageResultados.setGeometry(QtCore.QRect(0, 0, 652, 446)) self.pageResultados.setObjectName("pageResultados") self.formLayout_3 = QtWidgets.QFormLayout(self.pageResultados) self.formLayout_3.setObjectName("formLayout_3") self.labelResultados = QtWidgets.QLabel(self.pageResultados) self.labelResultados.setObjectName("labelResultados") self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.labelResultados) self.toolBox.addItem(self.pageResultados, "") self.gridLayout.addWidget(self.toolBox, 1, 0, 1, 1)

self.retranslateUi(Dialog) self.toolBox.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(Dialog)

def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate

Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.labelDescripcion.setText(_translate("Dialog", "<html><head/><body><p align=\"justify\">Simulación del proceso de consolidación para materiales porosos elásticos cuya geometría corresponda a un sólido de revolución,</p><p align=\"justify\">bajo las condiciones de frontera de un ensayo edométrico.</p><p align=\"justify\">Los pasos para realizar el análisis son:</p><p align=\"justify\">1. Generación de la geometría</p><p align=\"justify\">2. Digitación de los variables de entrada</p><p align=\"justify\">2. Discretización de la geometría</p><p align=\"justify\">3. Ejecución del programa</p><p align=\"center\"><img src=\":/newPrefix/imagenConsolidacion.png\"/></p></body></html>")) self.toolBox.setItemText(self.toolBox.indexOf(self.pageDescripcionGeneral), _translate("Dialog", "Descripción general")) self.labelVariablesEntrada.setText(_translate("Dialog", "<html><head/><body><p>Se deben ingresar las variables en la ruta &quot;Análisis&quot; &gt; &quot;Propiedades&quot;:</p><p>Carga de ensayo P en kPa</p><p>La geometría consiste en un sólido de revolución de radio (r) y altura (h) en

Page 212: Desarrollo de un laboratorio virtual de geotecnia enfocado

192 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

metros</p><p>El peso unitario total del suelo y del fluido de poros en kN/m3</p><p>El módulo de Young en Kpa</p><p>La relación de Poisson, adimensional</p><p>La permeabilidad horizontal kh y vertical del material kv en m/s</p><p><br/></p><p>El algortimo de discretización requiere de un valor de entrada consistente en el tamaño deseado de</p><p>para los lados del elemento triangular de la malla por elementos finitos, este puede ser ingresado</p><p>en la ruta &quot;Análisis&quot; &gt; &quot;Propiedades&quot; &gt; &quot;Avanzado&quot;</p></body></html>")) self.toolBox.setItemText(self.toolBox.indexOf(self.pageVariablesEntrada), _translate("Dialog", "Variables de entrada")) self.labelResultados.setText(_translate("Dialog", "<html><head/><body><p>Para el análisis de resultados se provee:</p><p><br/></p><p>1. la curva de disipación de la razón adimensional entre la presión de poros en el centro de la muestra </p><p>(p) y la carga aplicada (q); (p/q) y el tiempo definido adimensional (T) para este problema como:</p><p><br/></p><p>ΔT = (1/3)(k/<span style=\" font-weight:600;\">γ</span><span style=\" font-weight:600; vertical-align:sub;\">w</span> )E(1-ν)/((1+ν)(1-2ν))(Δt/a²)<br/></p><p>en donde:</p><p>a es la mitad de la altura de la muestra:</p><p>k es la permeabilidad promedio</p><p>E el módulo de Young</p><p>v la relación de Pooison</p><p>Δt el tiempo en segundos</p><p><span style=\" font-weight:600;\">γ</span><span style=\" font-weight:600; vertical-align:sub;\">w </span>es el peso unitario del agua<br/></p><p>2. la curva de consolidación definida como la deformación en función del tiempo s en segundos</p><p><br/></p></body></html>")) self.toolBox.setItemText(self.toolBox.indexOf(self.pageResultados), _translate("Dialog", "Resultados"))

import test_rc

dialog_help_class.py# -*- coding: utf-8 -*-"""Created on Thu Aug 8 22:01:07 2019

@author: JOscar"""

import sysimport refrom PyQt5 import QtCore, QtGui, QtWidgetsfrom dialog_help import Ui_Dialog

class HelpDlg(QtWidgets.QDialog, Ui_Dialog): def __init__(self, parent = None): super(HelpDlg, self).__init__(parent) self.setupUi(self)

if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = HelpDlg() myapp.show() # sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys

Page 213: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 193

exit(app.exec_())

dialog_help_trx.py# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'dialog_help_trx.ui'## Created by: PyQt5 UI code generator 5.11.3## WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(745, 517) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.toolBox = QtWidgets.QToolBox(Dialog) self.toolBox.setObjectName("toolBox") self.pageDescripcionGeneral = QtWidgets.QWidget() self.pageDescripcionGeneral.setGeometry(QtCore.QRect(0, 0, 710, 1470)) self.pageDescripcionGeneral.setObjectName("pageDescripcionGeneral") self.formLayout = QtWidgets.QFormLayout(self.pageDescripcionGeneral) self.formLayout.setObjectName("formLayout") self.labelDescripcion = QtWidgets.QLabel(self.pageDescripcionGeneral) self.labelDescripcion.setTextFormat(QtCore.Qt.RichText) self.labelDescripcion.setObjectName("labelDescripcion") self.formLayout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.labelDescripcion) self.toolBox.addItem(self.pageDescripcionGeneral, "") self.pageVariablesEntrada = QtWidgets.QWidget() self.pageVariablesEntrada.setGeometry(QtCore.QRect(0, 0, 727, 418)) self.pageVariablesEntrada.setObjectName("pageVariablesEntrada") self.formLayout_2 = QtWidgets.QFormLayout(self.pageVariablesEntrada) self.formLayout_2.setObjectName("formLayout_2") self.labelVariablesEntrada = QtWidgets.QLabel(self.pageVariablesEntrada) self.labelVariablesEntrada.setObjectName("labelVariablesEntrada") self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.labelVariablesEntrada) self.toolBox.addItem(self.pageVariablesEntrada, "") self.pageResultados = QtWidgets.QWidget() self.pageResultados.setGeometry(QtCore.QRect(0, 0, 727, 418)) self.pageResultados.setObjectName("pageResultados") self.formLayout_3 = QtWidgets.QFormLayout(self.pageResultados) self.formLayout_3.setObjectName("formLayout_3") self.labelResultados = QtWidgets.QLabel(self.pageResultados) self.labelResultados.setObjectName("labelResultados")

Page 214: Desarrollo de un laboratorio virtual de geotecnia enfocado

194 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.labelResultados) self.toolBox.addItem(self.pageResultados, "") self.gridLayout.addWidget(self.toolBox, 1, 0, 1, 1)

self.retranslateUi(Dialog) self.toolBox.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(Dialog)

def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.labelDescripcion.setText(_translate("Dialog", "<html><head/><body><p align=\"justify\">Simulación de la etapa de compresión triaxial para materiales que endurecen por deformación según la función de fluencia de Drucker y Prager.</p><p align=\"justify\">Los pasos para realizar el análisis son:</p><p align=\"justify\">1. Generación de la geometría</p><p align=\"justify\">2. Digitación de los variables de entrada</p><p align=\"justify\">2. Discretización de la geometría</p><p align=\"justify\">3. Ejecución del programa</p><p align=\"justify\"><br/></p><p align=\"justify\"><img src=\":/newPrefixTrx/imagenTRX.png\"/></p></body></html>")) self.toolBox.setItemText(self.toolBox.indexOf(self.pageDescripcionGeneral), _translate("Dialog", "Descripción general")) self.labelVariablesEntrada.setText(_translate("Dialog", "<html><head/><body><p>Se deben ingresar las variables en la ruta &quot;Análisis&quot; &gt; &quot;Propiedades&quot;:</p><p>Carga de ensayo P en kPa</p><p>La geometría consiste en un sólido de revolución de radio (r) y altura (h) en metros</p><p>El peso unitario total del suelo en kN/m3</p><p>El módulo de Young E en Kpa</p><p>La relación de Poisson, adimensional</p><p>La cohesión c en kPa y el ángulo de fricción en ° (grados)</p><p>La pendiente de la curva esfuerzo - deformación en el rango elastoplástico H\' en la tabla Sigma vs H\'</p><p><br/></p><p>El algortimo de discretización requiere de un valor de entrada consistente en el tamaño deseado de</p><p>para los lados del elemento triangular de la malla por elementos finitos, este puede ser ingresado</p><p>en la ruta &quot;Análisis&quot; &gt; &quot;Propiedades&quot; &gt; &quot;Avanzado&quot;</p></body></html>")) self.toolBox.setItemText(self.toolBox.indexOf(self.pageVariablesEntrada), _translate("Dialog", "Variables de entrada")) self.labelResultados.setText(_translate("Dialog", "<html><head/><body><p>Para el análisis de resultados se proveen las curvas:<br/></p><p>1. Esfuerzo desviador q\' vs deformación cortante <span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt;\">ε</span><span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt; vertical-align:sub;\">s</span></p><p>2. Esfuerzo desviador q\' vs esfuerzo promedio p\'</p><p>3. Deformación voluméntrica <span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt;\">ε</span><span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt; vertical-align:sub;\">v</span> vs deformación cortante <span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt;\">ε</span><span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt; vertical-align:sub;\">s</span></p><p>4. Volumen v vs esfuerzo promedio p\'</p><p>5. Esfuerzo desviador q\' vs deformación axial <span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt;\">ε</span><span style=\" font-family:\'Arial,sans-serif\'; font-size:13pt; vertical-align:sub;\">a</span></p><p><br/></p></body></html>"))

Page 215: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 195

self.toolBox.setItemText(self.toolBox.indexOf(self.pageResultados), _translate("Dialog", "Resultados"))

import test_rc

dialog_help_trx_class.py# -*- coding: utf-8 -*-"""Created on Thu Aug 8 22:01:07 2019

@author: JOscar"""

import sysimport refrom PyQt5 import QtCore, QtGui, QtWidgetsfrom dialog_help_trx import Ui_Dialog

class HelpDlg(QtWidgets.QDialog, Ui_Dialog): def __init__(self, parent = None): super(HelpDlg, self).__init__(parent) self.setupUi(self)

if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = HelpDlg() myapp.show() # sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys exit(app.exec_())

dialog_input_class.py# -*- coding: utf-8 -*-"""Created on Tue Aug 6 14:18:17 2019

@author: JOscar"""

import sysimport refrom PyQt5 import QtCore, QtGui, QtWidgetsfrom dialog_input_interface import Ui_Dialog_Inputsfrom dialog_advanced_input_class import Input_Adv_Dlg

class Input_Dlg(QtWidgets.QDialog, Ui_Dialog_Inputs): def __init__(self, parent = None): super(Input_Dlg, self).__init__(parent) self.setupUi(self) self.adv_Dlg = Input_Adv_Dlg(self)

Page 216: Desarrollo de un laboratorio virtual de geotecnia enfocado

196 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.criterium = None self.pushButton_Ok.clicked.connect(self.corroborate) self.pushButton_Cancel.clicked.connect(self.reject) self.pushButton_Advanced.clicked.connect(self.set_Adv) def isanumber(self, a): try: float(repr(a)) bool_a = True except: bool_a = False print(bool_a) return bool_a def set_Adv(self): if self.adv_Dlg.exec_(): self.criterium = float(self.adv_Dlg.lineEdit_criterium.text()) def corroborate(self): # Raise error class Nu_error(Exception): pass message = '' try: p = float(self.lineEdit_P.text()) except: message = message + "Error valor ingresado: Carga (P) no válida \n"

try: h = float(self.lineEdit_altura.text()) except: message = message + "Error valor ingresado: Altura (h) no válida \n"

try: r = float(self.lineEdit_radio.text()) except: message = message + "Error valor ingresado: Radio (r) no válido \n" try: gt = float(self.lineEdit_tot_unit_weight.text()) except: message = message + "Error valor ingresado: Peso unitario total no válido \n" try: gw = float(self.lineEdit_fluid_unit_weight.text()) except: message = message + "Error valor ingresado: Peso unitario de fluido no válido \n" try: nu = float(self.lineEdit_nu.text()) try:

Page 217: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 197

if nu > 0.5: raise Nu_error elif nu < 0: raise Nu_error except Nu_error: message = message + "Error valor ingresado: Relación de Poisson debe estar en el rango (0 - 0.5) \n" except: message = message +"Error valor ingresado: Relación de Poisson no válida \n"

try: e_ = float(self.lineEdit_e.text()) except: message = message + "Error valor ingresado: Módulo de Young (E) no válido \n" try: kh = float(self.lineEdit_kh.text()) except: message = message + "Error valor ingresado: Coeficiente de permeabilidad horizontal no válido \n" try: kv = float(self.lineEdit_kv.text()) except: message = message +"Error valor ingresado: Coefciente de permeabilidad vertical no válido \n" if message != '': QtWidgets.QMessageBox.warning(self, "Error valor ingresado", message) return self.accept()

if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = Input_Dlg() myapp.show() # sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys exit(app.exec_())

dialog_input_interface.py# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'dialogo_inputs16May.ui'## Created by: PyQt5 UI code generator 5.11.3## WARNING! All changes made in this file will be lost!

Page 218: Desarrollo de un laboratorio virtual de geotecnia enfocado

198 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog_Inputs(object): def setupUi(self, Dialog_Inputs): Dialog_Inputs.setObjectName("Dialog_Inputs") Dialog_Inputs.resize(240, 425) self.gridLayout = QtWidgets.QGridLayout(Dialog_Inputs) self.gridLayout.setObjectName("gridLayout") self.label_Carga = QtWidgets.QLabel(Dialog_Inputs) self.label_Carga.setObjectName("label_Carga") self.gridLayout.addWidget(self.label_Carga, 0, 0, 1, 2) self.label_P = QtWidgets.QLabel(Dialog_Inputs) self.label_P.setObjectName("label_P") self.gridLayout.addWidget(self.label_P, 1, 0, 1, 1) spacerItem = QtWidgets.QSpacerItem(23, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem, 1, 2, 1, 2) self.lineEdit_P = QtWidgets.QLineEdit(Dialog_Inputs) self.lineEdit_P.setLayoutDirection(QtCore.Qt.LeftToRight) self.lineEdit_P.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_P.setObjectName("lineEdit_P") self.gridLayout.addWidget(self.lineEdit_P, 1, 5, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem1, 1, 6, 1, 1) self.label_geometria = QtWidgets.QLabel(Dialog_Inputs) self.label_geometria.setObjectName("label_geometria") self.gridLayout.addWidget(self.label_geometria, 2, 0, 1, 3) self.label_altura = QtWidgets.QLabel(Dialog_Inputs) self.label_altura.setObjectName("label_altura") self.gridLayout.addWidget(self.label_altura, 3, 0, 1, 2) spacerItem2 = QtWidgets.QSpacerItem(48, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem2, 3, 3, 1, 1) self.lineEdit_altura = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_altura.sizePolicy().hasHeightForWidth()) self.lineEdit_altura.setSizePolicy(sizePolicy) self.lineEdit_altura.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_altura.setObjectName("lineEdit_altura") self.gridLayout.addWidget(self.lineEdit_altura, 3, 5, 1, 1)

Page 219: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 199

spacerItem3 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem3, 3, 6, 1, 1) self.label_radio = QtWidgets.QLabel(Dialog_Inputs) self.label_radio.setObjectName("label_radio") self.gridLayout.addWidget(self.label_radio, 4, 0, 1, 2) spacerItem4 = QtWidgets.QSpacerItem(48, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem4, 4, 3, 1, 1) self.lineEdit_radio = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_radio.sizePolicy().hasHeightForWidth()) self.lineEdit_radio.setSizePolicy(sizePolicy) self.lineEdit_radio.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_radio.setObjectName("lineEdit_radio") self.gridLayout.addWidget(self.lineEdit_radio, 4, 5, 1, 1) spacerItem5 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem5, 4, 6, 1, 1) self.label_propiedades = QtWidgets.QLabel(Dialog_Inputs) self.label_propiedades.setObjectName("label_propiedades") self.gridLayout.addWidget(self.label_propiedades, 5, 0, 1, 4) self.label_tot_unit_weight = QtWidgets.QLabel(Dialog_Inputs) self.label_tot_unit_weight.setObjectName("label_tot_unit_weight") self.gridLayout.addWidget(self.label_tot_unit_weight, 6, 0, 1, 4) spacerItem6 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem6, 6, 4, 1, 1) self.lineEdit_tot_unit_weight = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_tot_unit_weight.sizePolicy().hasHeightForWidth()) self.lineEdit_tot_unit_weight.setSizePolicy(sizePolicy) self.lineEdit_tot_unit_weight.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_tot_unit_weight.setObjectName("lineEdit_tot_unit_weight") self.gridLayout.addWidget(self.lineEdit_tot_unit_weight, 6, 5, 1, 1) spacerItem7 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem7, 6, 6, 1, 1)

Page 220: Desarrollo de un laboratorio virtual de geotecnia enfocado

200 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.label_fluid_unit_weight = QtWidgets.QLabel(Dialog_Inputs) self.label_fluid_unit_weight.setObjectName("label_fluid_unit_weight") self.gridLayout.addWidget(self.label_fluid_unit_weight, 7, 0, 1, 4) spacerItem8 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem8, 7, 4, 1, 1) self.lineEdit_fluid_unit_weight = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_fluid_unit_weight.sizePolicy().hasHeightForWidth()) self.lineEdit_fluid_unit_weight.setSizePolicy(sizePolicy) self.lineEdit_fluid_unit_weight.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_fluid_unit_weight.setObjectName("lineEdit_fluid_unit_weight")

self.gridLayout.addWidget(self.lineEdit_fluid_unit_weight, 7, 5, 1, 1) spacerItem9 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem9, 7, 6, 1, 1) self.label_mecanicos = QtWidgets.QLabel(Dialog_Inputs) self.label_mecanicos.setObjectName("label_mecanicos") self.gridLayout.addWidget(self.label_mecanicos, 8, 0, 1, 6) self.label_nu = QtWidgets.QLabel(Dialog_Inputs) self.label_nu.setObjectName("label_nu") self.gridLayout.addWidget(self.label_nu, 9, 0, 1, 1) spacerItem10 = QtWidgets.QSpacerItem(48, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem10, 9, 1, 1, 3) self.lineEdit_nu = QtWidgets.QLineEdit(Dialog_Inputs) self.lineEdit_nu.setEnabled(True) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_nu.sizePolicy().hasHeightForWidth()) self.lineEdit_nu.setSizePolicy(sizePolicy) self.lineEdit_nu.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_nu.setObjectName("lineEdit_nu") self.gridLayout.addWidget(self.lineEdit_nu, 9, 5, 1, 1) spacerItem11 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem11, 9, 6, 1, 1) self.label_E_MPa = QtWidgets.QLabel(Dialog_Inputs) self.label_E_MPa.setObjectName("label_E_MPa")

Page 221: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 201

self.gridLayout.addWidget(self.label_E_MPa, 10, 0, 1, 2) spacerItem12 = QtWidgets.QSpacerItem(14, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem12, 10, 4, 1, 1) self.lineEdit_e = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_e.sizePolicy().hasHeightForWidth()) self.lineEdit_e.setSizePolicy(sizePolicy) self.lineEdit_e.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_e.setObjectName("lineEdit_e") self.gridLayout.addWidget(self.lineEdit_e, 10, 5, 1, 1) spacerItem13 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem13, 10, 6, 1, 1) self.label_hidraulicos = QtWidgets.QLabel(Dialog_Inputs) self.label_hidraulicos.setObjectName("label_hidraulicos") self.gridLayout.addWidget(self.label_hidraulicos, 11, 0, 1, 6) self.label_kh = QtWidgets.QLabel(Dialog_Inputs) self.label_kh.setObjectName("label_kh") self.gridLayout.addWidget(self.label_kh, 12, 0, 1, 2) spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem14, 12, 4, 1, 1) self.lineEdit_kh = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_kh.sizePolicy().hasHeightForWidth()) self.lineEdit_kh.setSizePolicy(sizePolicy) self.lineEdit_kh.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_kh.setObjectName("lineEdit_kh") self.gridLayout.addWidget(self.lineEdit_kh, 12, 5, 1, 1) spacerItem15 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem15, 12, 6, 1, 1) self.label_kv = QtWidgets.QLabel(Dialog_Inputs) self.label_kv.setObjectName("label_kv") self.gridLayout.addWidget(self.label_kv, 13, 0, 1, 2) spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem16, 13, 4, 1, 1) self.lineEdit_kv = QtWidgets.QLineEdit(Dialog_Inputs)

Page 222: Desarrollo de un laboratorio virtual de geotecnia enfocado

202 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_kv.sizePolicy().hasHeightForWidth()) self.lineEdit_kv.setSizePolicy(sizePolicy) self.lineEdit_kv.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_kv.setObjectName("lineEdit_kv") self.gridLayout.addWidget(self.lineEdit_kv, 13, 5, 1, 1) spacerItem17 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem17, 13, 6, 1, 1) self.formLayout = QtWidgets.QFormLayout() self.formLayout.setObjectName("formLayout") spacerItem18 = QtWidgets.QSpacerItem(88, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.formLayout.setItem(0, QtWidgets.QFormLayout.LabelRole, spacerItem18) self.pushButton_Advanced = QtWidgets.QPushButton(Dialog_Inputs) self.pushButton_Advanced.setObjectName("pushButton_Advanced") self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.pushButton_Advanced) self.gridLayout.addLayout(self.formLayout, 14, 0, 1, 6) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem19 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem19) self.pushButton_Ok = QtWidgets.QPushButton(Dialog_Inputs) self.pushButton_Ok.setObjectName("pushButton_Ok") self.horizontalLayout.addWidget(self.pushButton_Ok) self.pushButton_Cancel = QtWidgets.QPushButton(Dialog_Inputs) self.pushButton_Cancel.setObjectName("pushButton_Cancel") self.horizontalLayout.addWidget(self.pushButton_Cancel) self.gridLayout.addLayout(self.horizontalLayout, 15, 0, 1, 6) self.label_altura.setBuddy(self.lineEdit_altura) self.label_radio.setBuddy(self.lineEdit_radio) self.label_tot_unit_weight.setBuddy(self.lineEdit_tot_unit_weight) self.label_fluid_unit_weight.setBuddy(self.lineEdit_fluid_unit_weight) self.label_nu.setBuddy(self.lineEdit_nu) self.label_E_MPa.setBuddy(self.lineEdit_e) self.label_kh.setBuddy(self.lineEdit_kh) self.label_kv.setBuddy(self.lineEdit_kv)

self.retranslateUi(Dialog_Inputs) QtCore.QMetaObject.connectSlotsByName(Dialog_Inputs) Dialog_Inputs.setTabOrder(self.lineEdit_altura, self.lineEdit_radio) Dialog_Inputs.setTabOrder(self.lineEdit_radio, self.lineEdit_tot_unit_weight)

Page 223: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 203

Dialog_Inputs.setTabOrder(self.lineEdit_tot_unit_weight, self.lineEdit_fluid_unit_weight) Dialog_Inputs.setTabOrder(self.lineEdit_fluid_unit_weight, self.lineEdit_nu) Dialog_Inputs.setTabOrder(self.lineEdit_nu, self.lineEdit_e) Dialog_Inputs.setTabOrder(self.lineEdit_e, self.lineEdit_kh) Dialog_Inputs.setTabOrder(self.lineEdit_kh, self.lineEdit_kv) Dialog_Inputs.setTabOrder(self.lineEdit_kv, self.pushButton_Ok) Dialog_Inputs.setTabOrder(self.pushButton_Ok, self.pushButton_Advanced) Dialog_Inputs.setTabOrder(self.pushButton_Advanced, self.pushButton_Cancel)

def retranslateUi(self, Dialog_Inputs): _translate = QtCore.QCoreApplication.translate Dialog_Inputs.setWindowTitle(_translate("Dialog_Inputs", "Dialog")) self.label_Carga.setText(_translate("Dialog_Inputs", "Carga")) self.label_P.setText(_translate("Dialog_Inputs", "P (kPa)")) self.lineEdit_P.setText(_translate("Dialog_Inputs", "12.6")) self.label_geometria.setText(_translate("Dialog_Inputs", "Geometría")) self.label_altura.setText(_translate("Dialog_Inputs", "&h (m)")) self.lineEdit_altura.setText(_translate("Dialog_Inputs", "0.05")) self.label_radio.setText(_translate("Dialog_Inputs", "&r (m)")) self.lineEdit_radio.setText(_translate("Dialog_Inputs", "0.03")) self.label_propiedades.setText(_translate("Dialog_Inputs", "Propiedades")) self.label_tot_unit_weight.setText(_translate("Dialog_Inputs", "γ&t (kN/m^3)")) self.lineEdit_tot_unit_weight.setText(_translate("Dialog_Inputs", "16.0")) self.label_fluid_unit_weight.setText(_translate("Dialog_Inputs", "γ&w (kN/m^3)")) self.lineEdit_fluid_unit_weight.setText(_translate("Dialog_Inputs", "9.81")) self.label_mecanicos.setText(_translate("Dialog_Inputs", "Parámetros mecánicos")) self.label_nu.setText(_translate("Dialog_Inputs", "&nu")) self.lineEdit_nu.setText(_translate("Dialog_Inputs", "0.3")) self.label_E_MPa.setText(_translate("Dialog_Inputs", "&E(kPa)")) self.lineEdit_e.setText(_translate("Dialog_Inputs", "6400")) self.label_hidraulicos.setText(_translate("Dialog_Inputs", "Parámetros hidráulicos")) self.label_kh.setText(_translate("Dialog_Inputs", "k&h (m/s)")) self.lineEdit_kh.setText(_translate("Dialog_Inputs", "0.0025")) self.label_kv.setText(_translate("Dialog_Inputs", "k&v (m/s)")) self.lineEdit_kv.setText(_translate("Dialog_Inputs", "0.0050")) self.pushButton_Advanced.setText(_translate("Dialog_Inputs", "&Avanzado")) self.pushButton_Ok.setText(_translate("Dialog_Inputs", "&Ok")) self.pushButton_Cancel.setText(_translate("Dialog_Inputs", "&Cancelar"))

dialog_input_trx_class.py# -*- coding: utf-8 -*-"""Created on Tue Aug 6 14:18:17 2019

@author: JOscar"""

import sysimport re

Page 224: Desarrollo de un laboratorio virtual de geotecnia enfocado

204 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

from PyQt5 import QtCore, QtGui, QtWidgetsimport numpy as npimport time

from dialog_input_trx_interface import Ui_Dialog_Inputsfrom dialog_advanced_input_class import Input_Adv_Dlg

class Input_Dlg(QtWidgets.QDialog, Ui_Dialog_Inputs): def __init__(self, parent = None): super(Input_Dlg, self).__init__(parent) self.setupUi(self) self.adv_Dlg = Input_Adv_Dlg(self) self.criterium = None self.pushButton_Ok.clicked.connect(self.corroborate) self.pushButton_Cancel.clicked.connect(self.reject) self.pushButton_Advanced.clicked.connect(self.set_Adv) self.pushButtonAnadir.clicked.connect(self.insertarFila) self.pushButtonEliminar.clicked.connect(self.eliminarFila) self.pushButtonBorrarTodo.clicked.connect(self.limpiarTabla) # Agregando la tabla para el manejo de H self.tableWidgetH.setColumnCount(2) self.tableWidgetH.setRowCount(1) self.tableWidgetH.set orizontal eaderLabels(("σₐ (kPa)", " ' (kPa)")) self.tableWidgetH.setItem(0, 0, QtWidgets.QTableWidgetItem("1")) self.tableWidgetH.setItem(0, 1, QtWidgets.QTableWidgetItem("1")) self.listH = [] self.listSigma = [] a = float(self.tableWidgetH.item(0, 0).text()) b = float(self.tableWidgetH.item(0, 1).text()) # self.tableWidgetH.removeRow(0) def insertarFila(self): self.tableWidgetH.insertRow(self.tableWidgetH.rowCount()) def eliminarFila(self): # Para eliminar fila necesito que se elimine la fila seleccionada if self.tableWidgetH.rowCount() > 1: self.tableWidgetH.removeRow(self.tableWidgetH.currentRow()) def limpiarTabla(self): self.tableWidgetH.clear() self.tableWidgetH.setHorizontalHeaderLabels(("Sigma", "H")) def isanumber(self, a): try:

Page 225: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 205

float(repr(a)) bool_a = True except: bool_a = False print(bool_a) return bool_a def set_Adv(self): if self.adv_Dlg.exec_(): self.criterium = float(self.adv_Dlg.lineEdit_criterium.text()) def corroborate(self): # Raise error class Nu_error(Exception): pass message = '' try: s1 = float(self.lineEdit_S1.text()) except: message = message + "Error valor ingresado: Carga (σ1) no válida \n" try: s3 = float(self.lineEdit_S1.text()) except: message = message + "Error valor ingresado: Carga (σ3) no válida \n"

try: h = float(self.lineEdit_altura.text()) except: message = message + "Error valor ingresado: Altura (h) no válida \n"

try: r = float(self.lineEdit_radio.text()) except: message = message + "Error valor ingresado: Radio (r) no válido \n" try: gt = float(self.lineEdit_tot_unit_weight.text()) except: message = message + "Error valor ingresado: Peso unitario total no válido \n" try: nu = float(self.lineEdit_nu.text()) try: if nu > 0.5: raise Nu_error elif nu < 0: raise Nu_error except Nu_error: message = message + "Error valor ingresado: Relación de Poisson debe estar en el rango (0 - 0.5) \n"

Page 226: Desarrollo de un laboratorio virtual de geotecnia enfocado

206 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

except: message = message +"Error valor ingresado: Relación de Poisson no válida \n"

try: e_ = float(self.lineEdit_e.text()) except: message = message + "Error valor ingresado: Módulo de Young (E) no válido \n" try: c = float(self.lineEdit_c.text())

except: message = message + "Error valor ingresado: cohesión no válida \n" try: phi = float(self.lineEdit_phi.text()) except: message = message +"Error valor ingresado: Ángulo de fricción no válido \n" arregloH = np.arange(0, self.tableWidgetH.rowCount(), 1) for a in arregloH: try: if not self.tableWidgetH.item(a, 1)==None and not self.tableWidgetH.item(a,0)==None: self.listH.append(float(self.tableWidgetH.item(a, 1).text())) self.listSigma.append(float(self.tableWidgetH.item(a, 0).text())) except: message = message +"Error valor ingresado: Valores tabla \n" if message != '': QtWidgets.QMessageBox.warning(self, "Error valor ingresado", message) return self.accept()

if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myapp = Input_Dlg() myapp.show() # sys.exit(app.exec_()) no funciona porque Ipython tiene problemas con sys exit(app.exec_())

dialog_input_trx_interface.py# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'dialogo_inputs_trx.ui'## Created by: PyQt5 UI code generator 5.11.3## WARNING! All changes made in this file will be lost!

Page 227: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 207

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog_Inputs(object): def setupUi(self, Dialog_Inputs): Dialog_Inputs.setObjectName("Dialog_Inputs") Dialog_Inputs.resize(607, 458) self.gridLayout = QtWidgets.QGridLayout(Dialog_Inputs) self.gridLayout.setObjectName("gridLayout") self.label_esfuerzo = QtWidgets.QLabel(Dialog_Inputs) self.label_esfuerzo.setObjectName("label_esfuerzo") self.gridLayout.addWidget(self.label_esfuerzo, 0, 0, 1, 1) self.tableWidgetH = QtWidgets.QTableWidget(Dialog_Inputs) self.tableWidgetH.setObjectName("tableWidgetH") self.tableWidgetH.setColumnCount(0) self.tableWidgetH.setRowCount(0) self.gridLayout.addWidget(self.tableWidgetH, 0, 4, 16, 1) self.label_S1 = QtWidgets.QLabel(Dialog_Inputs) self.label_S1.setObjectName("label_S1") self.gridLayout.addWidget(self.label_S1, 1, 0, 1, 1) spacerItem = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem, 1, 1, 1, 1) self.lineEdit_S1 = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_S1.sizePolicy().hasHeightForWidth()) self.lineEdit_S1.setSizePolicy(sizePolicy) self.lineEdit_S1.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_S1.setObjectName("lineEdit_S1") self.gridLayout.addWidget(self.lineEdit_S1, 1, 2, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(0, 14, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem1, 1, 3, 1, 1) self.label_S3 = QtWidgets.QLabel(Dialog_Inputs) self.label_S3.setObjectName("label_S3") self.gridLayout.addWidget(self.label_S3, 2, 0, 1, 1) spacerItem2 = QtWidgets.QSpacerItem(39, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem2, 2, 1, 1, 1) self.lineEdit_S3 = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_S3.sizePolicy().hasHeightForWidth()) self.lineEdit_S3.setSizePolicy(sizePolicy)

Page 228: Desarrollo de un laboratorio virtual de geotecnia enfocado

208 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.lineEdit_S3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_S3.setObjectName("lineEdit_S3") self.gridLayout.addWidget(self.lineEdit_S3, 2, 2, 1, 1) spacerItem3 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem3, 2, 3, 1, 1) self.formLayout_2 = QtWidgets.QFormLayout() self.formLayout_2.setObjectName("formLayout_2") self.pushButtonAnadir = QtWidgets.QPushButton(Dialog_Inputs) self.pushButtonAnadir.setObjectName("pushButtonAnadir") self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.pushButtonAnadir) self.pushButtonEliminar = QtWidgets.QPushButton(Dialog_Inputs) self.pushButtonEliminar.setObjectName("pushButtonEliminar") self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.pushButtonEliminar) self.pushButtonBorrarTodo = QtWidgets.QPushButton(Dialog_Inputs) self.pushButtonBorrarTodo.setObjectName("pushButtonBorrarTodo") self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.pushButtonBorrarTodo) self.labelOpcionesDeTabla = QtWidgets.QLabel(Dialog_Inputs) self.labelOpcionesDeTabla.setObjectName("labelOpcionesDeTabla") self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.labelOpcionesDeTabla) spacerItem4 = QtWidgets.QSpacerItem(72, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.formLayout_2.setItem(3, QtWidgets.QFormLayout.LabelRole, spacerItem4) self.gridLayout.addLayout(self.formLayout_2, 2, 5, 7, 1) self.label_geometria = QtWidgets.QLabel(Dialog_Inputs) self.label_geometria.setObjectName("label_geometria") self.gridLayout.addWidget(self.label_geometria, 3, 0, 1, 1) self.label_altura = QtWidgets.QLabel(Dialog_Inputs) self.label_altura.setObjectName("label_altura") self.gridLayout.addWidget(self.label_altura, 4, 0, 1, 1) spacerItem5 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem5, 4, 1, 1, 1) self.lineEdit_altura = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_altura.sizePolicy().hasHeightForWidth()) self.lineEdit_altura.setSizePolicy(sizePolicy) self.lineEdit_altura.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_altura.setObjectName("lineEdit_altura")

Page 229: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 209

self.gridLayout.addWidget(self.lineEdit_altura, 4, 2, 1, 1) spacerItem6 = QtWidgets.QSpacerItem(0, 14, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem6, 4, 3, 1, 1) self.label_radio = QtWidgets.QLabel(Dialog_Inputs) self.label_radio.setObjectName("label_radio") self.gridLayout.addWidget(self.label_radio, 5, 0, 1, 1) spacerItem7 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem7, 5, 1, 1, 1) self.lineEdit_radio = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_radio.sizePolicy().hasHeightForWidth()) self.lineEdit_radio.setSizePolicy(sizePolicy) self.lineEdit_radio.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_radio.setObjectName("lineEdit_radio") self.gridLayout.addWidget(self.lineEdit_radio, 5, 2, 1, 1) spacerItem8 = QtWidgets.QSpacerItem(0, 14, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem8, 5, 3, 1, 1) self.label_propiedades = QtWidgets.QLabel(Dialog_Inputs) self.label_propiedades.setObjectName("label_propiedades") self.gridLayout.addWidget(self.label_propiedades, 6, 0, 1, 1) self.label_tot_unit_weight = QtWidgets.QLabel(Dialog_Inputs) self.label_tot_unit_weight.setObjectName("label_tot_unit_weight") self.gridLayout.addWidget(self.label_tot_unit_weight, 7, 0, 1, 1) spacerItem9 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem9, 7, 1, 1, 1) self.lineEdit_tot_unit_weight = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0)

sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_tot_unit_weight.sizePolicy().hasHeightForWidth()) self.lineEdit_tot_unit_weight.setSizePolicy(sizePolicy) self.lineEdit_tot_unit_weight.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_tot_unit_weight.setObjectName("lineEdit_tot_unit_weight") self.gridLayout.addWidget(self.lineEdit_tot_unit_weight, 7, 2, 1, 1) spacerItem10 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)

Page 230: Desarrollo de un laboratorio virtual de geotecnia enfocado

210 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.gridLayout.addItem(spacerItem10, 7, 3, 1, 1) self.label_mecanicos = QtWidgets.QLabel(Dialog_Inputs) self.label_mecanicos.setObjectName("label_mecanicos") self.gridLayout.addWidget(self.label_mecanicos, 8, 0, 1, 2) self.label_nu = QtWidgets.QLabel(Dialog_Inputs) self.label_nu.setObjectName("label_nu") self.gridLayout.addWidget(self.label_nu, 9, 0, 1, 1) spacerItem11 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem11, 9, 1, 1, 1) self.lineEdit_nu = QtWidgets.QLineEdit(Dialog_Inputs) self.lineEdit_nu.setEnabled(True) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_nu.sizePolicy().hasHeightForWidth()) self.lineEdit_nu.setSizePolicy(sizePolicy) self.lineEdit_nu.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_nu.setObjectName("lineEdit_nu") self.gridLayout.addWidget(self.lineEdit_nu, 9, 2, 1, 1) spacerItem12 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem12, 9, 3, 1, 1) self.label_E_MPa = QtWidgets.QLabel(Dialog_Inputs) self.label_E_MPa.setObjectName("label_E_MPa") self.gridLayout.addWidget(self.label_E_MPa, 10, 0, 1, 1) spacerItem13 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem13, 10, 1, 1, 1) self.lineEdit_e = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_e.sizePolicy().hasHeightForWidth()) self.lineEdit_e.setSizePolicy(sizePolicy) self.lineEdit_e.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_e.setObjectName("lineEdit_e") self.gridLayout.addWidget(self.lineEdit_e, 10, 2, 1, 1) spacerItem14 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem14, 10, 3, 1, 1) self.label_hidraulicos = QtWidgets.QLabel(Dialog_Inputs) self.label_hidraulicos.setObjectName("label_hidraulicos") self.gridLayout.addWidget(self.label_hidraulicos, 11, 0, 1, 1)

Page 231: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 211

self.label_c = QtWidgets.QLabel(Dialog_Inputs) self.label_c.setObjectName("label_c") self.gridLayout.addWidget(self.label_c, 12, 0, 1, 1) spacerItem15 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem15, 12, 1, 1, 1) self.lineEdit_c = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_c.sizePolicy().hasHeightForWidth()) self.lineEdit_c.setSizePolicy(sizePolicy) self.lineEdit_c.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_c.setObjectName("lineEdit_c") self.gridLayout.addWidget(self.lineEdit_c, 12, 2, 1, 1) spacerItem16 = QtWidgets.QSpacerItem(0, 14, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem16, 12, 3, 1, 1) self.label_phi = QtWidgets.QLabel(Dialog_Inputs) self.label_phi.setObjectName("label_phi") self.gridLayout.addWidget(self.label_phi, 13, 0, 1, 1) spacerItem17 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem17, 13, 1, 1, 1) self.lineEdit_phi = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_phi.sizePolicy().hasHeightForWidth()) self.lineEdit_phi.setSizePolicy(sizePolicy) self.lineEdit_phi.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_phi.setObjectName("lineEdit_phi") self.gridLayout.addWidget(self.lineEdit_phi, 13, 2, 1, 1) spacerItem18 = QtWidgets.QSpacerItem(0, 14, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem18, 13, 3, 1, 1) self.label_analisis = QtWidgets.QLabel(Dialog_Inputs) self.label_analisis.setObjectName("label_analisis") self.gridLayout.addWidget(self.label_analisis, 14, 0, 1, 1) self.label_n = QtWidgets.QLabel(Dialog_Inputs) self.label_n.setObjectName("label_n") self.gridLayout.addWidget(self.label_n, 15, 0, 1, 1) spacerItem19 = QtWidgets.QSpacerItem(39, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)

Page 232: Desarrollo de un laboratorio virtual de geotecnia enfocado

212 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.gridLayout.addItem(spacerItem19, 15, 1, 1, 1) self.lineEdit_n = QtWidgets.QLineEdit(Dialog_Inputs) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_n.sizePolicy().hasHeightForWidth()) self.lineEdit_n.setSizePolicy(sizePolicy) self.lineEdit_n.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lineEdit_n.setObjectName("lineEdit_n") self.gridLayout.addWidget(self.lineEdit_n, 15, 2, 1, 1) spacerItem20 = QtWidgets.QSpacerItem(0, 14, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem20, 15, 3, 1, 1) self.formLayout = QtWidgets.QFormLayout() self.formLayout.setObjectName("formLayout") spacerItem21 = QtWidgets.QSpacerItem(88, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.formLayout.setItem(0, QtWidgets.QFormLayout.LabelRole, spacerItem21) self.pushButton_Advanced = QtWidgets.QPushButton(Dialog_Inputs) self.pushButton_Advanced.setObjectName("pushButton_Advanced") self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.pushButton_Advanced) self.gridLayout.addLayout(self.formLayout, 16, 0, 1, 3) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem22 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem22) self.pushButton_Ok = QtWidgets.QPushButton(Dialog_Inputs) self.pushButton_Ok.setObjectName("pushButton_Ok") self.horizontalLayout.addWidget(self.pushButton_Ok) self.pushButton_Cancel = QtWidgets.QPushButton(Dialog_Inputs) self.pushButton_Cancel.setObjectName("pushButton_Cancel") self.horizontalLayout.addWidget(self.pushButton_Cancel) self.gridLayout.addLayout(self.horizontalLayout, 17, 0, 1, 3) self.label_analisis_explicacion = QtWidgets.QLabel(Dialog_Inputs) self.label_analisis_explicacion.setObjectName("label_analisis_explicacion") self.gridLayout.addWidget(self.label_analisis_explicacion, 14, 2, 1, 1) self.label_altura.setBuddy(self.lineEdit_altura) self.label_radio.setBuddy(self.lineEdit_radio) self.label_tot_unit_weight.setBuddy(self.lineEdit_tot_unit_weight) self.label_nu.setBuddy(self.lineEdit_nu) self.label_E_MPa.setBuddy(self.lineEdit_e) self.label_c.setBuddy(self.lineEdit_c) self.label_phi.setBuddy(self.lineEdit_phi) self.label_n.setBuddy(self.lineEdit_phi)

Page 233: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 213

self.retranslateUi(Dialog_Inputs) QtCore.QMetaObject.connectSlotsByName(Dialog_Inputs) Dialog_Inputs.setTabOrder(self.lineEdit_S1, self.lineEdit_altura) Dialog_Inputs.setTabOrder(self.lineEdit_altura, self.lineEdit_radio) Dialog_Inputs.setTabOrder(self.lineEdit_radio, self.lineEdit_tot_unit_weight) Dialog_Inputs.setTabOrder(self.lineEdit_tot_unit_weight, self.lineEdit_nu) Dialog_Inputs.setTabOrder(self.lineEdit_nu, self.lineEdit_e) Dialog_Inputs.setTabOrder(self.lineEdit_e, self.lineEdit_c) Dialog_Inputs.setTabOrder(self.lineEdit_c, self.lineEdit_phi) Dialog_Inputs.setTabOrder(self.lineEdit_phi, self.tableWidgetH) Dialog_Inputs.setTabOrder(self.tableWidgetH, self.pushButton_Advanced) Dialog_Inputs.setTabOrder(self.pushButton_Advanced, self.pushButton_Ok) Dialog_Inputs.setTabOrder(self.pushButton_Ok, self.pushButton_Cancel)

def retranslateUi(self, Dialog_Inputs): _translate = QtCore.QCoreApplication.translate Dialog_Inputs.setWindowTitle(_translate("Dialog_Inputs", "Dialog")) self.label_esfuerzo.setText(_translate("Dialog_Inputs", "Esfuerzo")) self.label_S1.setText(_translate("Dialog_Inputs", "<html><head/><body><p>σ\'<span style=\" vertical-align:sub;\">1</span> (kPa)</p></body></html>")) self.lineEdit_S1.setText(_translate("Dialog_Inputs", "15")) self.label_S3.setText(_translate("Dialog_Inputs", "<html><head/><body><p>σ\'<span style=\" vertical-align:sub;\">3</span> (kPa)</p></body></html>")) self.lineEdit_S3.setText(_translate("Dialog_Inputs", "5")) self.pushButtonAnadir.setText(_translate("Dialog_Inputs", "Agregar")) self.pushButtonEliminar.setText(_translate("Dialog_Inputs", "Eliminar")) self.pushButtonBorrarTodo.setText(_translate("Dialog_Inputs", "Borrar todo")) self.labelOpcionesDeTabla.setText(_translate("Dialog_Inputs", "<html><head/><body><p align=\"center\">Opciones</p><p align=\"center\">de tabla</p></body></html>")) self.label_geometria.setText(_translate("Dialog_Inputs", "Geometría")) self.label_altura.setText(_translate("Dialog_Inputs", "&h (m)")) self.lineEdit_altura.setText(_translate("Dialog_Inputs", "0.05")) self.label_radio.setText(_translate("Dialog_Inputs", "&r (m)")) self.lineEdit_radio.setText(_translate("Dialog_Inputs", "0.03")) self.label_propiedades.setText(_translate("Dialog_Inputs", "Propiedades")) self.label_tot_unit_weight.setText(_translate("Dialog_Inputs", "γ&t (kN/m^3)")) self.lineEdit_tot_unit_weight.setText(_translate("Dialog_Inputs", "16.0")) self.label_mecanicos.setText(_translate("Dialog_Inputs", "Parámetros mecánicos")) self.label_nu.setText(_translate("Dialog_Inputs", "&nu")) self.lineEdit_nu.setText(_translate("Dialog_Inputs", "0.3")) self.label_E_MPa.setText(_translate("Dialog_Inputs", "&E\'(kPa)")) self.lineEdit_e.setText(_translate("Dialog_Inputs", "6400")) self.label_hidraulicos.setText(_translate("Dialog_Inputs", "Resistencia")) self.label_c.setText(_translate("Dialog_Inputs", "&c\' (kPa)")) self.lineEdit_c.setText(_translate("Dialog_Inputs", "10")) self.label_phi.setText(_translate("Dialog_Inputs", "Φ\' (°)")) self.lineEdit_phi.setText(_translate("Dialog_Inputs", "5"))

Page 234: Desarrollo de un laboratorio virtual de geotecnia enfocado

214 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.label_analisis.setText(_translate("Dialog_Inputs", "Análisis:")) self.label_n.setText(_translate("Dialog_Inputs", "N (adim)")) self.lineEdit_n.setText(_translate("Dialog_Inputs", "30")) self.pushButton_Advanced.setText(_translate("Dialog_Inputs", "&Avanzado")) self.pushButton_Ok.setText(_translate("Dialog_Inputs", "&Ok")) self.pushButton_Cancel.setText(_translate("Dialog_Inputs", "&Cancelar")) self.label_analisis_explicacion.setText(_translate("Dialog_Inputs", "Número de pasos de carga"))

element_force_vector.py"""This module stores element force classes.""" #JOscarfrom __future__ import divisionfrom math import sqrt as raiz_cuadfrom math import pi, factorialimport numpy as npimport time

import integration_pointsimport jacobianoimport inv_coordimport ccw_formatimport element_shape_matrices

np.set_printoptions(precision=3)

class Element_force_vector(object): """Makes an element force vector.

Args: write here the arguments Attributes: write here the used attributes in this module """ def __init__(self, element, total_unit_weight, problem_type,): self.id = element.id self.element = element self.problem_type = problem_type self.element_type = element.ccxtype if element.ccxtype in ['CPS3', 'CAX3', 'CPE3']: self.integration_points = integration_points.Integration_points().integration_points self.body_force_vector = np.zeros((6, 1)) if element.ccxtype in ['CPS3', 'CPE3']:

Page 235: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 215

self.t = 1 elif element.ccxtype in ['CAX3']: self.t = 2*pi*element.calc_center().y if self.problem_type == 'field_problem': 1 # pendiente if self.problem_type == 'consolidation':# self.set_body_force_vector(element, total_unit_weight) self.vector_n = np.zeros((3, 1)) if element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: self.integration_points = integration_points.Integration_points().integration_points self.body_force_vector = np.zeros((12, 1)) if element.ccxtype in ['CPS6', 'CPE6']: self.t = 1 elif element.ccxtype in ['CAX6']: self.t = 2*pi*element.calc_center().y # Cambiada por la distancia horizontal de cada punto de integración def __hash__(self): """Returns the item's id as its hash.""" return self.id def invert_coordinates(self, element): inv_coord.Inv_coord(element) def counterclockwise_format(self, element): """Organizes the nodes of the element in a counterclockwise format 'i, j and k'. A linear triangular element is used""" formato = ccw_format.Ccw(element) if element.ccxtype in ['CPS3', 'CAX3', 'CPE3']: self.nodei = formato.nodei self.nodej = formato.nodej self.nodek = formato.nodek return self.nodei, self.nodej, self.nodek

elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: self.nodei = formato.nodei self.nodej = formato.nodej self.nodek = formato.nodek self.nodel = formato.nodel self.nodem = formato.nodem self.noden = formato.noden return self.nodei, self.nodej, self.nodek, self.nodel, self.nodem, self.noden

Page 236: Desarrollo de un laboratorio virtual de geotecnia enfocado

216 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

def set_body_force_vector(self, element, total_unit_weight, fluid_unit_weight = 9.81, unbalanced_force = None): # water 9.81 kN/m^3 """"Body force vector in the global coordinate system""" # considering the gravitational force in global coordinate system self.invert_coordinates(element) if element.ccxtype in ['CPS3', 'CAX3', 'CPE3'] and self.problem_type == 'consolidation': jacobian = jacobiano.Jacobiano(element).matrix_J # -1 according to the positive direction of the axis rt = -1*np.array([[0], [total_unit_weight]]) # considering buoyancy force (fluid unit weight = 9.81 kN/m^3) rw = +1*np.array([[0], [fluid_unit_weight]]) ni,nj,nk = self.counterclockwise_format(element) for point in self.integration_points.values(): n1 = point['l1'] n2 = point['l2'] n3 = 1 - n1 - n2 shape_vector = np.array([[n1, 0, n2, 0, n3, 0], [0, n1, 0, n2, 0, n3]]) xc = 1*(n1*ni.x + n2*nj.x + n3*nk.x) xi = rt + rw detJ = np.linalg.det(jacobian) if element.ccxtype in ['CAX3']: t = 2*pi*xc else: t = 1 self.body_force_vector = self.body_force_vector + point['w']*t*abs(detJ)*np.matmul( np.transpose(shape_vector), xi) self.invert_coordinates(element) return self.body_force_vector elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6'] and unbalanced_force != None: self.body_force_vector = unbalanced_force['element'][element.id]['unbalanced'] self.invert_coordinates(element) return self.body_force_vector elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6'] and self.problem_type == 'large_displacements': ni,nj,nk,nl,nm,nn = self.counterclockwise_format(element) for point in self.integration_points.values(): jacobian = jacobiano.Jacobiano(element, point['l1'], point['l2']).matrix_J rt = -1*np.array([[0],

Page 237: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 217

[total_unit_weight]]) n1 = point['l1']*(2*point['l1'] - 1) n2 = 4*point['l1']*point['l2'] n3 = point['l2']*(2*point['l2'] - 1) n4 = 4*point['l2']*(1 - point['l1'] - point['l2']) n5 = 1 - 3*(point['l1'] + point['l2']) + 2*((point['l1'] + point['l2'])**2) n6 = 4*point['l1']*(1 - point['l1'] - point['l2']) shape_vector = np.array([[n1, 0, n2, 0, n3, 0, n4, 0, n5, 0, n6, 0], [0, n1, 0, n2, 0, n3, 0, n4, 0, n5, 0, n6]])

xc = 1*(n1*self.nodei.x + n2*self.nodej.x + n3*self.nodek.x + n4*self.nodel.x + n5*self.nodem.x + n6*self.noden.x) xi = rt detJ = np.linalg.det(jacobian) if element.ccxtype in ['CAX6']: t = 2*pi*xc else: t = 1 self.body_force_vector = self.body_force_vector + point['w']*t*abs(detJ)*np.matmul( np.transpose(shape_vector), xi) self.invert_coordinates(element) return self.body_force_vector def agreg_surf_force_vector(self, node1, node2, direc, val, face, nodeintermedio = None): """Agregates the contribution of the stresses to self.body_force_vector by doing the 'surface' integral from node1 to node2""" if self.element_type in ['CPS3', 'CAX3', 'CPE3']: #print('node1: ', node1.id, 'node2: ', node2.id) L = raiz_cuad((node1.x - node2.x)**2 + (node1.y - node2.y)**2) i, j, k = 1, 1, 1 p1x, p1y, p2x, p2y, p3x, p3y = 0, 0, 0, 0, 0, 0 # solamente tiene en cuenta esfuerzos normales, no cortantes if direc == '-y' or direc == 'y': if direc == '-y': val = -abs(val) else: val = abs(val) v = np.array([[0], [val]]) elif direc == '-x' or direc == 'x': if direc == '-x': val = -abs(val) else: val = abs(val) v = np.array([[val], [0]])

Page 238: Desarrollo de un laboratorio virtual de geotecnia enfocado

218 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

alpha = 0.861136 beta = 0.339981 pesoAlpha = 0.347855 pesoBeta = 0.652145 a = {'epsilon' : alpha, 'w' : pesoAlpha, 'id': 1} b = {'epsilon' : -alpha, 'w' : pesoAlpha, 'id': 2} c = {'epsilon' : beta, 'w' : pesoBeta, 'id': 3} d = {'epsilon' : -beta, 'w' : pesoBeta, 'id': 4} points = {'a': a, 'b': b, 'c': c, 'd': d} integral = np.zeros((4, 1)) for point in points.values(): n1 = 1/2*(1 - point['epsilon']) n2 = 1/2*(1 + point['epsilon']) matrix_N = np.array([[n1, 0, n2, 0], [0, n1, 0, n2]]) # En este punto y es la dirección vertical & x la dirección horizontal # como valor de direc pero como no utilizo invert_coords la distancia horizontal # se accede con node.y # Recibe el nodo organizado de forma contrahoraria if direc == '-y' or direc == 'y': t = (n1*node1.y + n2*node2.y) elif direc == '-x' or direc == 'x': t = (n1*node1.y + n2*node2.y) if self.element.ccxtype in ['CAX3']: ax = 2*pi*t else: ax = 1# print('t', t) # detJ = 0.5*L integral = integral + ax*point['w']*0.5*L*np.matmul(np.transpose(matrix_N), v)

if face == 'ij': self.body_force_vector[1-1][1-1]=self.body_force_vector[1-1][1-1]+integral[1-1][1-1] self.body_force_vector[2-1][1-1]=self.body_force_vector[2-1][1-1]+integral[2-1][1-1] self.body_force_vector[3-1][1-1]=self.body_force_vector[3-1][1-1]+integral[3-1][1-1] self.body_force_vector[4-1][1-1]=self.body_force_vector[4-1][1-1]+integral[4-1][1-1]

elif face == 'jk': self.body_force_vector[3-1][1-1]=self.body_force_vector[3-1][1-1]+integral[1-1][1-1]

Page 239: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 219

self.body_force_vector[4-1][1-1]=self.body_force_vector[4-1][1-1]+integral[2-1][1-1] self.body_force_vector[5-1][1-1]=self.body_force_vector[5-1][1-1]+integral[3-1][1-1] self.body_force_vector[6-1][1-1]=self.body_force_vector[6-1][1-1]+integral[4-1][1-1]

elif face == 'ki': self.body_force_vector[5-1][1-1]=self.body_force_vector[5-1][1-1]+integral[1-1][1-1] self.body_force_vector[6-1][1-1]=self.body_force_vector[6-1][1-1]+integral[2-1][1-1] self.body_force_vector[1-1][1-1]=self.body_force_vector[1-1][1-1]+integral[3-1][1-1] self.body_force_vector[2-1][1-1]=self.body_force_vector[2-1][1-1]+integral[4-1][1-1]# print('face', face)# print('carga', self.body_force_vector) elif self.element_type in ['CPS6', 'CAX6', 'CPE6']: L = raiz_cuad((node1.x - node2.x)**2 + (node1.y - node2.y)**2) i, j, k, l, m, n = 1/6, 2/3, 1/6, 2/3, 1/6, 2/3 p1x, p1y, p2x, p2y, p3x, p3y = 0, 0, 0, 0, 0, 0 p4x, p4y, p5x, p5y, p6x, p6y = 0, 0, 0, 0, 0, 0 # 1 Pa = 0.001 kPa p = 0.001*np.array([[-p1x], [p1y], [-p2x], [p2y], [-p3x], [p3y], [-p4x], [p4y], [-p5x], [p5y], [-p6x], [p6y]]) # solamente tiene en cuenta esfuerzos normales, no cortantes if direc == '-y' or direc == 'y': if direc == '-y': val = -abs(val) else: val = abs(val) v = np.array([[0], [val]]) elif direc == '-x' or direc == 'x': if direc == '-x': val = -abs(val) else: val = abs(val) v = np.array([[val], [0]]) # Error con t alpha = 0.861136 beta = 0.339981 pesoAlpha = 0.347855 pesoBeta = 0.652145

Page 240: Desarrollo de un laboratorio virtual de geotecnia enfocado

220 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

a = {'epsilon' : alpha, 'w' : pesoAlpha, 'id': 1} b = {'epsilon' : -alpha, 'w' : pesoAlpha, 'id': 2} c = {'epsilon' : beta, 'w' : pesoBeta, 'id': 3} d = {'epsilon' : -beta, 'w' : pesoBeta, 'id': 4}

points = {'a': a, 'b': b, 'c': c, 'd': d}

# primero hago la integral y después pongo los datos en los # grados de libertad involucrados integral = np.zeros((6, 1)) for point in points.values(): n1 = -1/2*(1 - point['epsilon'])*point['epsilon'] n2 = (1 - point['epsilon'])*(1 + point['epsilon']) n3 = 1/2*(1 + point['epsilon'])*point['epsilon'] matrix_N = np.array([[n1, 0, n2, 0, n3, 0], [0, n1, 0, n2, 0, n3]])

# En este punto y es la dirección vertical & x la dirección horizontal # como valor de direc pero como no utilizo invert_coords la distancia horizontal # se accede con node.y

# Recibe el nodo organizado de forma contrahoraria a = 1.65 if direc == '-y' or direc == 'y': t = a*(n1*node1.y + n3*node2.y + n2*nodeintermedio.y) detJ = (point['epsilon']-1/2)*node1.y - 2*point['epsilon']*nodeintermedio.y + (point['epsilon']+1/2)*node2.y elif direc == '-x' or direc == 'x': t = a*(n1*node1.y + n3*node2.y + n2*nodeintermedio.y) detJ = (point['epsilon']-1/2)*node1.x - 2*point['epsilon']*nodeintermedio.x + (point['epsilon']+1/2)*node2.x if self.element.ccxtype in ['CAX6']: ax = 2*pi*abs(t) else: ax = 1

integral = integral + ax*point['w']*abs(detJ)*np.matmul(np.transpose(matrix_N), v)

if face == 'ik': self.body_force_vector[1-1][1-1]=self.body_force_vector[1-1][1-1]+integral[1-1][1-1] self.body_force_vector[2-1][1-1]=self.body_force_vector[2-1][1-1]+integral[2-1][1-1] self.body_force_vector[3-1][1-1]=self.body_force_vector[3-1][1-1]+integral[3-1][1-1] self.body_force_vector[4-1][1-1]=self.body_force_vector[4-1][1-1]+integral[4-1][1-1]

Page 241: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 221

self.body_force_vector[5-1][1-1]=self.body_force_vector[5-1][1-1]+integral[5-1][1-1] self.body_force_vector[6-1][1-1]=self.body_force_vector[6-1][1-1]+integral[6-1][1-1] elif face == 'km': self.body_force_vector[5-1][1-1]=self.body_force_vector[5-1][1-1]+integral[1-1][1-1] self.body_force_vector[6-1][1-1]=self.body_force_vector[6-1][1-1]+integral[2-1][1-1] self.body_force_vector[7-1][1-1]=self.body_force_vector[7-1][1-1]+integral[3-1][1-1] self.body_force_vector[8-1][1-1]=self.body_force_vector[8-1][1-1]+integral[4-1][1-1] self.body_force_vector[9-1][1-1]=self.body_force_vector[9-1][1-1]+integral[5-1][1-1] self.body_force_vector[10-1][1-1]=self.body_force_vector[10-1][1-1]+integral[6-1][1-1] elif face == 'mi': self.body_force_vector[9-1][1-1]=self.body_force_vector[9-1][1-1]+integral[1-1][1-1] self.body_force_vector[10-1][1-1]=self.body_force_vector[10-1][1-1]+integral[2-1][1-1] self.body_force_vector[11-1][1-1]=self.body_force_vector[11-1][1-1]+integral[3-1][1-1] self.body_force_vector[12-1][1-1]=self.body_force_vector[12-1][1-1]+integral[4-1][1-1] self.body_force_vector[1-1][1-1]=self.body_force_vector[1-1][1-1]+integral[5-1][1-1] self.body_force_vector[2-1][1-1]=self.body_force_vector[2-1][1-1]+integral[6-

1][1-1] def int_Abramowitz_Stegun(self, coef, a, b): integral = coef*factorial(a)*factorial(b)/factorial(a+b+1) return integral def set_vector_n(self, element, kx, ky): """Builds the (ne) vector for the linear triangular element in the natural coordinate system l1, l2, l3""" self.invert_coordinates(element) # Here node ijk are needed because of the integral nodei, nodej, nodek = self.counterclockwise_format(element) jacobian = jacobiano.Jacobiano(element).matrix_J detJ = np.linalg.det(jacobian) inv_jacobian = np.linalg.inv(jacobian) for point in self.integration_points.values():

Page 242: Desarrollo de un laboratorio virtual de geotecnia enfocado

222 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# Page 377, Applied Finite Element Analysis - Larry J. Segerlind # 2*area = |det(J)| n1 = point['l1'] n2 = point['l2'] n3 = 1-point['l1']-point['l2'] xc = nodei.x*n1 + nodej.x*n2 + nodek.x*n3 self.matrix_E = element_shape_matrices.Shape_matrices(inv_jacobian, element.ccxtype, point['l1'], point['l2'], xc).matrix_E matrix_k_Darcy = np.array([[kx, 0], [0, ky]]) # vector {iG} corresponds to the positional energy in each node # the horizontal reference axe is the origin of the vertical # axis in the general coordinate system matrix_n0 = np.matmul(np.transpose(self.matrix_E), matrix_k_Darcy) # x = 0 because the positional energy is measured in y # X = 0 # Page 373 Applied Finite Element Analysis - Larry J. Segerlind Eq.(27.12) # Y = n1*nodei.y + n2*nodej.y + n3*nodek.y

if element.ccxtype in ['CAX3']: ax = 2*pi*xc else: ax = 1 # is the unit vector parallel, but in the opposite direction, to gravity #vector_iG = 1/np.linalg.norm(np.array([[X],[Y]]))*np.array([[X],[Y]]) vector_iG = np.array([[0],[1]]) self.vector_n = self.vector_n + point['w']*ax*abs(detJ)*np.dot(matrix_n0, vector_iG) self.invert_coordinates(element) return self.vector_n

element_matrices.py"""This module stores element k matrix classes.""" #JOscar

import numpy as npfrom numpy.linalg import invfrom math import pifrom copy import deepcopyimport time

import integration_points

Page 243: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 223

import ccw_formatimport inv_coordimport jacobianoimport element_shape_matricesimport matrix_Dep

np.set_printoptions(precision=3)

class Element_matrices(object): """Makes an element matrix in a 2D field_problem 'field_problem' the equation to solve is Dx(d2u/dx2) + Dy(d2u/dy2) + Gu + Q = 0 or makes the element matrices in a 'consolidation' problem

Args: write here the arguments element(mesh.element): element object Defining the equation: Dx(d2u/dx2) + Dy(d2u/dy2) + Gu + Q = 0 Dx(float): propertie in x direction Dy(float): propertie in y direction G(float) Q(float) self. problem_type - problem_type(string): kind of problem, value 'field_problem' the equation to solve is Dx(d2u/dx2) + Dy(d2u/dy2) + Gu + Q = 0 Value 'consolidation' try to solve the consolidation system FEA equations Attributes: write here the used attributes in this module id (int): element matrix number x (float): x-coordinate y (float): y-coordinate z (float): z-coordinate self.matrix_B: matriz de interpolación de desplazamientos self.matrix_k: matriz de rigidez del elemento self.matrix_l: matriz de rigidez asociada a flujo y deformaciones self.matrix_C: 12X12 distortion rate matrix """

def __init__(self, element, problem_type): self.id = element.id self.problem_type = problem_type

if element.ccxtype in ['CPS3', 'CAX3', 'CPE3'] and self.problem_type == 'field_problem': self.matrix_B = np.zeros((2, 3)) self.matrix_k_Dx = np.zeros((3, 3))

Page 244: Desarrollo de un laboratorio virtual de geotecnia enfocado

224 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.matrix_k_Dy = np.zeros((3, 3)) self.matrix_k = np.zeros((3, 3)) self.integration_points = integration_points.Integration_points().integration_points if element.ccxtype in ['CPS3', 'CPE3']: self.t = 1 elif element.ccxtype in ['CAX3']: self.t = 2*pi*element.calc_center().y elif element.ccxtype in ['CPS3', 'CAX3', 'CPE3'] and self.problem_type == 'consolidation': self.matrix_B = np.zeros((4, 6)) self.matrix_B_total = np.zeros((4, 6)) self.matrix_D = np.zeros((4, 4)) self.matrix_k = np.zeros((6, 6)) self.matrix_l = np.zeros((6, 3)) self.matrix_E = np.zeros((2, 3)) self.matrix_phi = np.zeros((3, 3)) self.integration_points = integration_points.Integration_points().integration_points elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: self.matrix_B = np.zeros((4, 12))# self.matrix_BL = np.zeros((4, 12)) self.matrix_B_total = np.zeros((4, 12)) self.matrix_ksigma = np.zeros((12, 12)) self.matrix_k = np.zeros((12, 12)) self.matrix_kL = np.zeros((12, 12)) self.integration_points = integration_points.Integration_points().integration_points self.matrix_FT = np.zeros((3, 3)) if element.ccxtype in ['CPS6', 'CPE6']: self.t = 1 elif element.ccxtype in ['CAX6']: self.t = 2*pi*element.calc_center().y def __hash__(self): """Returns the item's id as its hash.""" return self.id def counterclockwise_format(self, element): """Organizes the nodes of the element in a counterclockwise format 'i, j and k'. A linear triangular element is used""" formato = ccw_format.Ccw(element) if element.ccxtype in ['CPS3', 'CAX3', 'CPE3']: self.nodei = formato.nodei self.nodej = formato.nodej self.nodek = formato.nodek return self.nodei, self.nodej, self.nodek

Page 245: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 225

elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: self.nodei = formato.nodei self.nodej = formato.nodej self.nodek = formato.nodek self.nodel = formato.nodel self.nodem = formato.nodem self.noden = formato.noden return self.nodei, self.nodej, self.nodek, self.nodel, self.nodem, self.noden

def invert_coordinates(self, element): inv_coord.Inv_coord(element) def set_boundary_matrix(self): self.uno = 1 def set_matrix_B(self, inv_jacobian, ccxtype, l1, l2, xc): """Builds the (Be) matrix for the linear triangular element in the natural coordinate system l1, l2, l3""" self.matrix_B = element_shape_matrices.Shape_matrices(inv_jacobian, ccxtype, l1, l2, xc).matrix_B return self.matrix_B def set_matrix_BL_ksigma(self, inv_jacobian, ccxtype, l1, l2, xc, vect_u, cauchy): matrices = element_shape_matrices.Shape_matrices(inv_jacobian, ccxtype, l1, l2, xc, vect_u, cauchy) return matrices.matrix_BL, matrices.matrix_ksigma, matrices.gradient_matrix_FT def set_matrix_E(self, inv_jacobian, ccxtype, l1, l2, xc): self.matrix_E = element_shape_matrices.Shape_matrices(inv_jacobian, ccxtype, l1, l2, xc).matrix_E return self.matrix_E def set_matrix_k(self, element, Dx = None, Dy = None, nu = None, e = None, _resp = None, H = None, phi = None): """Builds the (ke) matrix for the linear triangular element in the natural coordinate system l1, l2, l3""" self.invert_coordinates(element) if element.ccxtype in ['CPS3', 'CAX3', 'CPE3']:

Page 246: Desarrollo de un laboratorio virtual de geotecnia enfocado

226 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

nodei, nodej, nodek = self.counterclockwise_format(element) elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: nodei, nodej, nodek, nodel, nodem, noden = self.counterclockwise_format(element)

if self.problem_type == 'field_problem': bi = nodej.y - nodek.y bj = nodek.y - nodei.y bk = nodei.y - nodej.y ci = nodek.x - nodej.x cj = nodei.x - nodek.x ck = nodej.x - nodei.x jacobian = jacobiano.Jacobiano(element).matrix_J area = 1/2 * np.linalg.det(jacobian) self.matrix_k_Dx = (Dx/(4*area))*np.array([[bi**(2), bi*bj, bi*bk], [bi*bj, bj**(2), bj*bk], [bi*bk, bj*bk, bk**(2)]]) self.matrix_k_Dy = (Dy/(4*area))*np.array([[ci**(2), ci*cj, ci*ck], [ci*cj, cj**(2), cj*ck], [ci*ck, cj*ck, ck**(2)]]) self.matrix_k = self.matrix_k_Dx + self.matrix_k_Dy self.invert_coordinates(element) return self.matrix_k elif self.problem_type == 'consolidation': jacobian = jacobiano.Jacobiano(element).matrix_J detJ = np.linalg.det(jacobian) inv_jacobian = inv(jacobian)

# Pages 8 and 9 Potts Zdravkovic 1999 Finite Element theory Eq(1.7) self.matrix_D = e/((1 + nu)*(1 - 2*nu))*np.array( [[1-nu, nu, 0, nu], [nu, 1-nu, 0, nu], [0, 0, 1/2 - nu, 0], [nu, nu, 0, 1-nu]])

# # xc is the radius to the centroid of the element for point in self.integration_points.values(): n1 = point['l1'] n2 = point['l2'] n3 = 1-point['l1']-point['l2'] xc = nodei.x*n1 + nodej.x*n2 + nodek.x*n3 self.matrix_B = self.set_matrix_B(inv_jacobian, element.ccxtype, point['l1'], point['l2'], xc)

Page 247: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 227

# self.matrix_B_total = self.matrix_B_total + point['w']*self.matrix_B Tiene un error# el peso de los puntos de integración no sirve para esto matrix_k0 = point['w']*np.matmul(np.transpose(self.matrix_B), self.matrix_D) # 2*area = |det(J)| if element.ccxtype in ['CAX3']: t = 2*pi*xc else: t = 1 self.matrix_k = self.matrix_k + t*abs(detJ)*np.matmul(matrix_k0, self.matrix_B) # print('ijk', nodei.id, nodej.id, nodek.id)# print('point', point)# print(detJ)# print(self.matrix_k) self.invert_coordinates(element) return self.matrix_k elif self.problem_type == 'large_displacements': #PENDIENTE DE LA TESIS DE BURD # Pages 8 and 9 Potts Zdravkovic 1999 Finite Element theory Eq(1.7) # esta variable guardará la matriz D del elemento self.matrix_D = e/((1 + nu)*(1 - 2*nu))*np.array( [[1-nu, nu, 0, nu], [nu, 1-nu, 0, nu], [0, 0, 1/2 - nu, 0], [nu, nu, 0, 1-nu]]) # esta matriz se puede modificar para albergar la de los puntos de integración matrix_D = deepcopy(self.matrix_D) if _resp != None: # AGREGAR CONDICIONAL PARA VER SI EL ELEMENTO ESTÁ EN FLUENCIA Listo # SI NO, UTILIZAR LA MATRIZ D ELÁSTICA Listo vect_u = _resp['element'][element.id]['vect_u'] cauchy = _resp['element'][element.id]['cauchy'] # Verificar si los puntos de integración están en fluencia o no # Varios autores dicen la matriz de depende del punto de integración # verificar si el elemento está en fluencia # sé cuál es el estado de los puntos de integración # puedo promediar la matriz D en los puntos de integración para # estimar la matriz total del elemento # La reinicio en ceros porque para cada punto se estima a partir de D # de los puntos de integración self.matrix_D = np.zeros((4, 4)) self.matricesEnPuntosIntegracion = {} for point in self.integration_points.values(): jacobian = jacobiano.Jacobiano(element, l1 = point['l1'], l2 = point['l2']).matrix_J

Page 248: Desarrollo de un laboratorio virtual de geotecnia enfocado

228 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

inv_jacobian = inv(jacobian) # xc is the radius to the centroid of the element # Zeevaert 'r a is the radial distance for the sampling point under consideration' fN1 = point['l1']*(2*point['l1'] - 1) fN2 = 4*point['l1']*point['l2'] fN3 = point['l2']*(2*point['l2'] - 1) fN4 = 4*point['l2']*(1 - point['l1'] - point['l2']) fN5 = 1 - 3*(point['l1'] + point['l2']) + 2*(point['l1'] + point['l2'])**2 fN6 = 4*point['l1']*(1 - point['l1'] - point['l2'])

xc = fN1*nodei.x + fN2*nodej.x + fN3*nodek.x + fN4*nodel.x + fN5*nodem.x + fN6*noden.x# xc = element.calc_center().x matrix_Bi = self.set_matrix_B(inv_jacobian, element.ccxtype, point['l1'], point['l2'], xc) self.matricesEnPuntosIntegracion[point['id']] = {} self.matricesEnPuntosIntegracion[point['id']]['matrix_B'] = deepcopy( matrix_Bi) matrix_Di = matrix_D self.matricesEnPuntosIntegracion[point['id']]['matrix_D'] = deepcopy( matrix_D) # The first step if _resp != None: verificadorDeFluencia = _resp['element'][element.id]['points'][point['id']]['yield'] cauchy = _resp['element'][element.id]['points'][point['id']]['cauchy'] if verificadorDeFluencia: matrix_DelasticPlastic = matrix_Dep.Matrix_Dep(matrix_D, H, phi, cauchy) matrix_Di = matrix_DelasticPlastic.matrix_Dep else: matrix_Di = matrix_D # para estimar la matrix_D del elemento self.matrix_D = self.matrix_D + point['w']*matrix_Di self.matrix_B = self.matrix_B + point['w']*matrix_Bi self.matricesEnPuntosIntegracion[point['id']]['matrix_D'] = deepcopy( matrix_Di) matrix_BLi, delta_matrix_ksigma, dFT = self.set_matrix_BL_ksigma( inv_jacobian, element.ccxtype, point['l1'], point['l2'], xc, vect_u, cauchy) self.matricesEnPuntosIntegracion[point['id']]['matrix_BL'] = matrix_BLi self.matricesEnPuntosIntegracion[point['id']]['FT'] = dFT # dFT no depende de cauchy self.matrix_FT = self.matrix_FT + point['w']*dFT self.matrix_ksigma = point['w']*delta_matrix_ksigma + self.matrix_ksigma

Page 249: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 229

# At this point the self.matrix_D is the matrix_Dep if yielding first = np.matmul(np.transpose(matrix_Bi), np.matmul(matrix_Di, matrix_BLi)) second = np.matmul(np.transpose(matrix_BLi), np.matmul(matrix_Di, matrix_BLi)) third = np.matmul(np.transpose(matrix_BLi), np.matmul(matrix_Di, matrix_Bi)) matrix_kLi = first + second + third self.matrix_kL = point['w']*matrix_kLi + self.matrix_kL self.matrix_B_total = self.matrix_B_total + point['w']*( self.matrix_B + matrix_BLi) else: self.matrix_D = self.matrix_D + point['w']*matrix_Di self.matrix_B = self.matrix_B + point['w']*matrix_Bi self.matrix_B_total = self.matrix_B_total + point['w']*matrix_Bi self.matricesEnPuntosIntegracion[point['id']]['matrix_B'] = deepcopy( matrix_Bi) self.matricesEnPuntosIntegracion[point['id']]['matrix_D'] = deepcopy( matrix_Di) matrix_k0 = point['w']*np.matmul(np.transpose(matrix_Bi), matrix_Di) detJ = np.linalg.det(jacobian) self.matrix_k = self.matrix_k + 2*pi*abs(xc)*abs(detJ)*np.matmul( matrix_k0, matrix_Bi) self.invert_coordinates(element) return self.matrix_k def set_matrix_l(self, element): """Builds the (le) matrix for the linear triangular element in the natural coordinate system l1, l2, l3""" self.invert_coordinates(element) jacobian = jacobiano.Jacobiano(element).matrix_J detJ = np.linalg.det(jacobian) inv_jacobian = inv(jacobian) nodei, nodej, nodek = self.counterclockwise_format(element) for point in self.integration_points.values(): # Page 377, Applied Finite Element Analysis - Larry J. Segerlind # 2*area = |det(J)| n1 = point['l1'] n2 = point['l2'] n3 = 1-point['l1']-point['l2'] xc = nodei.x*n1 + nodej.x*n2 + nodek.x*n3 self.matrix_B = self.set_matrix_B(inv_jacobian, element.ccxtype,

Page 250: Desarrollo de un laboratorio virtual de geotecnia enfocado

230 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

point['l1'], point['l2'], xc) m = np.array( [[1], [1], [0], # creo que con este cero se ignora el aporte por cortante [1]]) bt_m = np.dot(np.transpose(self.matrix_B), m) if element.ccxtype in ['CAX3']: t = 2*pi*xc else: t = 1 matrix_Np = np.array([[n1, n2, n3]]) self.matrix_l = self.matrix_l + t*abs(detJ)*point['w']*np.matmul(bt_m, matrix_Np)

self.invert_coordinates(element) return self.matrix_l def set_matrix_phi(self, element, kx, ky, fluid_unit_weight): """Builds the (le) matrix for the linear triangular element in the natural coordinate system l1, l2, l3""" self.invert_coordinates(element) jacobian = jacobiano.Jacobiano(element).matrix_J detJ = np.linalg.det(jacobian) inv_jacobian = inv(jacobian) nodei, nodej, nodek = self.counterclockwise_format(element) for point in self.integration_points.values(): # Page 377, Applied Finite Element Analysis - Larry J. Segerlind # 2*area = |det(J)|

n1 = point['l1'] n2 = point['l2'] n3 = 1-point['l1']-point['l2'] xc = nodei.x*n1 + nodej.x*n2 + nodek.x*n3 self.matrix_E = self.set_matrix_E(inv_jacobian, element.ccxtype, point['l1'], point['l2'], xc) matrix_k_Darcy = 1/fluid_unit_weight*np.array([[kx, 0], [0, ky]]) matrix_phi0 = point['w']*np.matmul(np.transpose(self.matrix_E), matrix_k_Darcy) # 2*area = |det(J)| if element.ccxtype in ['CAX3']: t = 2*pi*xc else: t = 1 self.matrix_phi = self.matrix_phi + t*abs(detJ)*np.matmul( matrix_phi0, self.matrix_E) self.invert_coordinates(element) return self.matrix_phi

Page 251: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 231

element_shape_matrices.py"""This module builds the B and E matrices.""" #JOscar

from __future__ import divisionimport numpy as npimport time

class Shape_matrices(): """Makes the B and E matrices.

Args: write here the arguments

Attributes: write here the used attributes in this module """ def __init__(self, inv_jacobian, geometric_idealisation, n1, n2, r, vect_u = np.array([[None]]), cauchy = None):# print('vect_u', vect_u) if vect_u.all() == None: self.matrix_B = self.set_matrix_B(inv_jacobian, geometric_idealisation, n1, n2, r) self.matrix_E = self.set_matrix_E(inv_jacobian, geometric_idealisation, n1, n2, r) else: self.matrix_BL, self.matrix_ksigma, self.gradient_matrix_FT= self.set_matrix_BL_ksigma( inv_jacobian, geometric_idealisation, n1, n2, r, vect_u, cauchy) self.inf_strain = np.zeros((3, 3)) def set_deriv_shape_funct_lineal(self, inv_jacobian): """Sets derivates of the shape functions in the natural coordinate system (l1, l2, l3) and relates them with the derivates in the global coordinate system for the linear triangular element""" dN1_dL1 = 1 dN1_dL2 = 0 dN2_dL1 = 0 dN2_dL2 = 1 dN3_dL1 = -1 dN3_dL2 = -1 dN1_natural = np.array([[dN1_dL1],[dN1_dL2]]) dN2_natural = np.array([[dN2_dL1],[dN2_dL2]]) dN3_natural = np.array([[dN3_dL1],[dN3_dL2]]) # Page 381 Applied Finite Element Analysis - Larry J. Segerlind Eq.(27.40) dN1_global = np.matmul(inv_jacobian, dN1_natural) dN2_global = np.matmul(inv_jacobian, dN2_natural) dN3_global = np.matmul(inv_jacobian, dN3_natural)

Page 252: Desarrollo de un laboratorio virtual de geotecnia enfocado

232 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

dN1_dx = dN1_global[0][0] dN1_dy = dN1_global[1][0] dN2_dx = dN2_global[0][0] dN2_dy = dN2_global[1][0] dN3_dx = dN3_global[0][0] dN3_dy = dN3_global[1][0] dN1 = {'dN1_dx': dN1_dx, 'dN1_dy': dN1_dy} dN2 = {'dN2_dx': dN2_dx, 'dN2_dy': dN2_dy} dN3 = {'dN3_dx': dN3_dx, 'dN3_dy': dN3_dy} der_shape_funct = {'dN1': dN1, 'dN2': dN2, 'dN3': dN3} return der_shape_funct def set_deriv_shape_funct_quadratic(self, inv_jacobian, l1, l2): """Sets derivates of the shape functions in the natural coordinate system (l1, l2, l3) and relates them with the derivates in the global coordinate system for the quadratic triangular element""" dN1_dL1 = 4*l1 - 1 dN1_dL2 = 0 dN2_dL1 = 4*l2 dN2_dL2 = 4*l1 dN3_dL1 = 0 dN3_dL2 = 4*l2 - 1 dN4_dL1 = -4*l2 dN4_dL2 = 4*(1 - l1 - 2*l2) dN5_dL1 = -3 + 4*(l1 + l2) dN5_dL2 = -3 + 4*(l1 + l2) dN6_dL1 = 4*(1 - 2*l1 - l2) dN6_dL2 = -4*l1 dN1_natural = np.array([[dN1_dL1],[dN1_dL2]]) dN2_natural = np.array([[dN2_dL1],[dN2_dL2]]) dN3_natural = np.array([[dN3_dL1],[dN3_dL2]]) dN4_natural = np.array([[dN4_dL1],[dN4_dL2]]) dN5_natural = np.array([[dN5_dL1],[dN5_dL2]]) dN6_natural = np.array([[dN6_dL1],[dN6_dL2]]) dN1_global = np.matmul(inv_jacobian, dN1_natural) dN2_global = np.matmul(inv_jacobian, dN2_natural) dN3_global = np.matmul(inv_jacobian, dN3_natural) dN4_global = np.matmul(inv_jacobian, dN4_natural)

Page 253: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 233

dN5_global = np.matmul(inv_jacobian, dN5_natural) dN6_global = np.matmul(inv_jacobian, dN6_natural) dN1_dx = dN1_global[0][0] dN1_dy = dN1_global[1][0] dN2_dx = dN2_global[0][0] dN2_dy = dN2_global[1][0] dN3_dx = dN3_global[0][0] dN3_dy = dN3_global[1][0] dN4_dx = dN4_global[0][0] dN4_dy = dN4_global[1][0] dN5_dx = dN5_global[0][0] dN5_dy = dN5_global[1][0] dN6_dx = dN6_global[0][0] dN6_dy = dN6_global[1][0] dN1 = {'dN1_dx': dN1_dx, 'dN1_dy': dN1_dy} dN2 = {'dN2_dx': dN2_dx, 'dN2_dy': dN2_dy} dN3 = {'dN3_dx': dN3_dx, 'dN3_dy': dN3_dy} dN4 = {'dN4_dx': dN4_dx, 'dN4_dy': dN4_dy} dN5 = {'dN5_dx': dN5_dx, 'dN5_dy': dN5_dy} dN6 = {'dN6_dx': dN6_dx, 'dN6_dy': dN6_dy}

der_shape_funct = {'dN1': dN1, 'dN2': dN2, 'dN3': dN3, 'dN4': dN4, 'dN5': dN5, 'dN6': dN6} return der_shape_funct def set_matrix_B(self, inv_jacobian, geometric_idealisation, n1, n2, r): """Builds the (Be) matrix for the linear triangular element in the natural coordinate system l1, l2, l3""" if geometric_idealisation in ['CAX3', 'CPE3']: der_shape_funct = self.set_deriv_shape_funct_lineal(inv_jacobian) dN1_dx = der_shape_funct.get('dN1').get('dN1_dx') dN1_dy = der_shape_funct.get('dN1').get('dN1_dy') dN2_dx = der_shape_funct.get('dN2').get('dN2_dx') dN2_dy = der_shape_funct.get('dN2').get('dN2_dy') dN3_dx = der_shape_funct.get('dN3').get('dN3_dx') dN3_dy = der_shape_funct.get('dN3').get('dN3_dy') elif geometric_idealisation in ['CAX6', 'CPE6']: der_shape_funct = self.set_deriv_shape_funct_quadratic(inv_jacobian, n1, n2) dN1_dx = der_shape_funct.get('dN1').get('dN1_dx') dN1_dy = der_shape_funct.get('dN1').get('dN1_dy') dN2_dx = der_shape_funct.get('dN2').get('dN2_dx') dN2_dy = der_shape_funct.get('dN2').get('dN2_dy') dN3_dx = der_shape_funct.get('dN3').get('dN3_dx')

Page 254: Desarrollo de un laboratorio virtual de geotecnia enfocado

234 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

dN3_dy = der_shape_funct.get('dN3').get('dN3_dy') dN4_dx = der_shape_funct.get('dN4').get('dN4_dx') dN4_dy = der_shape_funct.get('dN4').get('dN4_dy') dN5_dx = der_shape_funct.get('dN5').get('dN5_dx') dN5_dy = der_shape_funct.get('dN5').get('dN5_dy') dN6_dx = der_shape_funct.get('dN6').get('dN6_dx') dN6_dy = der_shape_funct.get('dN6').get('dN6_dy') if geometric_idealisation == 'CPE3': self.matrix_B = np.array([[dN1_dx, 0, dN2_dx, 0, dN3_dx, 0], [0, dN1_dy, 0, dN2_dy, 0, dN3_dy], [dN1_dy, dN1_dx, dN2_dy, dN2_dx, dN3_dy, dN3_dx], [0, 0, 0, 0, 0, 0]]) elif geometric_idealisation == 'CAX3': n3 = 1 - n1 - n2 self.matrix_B = np.array([[dN1_dx, 0, dN2_dx, 0, dN3_dx, 0], [0, dN1_dy, 0, dN2_dy, 0, dN3_dy], [dN1_dy, dN1_dx, dN2_dy, dN2_dx, dN3_dy, dN3_dx], [n1/r, 0, n2/r, 0, n3/r, 0]]) elif geometric_idealisation == 'CAX6': fN1 = n1*(2*n1 - 1) fN2 = 4*n1*n2 fN3 = n2*(2*n2 - 1) fN4 = 4*n2*(1 - n1 - n2) fN5 = 1 - 3*(n1 + n2) + 2*(n1 + n2)**2 fN6 = 4*n1*(1 - n1 - n2) # Page 365, Applied Finite Element Analysis - Larry J. Segerlind self.matrix_B = np.array([[dN1_dx, 0, dN2_dx, 0, dN3_dx, 0, dN4_dx, 0, dN5_dx, 0, dN6_dx, 0], [0, dN1_dy, 0, dN2_dy, 0, dN3_dy, 0, dN4_dy, 0, dN5_dy, 0, dN6_dy], [dN1_dy, dN1_dx, dN2_dy, dN2_dx, dN3_dy, dN3_dx, dN4_dy, dN4_dx, dN5_dy, dN5_dx, dN6_dy, dN6_dx], [fN1/r, 0, fN2/r, 0, fN3/r, 0, fN4/r, 0, fN5/r, 0, fN6/r, 0]])# # [dN1_dy, -dN1_dx, dN2_dy, -dN2_dx, dN3_dy, -dN3_dx, # dN4_dy, -dN4_dx, dN5_dy, -dN5_dx, dN6_dy, -dN6_dx]

return self.matrix_B def set_matrix_BL_ksigma(self, inv_jacobian, geometric_idealisation, n1, n2, r, vect_u, cauchy): if geometric_idealisation == 'CAX6': der_shape_funct = self.set_deriv_shape_funct_quadratic(inv_jacobian, n1, n2)

Page 255: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 235

dN1_dx = der_shape_funct.get('dN1').get('dN1_dx') dN1_dy = der_shape_funct.get('dN1').get('dN1_dy') dN2_dx = der_shape_funct.get('dN2').get('dN2_dx') dN2_dy = der_shape_funct.get('dN2').get('dN2_dy') dN3_dx = der_shape_funct.get('dN3').get('dN3_dx') dN3_dy = der_shape_funct.get('dN3').get('dN3_dy') dN4_dx = der_shape_funct.get('dN4').get('dN4_dx') dN4_dy = der_shape_funct.get('dN4').get('dN4_dy') dN5_dx = der_shape_funct.get('dN5').get('dN5_dx') dN5_dy = der_shape_funct.get('dN5').get('dN5_dy') dN6_dx = der_shape_funct.get('dN6').get('dN6_dx') dN6_dy = der_shape_funct.get('dN6').get('dN6_dy') fN1 = n1*(2*n1 - 1) fN2 = 4*n1*n2 fN3 = n2*(2*n2 - 1) fN4 = 4*n2*(1 - n1 - n2) fN5 = 1 - 3*(n1 + n2) + 2*(n1 + n2)**2 fN6 = 4*n1*(1 - n1 - n2)

p1 = np.array([[dN1_dx, 0, dN2_dx, 0, dN3_dx, 0, dN4_dx, 0, dN5_dx, 0, dN6_dx, 0], [dN1_dy, 0, dN2_dy, 0, dN3_dy, 0, dN4_dy, 0, dN5_dy, 0, dN6_dy, 0]]) p2 = np.array([[0, dN1_dx, 0, dN2_dx, 0, dN3_dx, 0, dN4_dx, 0, dN5_dx, 0, dN6_dx], [0, dN1_dy, 0, dN2_dy, 0, dN3_dy, 0, dN4_dy, 0, dN5_dy, 0, dN6_dy]]) g1 = np.matmul(inv_jacobian, p1) g2 = np.matmul(inv_jacobian, p2) _r = 1/r*np.array([[fN1, 0, fN2, 0, fN3, 0, fN4, 0, fN5, 0, fN6, 0]]) u_r = np.matmul(_r, vect_u) # print('inv_jacobian', inv_jacobian)# print('p1', p1)# print('p2', p2) # Ecuation 55 chapter V Zeevaert 1980 theta1 = np.matmul(g1, vect_u)#du theta2 = np.matmul(g2, vect_u)#dv theta = np.zeros((5, 1)) theta[1-1][1-1] = theta1[1-1][1-1]#du_dr theta[2-1][1-1] = theta2[1-1][1-1]#dv_dr theta[3-1][1-1] = theta1[2-1][1-1]#du_dz theta[4-1][1-1] = theta2[2-1][1-1]#dv_dz theta[5-1][1-1] = u_r[1-1][1-1] g = np.array([g1[1-1], g2[1-1], g1[2-1], g2[2-1], _r[1-1]]) a = np.array([[theta[1-1][1-1], theta[2-1][1-1], 0, 0, 0],

Page 256: Desarrollo de un laboratorio virtual de geotecnia enfocado

236 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

[0, 0, theta[3-1][1-1], theta[4-1][1-1], 0], [theta[3-1][1-1], theta[4-1][1-1], theta[1-1][1-1], theta[2-1][1-1], 0], [0, 0, 0, 0, u_r[1-1][1-1]]]) # print('g', g)# print('r', r)# print('1_r', _r) self.matrix_BL = np.matmul(a, g) self.matrix_ksigma = np.zeros((12, 12)) filas = np.arange(0, 12, 1) columnas = np.arange(0, 12, 1) sigma_r = cauchy[1-1][1-1] sigma_z = cauchy[2-1][2-1] tau_rz = cauchy[2-1][1-1] sigma_theta = cauchy[3-1][3-1]# print('cauchy', cauchy) for m in filas: for n in columnas: self.matrix_ksigma[m][n] = 1*( sigma_r*(g[1-1][m]*g[1-1][n] + g[2-1][m]*g[2-1][n]) + 2*tau_rz*(g[1-1][m]*g[3-1][n] + g[2-1][m]*g[4-1][n]) + sigma_z*(g[3-1][m]*g[3-1][n] + g[4-1][m]*g[4-1][n]) + sigma_theta*(g[5-1][m]*g[5-1][n]))# time.sleep(5.5)# print('self.matrix_ksigma', self.matrix_ksigma) # Now I have to calculate the incremental second Piola-Kirchhoff stress # using the transformation matrix F and the incremental Cauchy calculated # early. [F]T is the gradient matrix: Zeevaert page 91 du_dr = theta[1-1][1-1] dv_dr = theta[2-1][1-1] du_dz = theta[3-1][1-1] dv_dz = theta[4-1][1-1] u_r = theta[5-1][1-1] gradient_matrix_FT = np.array([[1+du_dr, dv_dr, 0], [du_dz, 1+dv_dz, 0], [0, 0, 1+u_r]]) # Creo que ya no necesito el tensor de deformaciones infinitesimales self.inf_strain = np.array([[du_dr, dv_dr + du_dz, 0], [dv_dr + du_dz, dv_dz, 0], [0, 0, 0, u_r]]) # gradient_matrix_FT no depende del estado de esfuerzos return self.matrix_BL, self.matrix_ksigma, gradient_matrix_FT

Page 257: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 237

def set_matrix_E(self, inv_jacobian, geometric_idealisation, n1, n2, r): der_shape_funct = self.set_deriv_shape_funct_lineal(inv_jacobian) dN1_dx = der_shape_funct.get('dN1').get('dN1_dx') dN1_dy = der_shape_funct.get('dN1').get('dN1_dy') dN2_dx = der_shape_funct.get('dN2').get('dN2_dx') dN2_dy = der_shape_funct.get('dN2').get('dN2_dy') dN3_dx = der_shape_funct.get('dN3').get('dN3_dx') dN3_dy = der_shape_funct.get('dN3').get('dN3_dy') if geometric_idealisation == 'CPE3': self.matrix_E = np.array([[dN1_dx, dN2_dx, dN3_dx], [dN1_dy, dN2_dy, dN3_dy]])

elif geometric_idealisation == 'CAX3': n3 = 1 - n1 - n2 self.matrix_E = np.array([[dN1_dx, dN2_dx, dN3_dx], [dN1_dy, dN2_dy, dN3_dy]]) else: return None return self.matrix_E

failure_criterion.py# -*- coding: utf-8 -*-""" @author: JOscar"""import numpy as npfrom math import sin, cos, sqrtimport time

import matrix_Dep

def corroborate_yield_criterion(cauchy, c, phi, y_tol = 1*10**(-4)): # o hacerlo con los esfuerzos principales # ver fórmulas de Zeevaert """ Si el elemento cumple con el criterio de fluencia la matriz D es reemplazada por Dep La condición de falla es verificada para cada uno de los puntos de integración. 'For points in failure outside the failure envelope, the stress modification of Chapter VIII, figure 8.3 The modified stresses replace the original computed stresses which fall outside the failure envelope.' El criterio de plastificación de Drucker y Prager puede ser escrito como: F(σ, k) = 3*α'*σm + σ' - k α' = 2*senΦ'/(3^1/2*(3-senΦ'))

Page 258: Desarrollo de un laboratorio virtual de geotecnia enfocado

238 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

k = 6*c'*cosΦ'/(3^1/2*(3-senΦ')) σm = 1/3*J2 = 1/3*(σ1 + σ2 + σ3) σ' = J2^(1/2) args: cauchy: np.array stress state to analyze c: cohesion phi: friction angle attributes: f: float, value of yield function msg: str """ sigmar = cauchy[1-1][1-1] sigmaz = cauchy[2-1][2-1] trz = cauchy[2-1][1-1] sigmatheta = cauchy[3-1][3-1] alpha = 2*sin(phi)/(3**(1/2)*(3-sin(phi))) k = 6*c*cos(phi)/(3**(1/2)*(3-sin(phi))) sigmam = 1/3*(sigmar + sigmaz + sigmatheta) sr = sigmar - sigmam stheta = sigmatheta - sigmam sz = sigmaz - sigmam raizJ2 = sqrt(1/2*(sr**2 + stheta**2 + sz**2) + trz**2) sigmaRaya = raizJ2 f = -3*alpha*sigmam + sigmaRaya - k if f > 0 + y_tol: msg = "Estado ilegal de esfuerzos" elif f < 0 - y_tol: msg = "Respuesta elastica" elif f < 0 + y_tol and f > 0 - y_tol: msg = "Fluencia" return f, msg # buscar alpha tal que representa la fracción del incremento que está en fluencia# tiene que recibir el estado de esfuerzos inicial y el incremento en el mismodef set_alpha(cauchy_inicial, delta_cauchy, c, phi, alpha_tol = 1*10**-4, y_tol = 1*10**-4): """According to the definition of 'Potts Zdravkovic 1999 Finite Element theory' page 278. args: cauchy_inicial: np.array, delta_cauchy: np.array, c: float, cohesion phi: float, friction angle alpha_tol: float, user defined tolerance to set the value of alpha y_tol: float, tolerance to achieve the yield condition

Page 259: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 239

attributes: list_alpha: list, contains the alpha values calculated in the Newton-Raphson approach delta_alpha: float, """ list_alpha = [0, 1] delta_alpha = abs(list_alpha[-1] - list_alpha[-2]) ambiguity_case2 = False # Ambiguity cases f, msg1 = corroborate_yield_criterion(cauchy_inicial, c, phi) s, msg2 = corroborate_yield_criterion(cauchy_inicial+delta_cauchy, c, phi) # print('f, msg1', f, msg1)# print('s, msg1', s, msg2) if msg1 == "Respuesta elastica" and msg2 == "Respuesta elastica": return 1 # alpha = 1 elif msg1 == "Fluencia" and msg2 == "Estado ilegal de esfuerzos":

# Ambiguity case 2: the initial stress state is at yield and the path goes inside # the yield function and goes to yield again # In this case it is necessary to calculate the quantity (∂F(σ,k)/∂σ)Δσ # if it is negative this case exists # Ambiguity case 1: the initial stress state is at yield, if positive this case # exists # calcular la derivada alphaf = 2*sin(phi)/(sqrt(3)*(3 - sin(phi))) dF_dsigmam = -3*alphaf sigmar = cauchy_inicial[1-1][1-1] sigmaz = cauchy_inicial[2-1][2-1] trz = cauchy_inicial[2-1][1-1] sigmatheta = cauchy_inicial[3-1][3-1] dSigmar = delta_cauchy[1-1][1-1] dSigmaz = delta_cauchy[2-1][2-1] dTrz = delta_cauchy[2-1][1-1] dSigmatheta = delta_cauchy[3-1][3-1] sigmam = (sigmar + sigmaz +sigmatheta)/3 sr = sigmar - sigmam stheta = sigmatheta - sigmam sz = sigmaz - sigmam raizJ = sqrt(1/2*(sr**2 + stheta**2 + sz**2) + trz**2) dF_dJ2 = 1/(2*raizJ) # According to my definition of D m0 = 1/(9*sigmam)*np.array([[1,1,0,1], [1,1,0,1], [0,0,0,0], [1,1,0,1]]) m1 = np.array([[2/3,-1/3,0,-1/3], [-1/3,2/3,0,-1/3],

Page 260: Desarrollo de un laboratorio virtual de geotecnia enfocado

240 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

[0, 0, 2, 0], [-1/3,-1/3,0,2/3]]) vector_Sigma = np.array([[sigmar], [sigmaz], [trz], [sigmatheta]]) dF_dSigma = np.matmul((dF_dsigmam*m0 + dF_dJ2*m1), vector_Sigma) d_Sigma = np.array([[dSigmar], [dSigmaz], [dTrz], [dSigmatheta]]) criterio = np.dot(np.transpose(dF_dSigma), d_Sigma) # Potts if criterio > 0: # caso 1 alpha = 0 return alpha elif criterio < 0: 2 # caso 2 # Identificar un estado de esfuerzos dentro de la superficie de fluencia # aplicar iteración por Newton Raphson y encontrar alpha # Buscando ese estado de esfuerzos ambiguity_case2 = True lista_beta = np.arange(0.01, 0.99, 0.05) beta = lista_beta[0] dentro_de_la_sup_de_fluencia = False count = 0 while not dentro_de_la_sup_de_fluencia: f, msg = corroborate_yield_criterion( cauchy_inicial+lista_beta[count]*delta_cauchy, c, phi) if msg == "Respuesta elatica": # Ver cuaderno notas 12-12-2019 beta = lista_beta[count] dentro_de_la_sup_de_fluencia = True count+=1 cauchy_inicial = cauchy_inicial + beta*delta_cauchy delta_cauchy = delta_cauchy - beta*delta_cauchy # The next loop is based on a Newton-Raphson or secant iteration approach while delta_alpha > alpha_tol: first,msg1 = corroborate_yield_criterion(cauchy_inicial+list_alpha[-1]*delta_cauchy, c, phi) second,msg2 = corroborate_yield_criterion(cauchy_inicial+list_alpha[-2]*delta_cauchy, c, phi) a = list_alpha[-1] - first/(first - second)*(list_alpha[-1]-list_alpha[-2]) list_alpha.append(a) delta_alpha = abs(list_alpha[-1] - list_alpha[-2]) if ambiguity_case2: new_alpha = beta + list_alpha[-1]*(1-beta) return new_alpha return list_alpha[-1]

Page 261: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 241

# alpha sirve para encontrar la fracción del incremento en la que el comportamiento# es elástico, para la parte elastoplástica se opta por integrar la trayectoria de# esfuerzos mediante el esquema de integración modificado de Euler con control# de la magnitud del error

def euler_integration_scheme(cauchy_inicial, delta_cauchy, delta_epsilon, c, phi, e, nu, slope_H, alpha, sstol = 1*10**-8): """ 'Substep algoritm' After the magnitude estimation of alpha, i.e. the size of the step that produces a elastic response, this function can integrate the strains to find the stress state (legal) according to those strains Args: cauchy_inicial: np.array, matrix delta_cauchy: np.array, matrix delta_epsilon: np. array, vector of incremental strains c: float, defines the material cohesion phi: float, defines the material friction angle e: float, Young's modulus slope_H: nu: float, Poisson's ratio sstol: float, substep tolerance alpha: float, fraction of the increment with elastic response Attributes: """ # i cauchy = cauchy_inicial + alpha*delta_cauchy sigma = np.array([[cauchy[1-1][1-1]], [cauchy[2-1][2-1]], [cauchy[2-1][1-1]], [cauchy[3-1][3-1]]]) delta_epsilon_s = (1-alpha)*delta_epsilon t = 0 delta_t = 1 beta = False while t < 1: # ii relativo = 1 while relativo > sstol: if beta != False: delta_t = beta*delta_t delta_epsilon_ss = delta_t*delta_epsilon_s # en este punto tengo que interpolar H con sigma matriz_D = e/((1 + nu)*(1 - 2*nu))*np.array( [[1-nu, nu, 0, nu],

Page 262: Desarrollo de un laboratorio virtual de geotecnia enfocado

242 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

[nu, 1-nu, 0, nu], [0, 0, 1/2 - nu, 0], [nu, nu, 0, 1-nu]]) # utilizar matriz elastoplástica pag 280 Potts matrix_DelasticPlastic = matrix_Dep.Matrix_Dep(matriz_D, slope_H, phi, cauchy) matriz_Dep1 = matrix_DelasticPlastic.matrix_Dep first_order_sigma = np.matmul(matriz_Dep1, delta_epsilon_ss) first_order_cauchy = np.array( [[first_order_sigma[1-1][1-1], first_order_sigma[3-1][1-1], 0], [first_order_sigma[3-1][1-1], first_order_sigma[2-1][1-1], 0], [0, 0, first_order_sigma[4-1][1-1]]]) # En Drucker y Prager k es constante matrix_DelasticPlastic2 = matrix_Dep.Matrix_Dep(matriz_D, slope_H, phi, cauchy + first_order_cauchy) matriz_Dep2 = matrix_DelasticPlastic2.matrix_Dep second_order_sigma = np.matmul(matriz_Dep2, delta_epsilon_ss) # Valor más preciso para el tensor de esfuerzos de Cauchy delta_sigma_euler = 1/2*(first_order_sigma + second_order_sigma) # Error local error_local = 1/2*(second_order_sigma - first_order_sigma) # Error relativo relativo = np.linalg.norm(error_local)/np.linalg.norm(sigma + delta_sigma_euler) beta = 0.8*sqrt(sstol/relativo)# print('BETA', beta) if beta < 0.1: beta = 0.1 if relativo < sstol: beta = False # corroborar que el nuevo estado de esfuerzos cumple con |F| < y_tol delta_cauchy_euler = np.array( [[delta_sigma_euler[1-1][1-1], delta_sigma_euler[3-1][1-1], 0], [delta_sigma_euler[3-1][1-1], delta_sigma_euler[2-1][1-1], 0], [0, 0, delta_sigma_euler[4-1][1-1]]]) ff, msgff = corroborate_yield_criterion(cauchy + delta_cauchy_euler, c, phi) if msgff == 'Fluencia' or msgff == 'Respuesta elastica': 1 # Correcto t = t + delta_t cauchy = cauchy + delta_cauchy_euler# if 1-t < delta_t:# delta_t = 1-t # para que el t total sea igual a 1 elif msgff == 'Estado ilegal de esfuerzos': 1 # Hay que disminuir el delta_t o los valores de y_tol y sstol raise ValueError('Estado ilegal de esfuerzos /n', 'Hay que disminuir el delta_t o los valores de y_tol y sstol') return "Hay que disminuir el delta_t o los valores de y_tol y sstol"

Page 263: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 243

return delta_cauchy_euler

global_force_vector.py"""This module stores global matrix classes.""" #JOscar

import numpy as npfrom math import sqrt, atan, cos, sin

import element_force_vectorimport store_in_txtimport inv_coord

class Global_force_vector(object): """Makes a global stiffness matrix.

Args: write here the arguments

Attributes: """ def __init__(self, total_nodes, problem_type): self.id = 1 self.problem_type = problem_type self.dict_element_matrices = {} if self.problem_type == 'field_problem': self.vector_F = np.zeros((total_nodes, 1)) elif self.problem_type == 'consolidation': self.vector_F = np.zeros((2*total_nodes, 1)) self.vector_nG = np.zeros((total_nodes, 1)) self.esfuerzos_Y = [] self.esfuerzos_X = [] elif self.problem_type == 'large_displacements': self.vector_F = np.zeros((2*total_nodes, 1)) self.esfuerzos_Y = [] self.esfuerzos_X = [] def __hash__(self): """Returns the item's id as its hash.""" return self.id def invert_coordinates(self, element): inv_coord.Inv_coord(element) def set_element_force_vectors(self, element, total_unit_weight, fluid_unit_weight = 9.81, unbalanced_force = None):

Page 264: Desarrollo de un laboratorio virtual de geotecnia enfocado

244 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.element_force_vectors = element_force_vector.Element_force_vector( element, total_unit_weight, problem_type = self.problem_type) self.dict_element_matrices[element.id] = self.element_force_vectors if self.problem_type == 'field_problem': 1 # Pending elif self.problem_type == 'consolidation': self.element_force_vectors.set_body_force_vector( element, total_unit_weight, fluid_unit_weight) elif self.problem_type == 'large_displacements': self.element_force_vectors.set_body_force_vector( element, total_unit_weight, unbalanced_force = unbalanced_force) def set_ijk(self, element): return self.element_force_vectors.counterclockwise_format(element) def write_ijk_in_vector_F(self, vector_fe, i, j, k, vector_ne = None, l = None, m = None, n = None): if self.problem_type == 'field_problem': 1 # Pending elif self.problem_type == 'consolidation': self.vector_F[2*i-2] = self.vector_F[2*i-2] + vector_fe[1-1] self.vector_F[2*i-1] = self.vector_F[2*i-1] + vector_fe[2-1] self.vector_F[2*j-2] = self.vector_F[2*j-2] + vector_fe[3-1] self.vector_F[2*j-1] = self.vector_F[2*j-1] + vector_fe[4-1] self.vector_F[2*k-2] = self.vector_F[2*k-2] + vector_fe[5-1] self.vector_F[2*k-1] = self.vector_F[2*k-1] + vector_fe[6-1] self.vector_nG[i-1] = self.vector_nG[i-1] + vector_ne[1-1] self.vector_nG[j-1] = self.vector_nG[j-1] + vector_ne[2-1] self.vector_nG[k-1] = self.vector_nG[k-1] + vector_ne[3-1] return self.vector_F, self.vector_nG elif self.problem_type == 'large_displacements': self.vector_F[2*i-2] = self.vector_F[2*i-2] + vector_fe[1-1] self.vector_F[2*i-1] = self.vector_F[2*i-1] + vector_fe[2-1] self.vector_F[2*j-2] = self.vector_F[2*j-2] + vector_fe[3-1] self.vector_F[2*j-1] = self.vector_F[2*j-1] + vector_fe[4-1] self.vector_F[2*k-2] = self.vector_F[2*k-2] + vector_fe[5-1] self.vector_F[2*k-1] = self.vector_F[2*k-1] + vector_fe[6-1] self.vector_F[2*l-2] = self.vector_F[2*l-2] + vector_fe[7-1] self.vector_F[2*l-1] = self.vector_F[2*l-1] + vector_fe[8-1] self.vector_F[2*m-2] = self.vector_F[2*m-2] + vector_fe[9-1]

Page 265: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 245

self.vector_F[2*m-1] = self.vector_F[2*m-1] + vector_fe[10-1] self.vector_F[2*n-2] = self.vector_F[2*n-2] + vector_fe[11-1] self.vector_F[2*n-1] = self.vector_F[2*n-1] + vector_fe[12-1] return self.vector_F def writing_loop(self, model, kx, ky, total_unit_weight, fluid_unit_weight = 9.81, unbalanced_force = None): """Builds the temporal global matrices""" # In order to obtain the nodes with stress boundary condition self.get_boundary_conditions(model) if unbalanced_force != None: for elemento in model.elements: if self.problem_type == 'large_displacements': self.set_element_force_vectors(elemento, total_unit_weight, unbalanced_force = unbalanced_force)

self.invert_coordinates(elemento) if elemento.ccxtype in ['CPS6', 'CAX6', 'CPE6']: nodei, nodej, nodek, nodel, nodem, noden= self.set_ijk(elemento) i = nodei.id j = nodej.id k = nodek.id l = nodel.id m = nodem.id n = noden.id self.invert_coordinates(elemento) vector_fe = self.element_force_vectors.body_force_vector vector_ne = None self.vector_F = self.write_ijk_in_vector_F(vector_fe, i, j, k,vector_ne, l, m, n) return self.vector_F else: for elemento in model.elements: # Here the element vectors are written if self.problem_type == 'field_problem': 1 # Pending elif self.problem_type == 'consolidation': self.set_element_force_vectors(elemento, total_unit_weight, fluid_unit_weight = fluid_unit_weight) elif self.problem_type == 'large_displacements': self.set_element_force_vectors(elemento, total_unit_weight) self.invert_coordinates(elemento) if elemento.ccxtype in ['CPS3', 'CAX3', 'CPE3']: nodei, nodej, nodek = self.set_ijk(elemento) i = nodei.id

Page 266: Desarrollo de un laboratorio virtual de geotecnia enfocado

246 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

j = nodej.id k = nodek.id elif elemento.ccxtype in ['CPS6', 'CAX6', 'CPE6']: nodei, nodej, nodek, nodel, nodem, noden= self.set_ijk(elemento) i = nodei.id j = nodej.id k = nodek.id l = nodel.id m = nodem.id n = noden.id self.invert_coordinates(elemento) # Making modifications in order to include the boundary stresses # stresses in x direction # contar hace que los pares de nodos ij, jk o ki seleccionados correspondan # a la misma carga if self.problem_type == 'field_problem': 1 # Pending elif self.problem_type == 'consolidation': # stresses in x direction for dicc in self.esfuerzos_X: if nodei.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_X: if nodej.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodei, nodej, direc, val, 'ij') if nodej.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_X: if nodek.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodej, nodek, direc, val, 'jk') if nodek.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_X: if nodei.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodek, nodei, direc, val, 'ki') # stresses in y direction for dicc in self.esfuerzos_Y: if nodei.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_Y: if nodej.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector(

Page 267: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 247

nodei, nodej, direc, val, 'ij') if nodej.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_Y: if nodek.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodej, nodek, direc, val, 'jk') if nodek.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_Y: if nodei.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodek, nodei, direc, val, 'ki') vector_fe = self.element_force_vectors.body_force_vector vector_ne = self.element_force_vectors.set_vector_n(elemento, kx, ky) # writing process self.vector_F, self.vector_nG = self.write_ijk_in_vector_F( vector_fe, i, j, k, vector_ne)# print('self.vector_nG', self.vector_nG)# print('FG \n', self.vector_F) elif self.problem_type == 'large_displacements': # stresses in x direction for dicc in self.esfuerzos_X: if nodei.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_X: if nodek.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodei, nodek, direc, val, 'ik', nodeintermedio = nodej) if nodek.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_X: if nodem.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodek, nodem, direc, val, 'km', nodeintermedio = nodel) if nodem.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_X: if nodei.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val']

Page 268: Desarrollo de un laboratorio virtual de geotecnia enfocado

248 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.element_force_vectors.agreg_surf_force_vector( nodem, nodei, direc, val, 'mi', nodeintermedio = noden) # stresses in y direction for dicc in self.esfuerzos_Y: if nodei.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_Y: if nodek.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodei, nodek, direc, val, 'ik', nodeintermedio = nodej) if nodek.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_Y: if nodem.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodek, nodem, direc, val, 'km', nodeintermedio = nodel) if nodem.id == dicc['node'].id: c = dicc['cont'] for dicc2 in self.esfuerzos_Y: if nodei.id == dicc2['node'].id and c == dicc2['cont']: direc, val = dicc2['dir'], dicc2['val'] self.element_force_vectors.agreg_surf_force_vector( nodem, nodei, direc, val, 'mi', nodeintermedio = noden) vector_fe = self.element_force_vectors.body_force_vector vector_ne = None self.vector_F = self.write_ijk_in_vector_F(vector_fe, i, j, k,vector_ne, l, m, n) if self.problem_type == 'consolidation': return self.vector_F, self.vector_nG else: return self.vector_F

def store_matrix_in_txt(self, matrix, nombre): store_in_txt.Store(matrix, nombre) def get_boundary_conditions(self, model): # store all node and element components self.presiones = {} for time in model.loads: for load in model.loads[time]: if load.ltype in ['press']: for signlinea in load.comp.items:# print('Vect_perpen: ', signlinea.line.get_perp_vec()) long_v_perp = 1/(sqrt(

Page 269: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 249

(signlinea.line.get_perp_vec().y)**2 + (signlinea.line.get_perp_vec().x)**2)) v_unit = long_v_perp*np.array( [[signlinea.line.get_perp_vec().y, signlinea.line.get_perp_vec().x]]) self.presiones[signlinea] = {'ltype': load.ltype, 'val': load.val, 'nodes': [], 'vect_perp': v_unit} for face in load.comp.get_children(): # Cuando se buscan los #nodos en los que actúa una presión, children() devuelve la cara #del elemento(s) en donde actúa esa presión for node in face.nodes: if node not in self.presiones[signlinea]['nodes']: self.presiones[signlinea]['nodes'].append(node) # print('\n', 'presiones: ',self.presiones) contar = 0 for line in self.presiones.keys(): contar = contar + 1 if self.presiones[line]['vect_perp'][ 0, 0] == 0 and self.presiones[line]['vect_perp'][0, 1] == -1: #print('Carga positiva en y') for node in self.presiones[line]['nodes']: # Guardar nodos en un vector self.esfuerzos_Y.append({'node': node, 'dir': 'y', 'val': self.presiones[line]['val'], 'cont': contar}) elif self.presiones[line]['vect_perp'][ 0, 0] == 0 and self.presiones[line]['vect_perp'][0, 1] == 1: #print('Carga negativa en y') for node in self.presiones[line]['nodes']: self.esfuerzos_Y.append({'node': node, 'dir': '-y', 'val': self.presiones[line]['val'], 'cont': contar}) elif self.presiones[line]['vect_perp'][ 0, 0] == -1 and self.presiones[line]['vect_perp'][0, 1] == 0: #print('Carga positiva en x') for node in self.presiones[line]['nodes']: self.esfuerzos_X.append({'node': node, 'dir': 'x', 'val': self.presiones[line]['val'], 'cont': contar}) elif self.presiones[line]['vect_perp'][ 0, 0] == 1 and self.presiones[line]['vect_perp'][0, 1] == 0: #print('Carga negativa en x') for node in self.presiones[line]['nodes']: self.esfuerzos_X.append({'node': node, 'dir': '-x', 'val': self.presiones[line]['val'], 'cont': contar}) else:

Page 270: Desarrollo de un laboratorio virtual de geotecnia enfocado

250 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# para esfuerzos inclinados # Trabajar con tangente theta = atan(self.presiones[line]['vect_perp'][0, 1]/ self.presiones[line]['vect_perp'][0, 0]) # definiendo la dirección y sentido de aplicación de la carga if self.presiones[line]['vect_perp'][0, 0] > 0 and self.presiones[line]['val'] > 0: x = '-x' elif self.presiones[line]['vect_perp'][0, 0] < 0 and self.presiones[line]['val'] > 0: x = 'x' elif self.presiones[line]['vect_perp'][0, 0] > 0 and self.presiones[line]['val'] < 0: x = 'x'

elif self.presiones[line]['vect_perp'][0, 0] < 0 and self.presiones[line]['val'] < 0: x = '-x' if self.presiones[line]['vect_perp'][0, 1] > 0 and self.presiones[line]['val'] > 0: y = '-y' elif self.presiones[line]['vect_perp'][0, 1] < 0 and self.presiones[line]['val'] > 0: y = 'y' elif self.presiones[line]['vect_perp'][0, 1] > 0 and self.presiones[line]['val'] < 0: y = 'y' elif self.presiones[line]['vect_perp'][0, 1] < 0 and self.presiones[line]['val'] < 0: y = '-y' #print('theta', theta) self.esfuerzos_X.append({'node': node, 'dir': x, 'val': self.presiones[line]['val']*cos(theta), 'cont': contar}) self.esfuerzos_Y.append({'node': node, 'dir': y, 'val': self.presiones[line]['val']*sin(theta), 'cont': contar}) # poner en un vector ordenado delta Ru# print('x', self.esfuerzos_X, '\n', 'y', self.esfuerzos_Y)

global_stiffness_matrix.py"""This module stores global matrix classes.""" #JOscar

import numpy as npimport element_matricesimport store_in_txtimport inv_coordfrom copy import deepcopy

np.set_printoptions(precision=3)

class Global_matrix(object): """Makes a global stiffness matrix.

Page 271: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 251

Args: write here the arguments total_nodes = total number of nodes in the model self. problem_type - problem_type(string): kind of problem, value 'field_problem' the equation to solve is Dx(d2u/dx2) + Dy(d2u/dy2) + Gu + Q = 0 Value 'consolidation' try to solve the consolidation system FEA equations Attributes: write here the used attributes in this module self.matrix_K = global stiffness matrix """ def __init__(self, total_nodes, problem_type): self.id = 1 self.problem_type = problem_type self.dict_element_matrices = {} if self.problem_type == 'field_problem': self.matrix_K = np.zeros((total_nodes, total_nodes)) elif self.problem_type == 'consolidation': self.matrix_K = np.zeros((2*total_nodes, 2*total_nodes)) self.matrix_L = np.zeros((2*total_nodes, total_nodes)) self.matrix_PHI = np.zeros((total_nodes, total_nodes)) elif self.problem_type == 'large_displacements': self.matrix_K = np.zeros((2*total_nodes, 2*total_nodes)) def __hash__(self): """Returns the item's id as its hash.""" return self.id def set_element_matrices(self, element, Dx = None, Dy = None, nu = None, kx = None, ky = None, fluid_unit_weight = None, e = None, _resp = None, H = None, phi = None, c = None): self.element_matrices = element_matrices.Element_matrices( element, problem_type = self.problem_type) self.dict_element_matrices[element.id] = self.element_matrices if self.problem_type == 'field_problem': return self.element_matrices.set_matrix_k(element, Dx = Dx, Dy = Dy) elif self.problem_type == 'consolidation': return self.element_matrices.set_matrix_k(element, nu = nu, e = e),\ self.element_matrices.set_matrix_l(element),\ self.element_matrices.set_matrix_phi(element, kx = kx, ky = ky, fluid_unit_weight = fluid_unit_weight) elif self.problem_type == 'large_displacements': return self.element_matrices.set_matrix_k(element, nu = nu, e = e,

Page 272: Desarrollo de un laboratorio virtual de geotecnia enfocado

252 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

_resp = _resp, H = H, phi = phi) def set_ijk(self, element): return self.element_matrices.counterclockwise_format(element) def invert_coordinates(self, element): inv_coord.Inv_coord(element) def write_ijk_in_matrix_K(self, element_matrix_k0, i, j, k, l = None, m = None, n = None): element_matrix_k = deepcopy(element_matrix_k0) if self.problem_type == 'field_problem': self.matrix_K[i-1][i-1] = self.matrix_K[i-1][i-1] + element_matrix_k[1-1][1-1] self.matrix_K[i-1][j-1] = self.matrix_K[i-1][j-1] + element_matrix_k[1-1][2-1] self.matrix_K[i-1][k-1] = self.matrix_K[i-1][k-1] + element_matrix_k[1-1][3-1] self.matrix_K[j-1][i-1] = self.matrix_K[j-1][i-1] + element_matrix_k[2-1][1-1] self.matrix_K[j-1][j-1] = self.matrix_K[j-1][j-1] + element_matrix_k[2-1][2-1] self.matrix_K[j-1][k-1] = self.matrix_K[j-1][k-1] + element_matrix_k[2-1][3-1] self.matrix_K[k-1][i-1] = self.matrix_K[k-1][i-1] + element_matrix_k[3-1][1-1] self.matrix_K[k-1][j-1] = self.matrix_K[k-1][j-1] + element_matrix_k[3-1][2-1] self.matrix_K[k-1][k-1] = self.matrix_K[k-1][k-1] + element_matrix_k[3-1][3-1] return self.matrix_K elif self.problem_type == 'consolidation': #i self.matrix_K[2*i-2][2*i-2] = self.matrix_K[2*i-2][2*i-2] + element_matrix_k[1-1][1-1] self.matrix_K[2*i-2][2*i-1] = self.matrix_K[2*i-2][2*i-1] + element_matrix_k[1-1][2-1] self.matrix_K[2*i-2][2*j-2] = self.matrix_K[2*i-2][2*j-2] + element_matrix_k[1-1][3-1] self.matrix_K[2*i-2][2*j-1] = self.matrix_K[2*i-2][2*j-1] + element_matrix_k[1-1][4-1] self.matrix_K[2*i-2][2*k-2] = self.matrix_K[2*i-2][2*k-2] + element_matrix_k[1-1][5-1] self.matrix_K[2*i-2][2*k-1] = self.matrix_K[2*i-2][2*k-1] + element_matrix_k[1-1][6-1] self.matrix_K[2*i-1][2*i-2] = self.matrix_K[2*i-1][2*i-2] + element_matrix_k[2-1][1-1] self.matrix_K[2*i-1][2*i-1] = self.matrix_K[2*i-1][2*i-1] + element_matrix_k[2-1][2-1] self.matrix_K[2*i-1][2*j-2] = self.matrix_K[2*i-1][2*j-2] + element_matrix_k[2-1][3-1] self.matrix_K[2*i-1][2*j-1] = self.matrix_K[2*i-1][2*j-1] + element_matrix_k[2-1][4-1] self.matrix_K[2*i-1][2*k-2] = self.matrix_K[2*i-1][2*k-2] + element_matrix_k[2-1][5-1] self.matrix_K[2*i-1][2*k-1] = self.matrix_K[2*i-1][2*k-1] + element_matrix_k[2-1][6-1]

Page 273: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 253

#j self.matrix_K[2*j-2][2*i-2] = self.matrix_K[2*j-2][2*i-2] + element_matrix_k[3-1][1-1] self.matrix_K[2*j-2][2*i-1] = self.matrix_K[2*j-2][2*i-1] + element_matrix_k[3-1][2-1] self.matrix_K[2*j-2][2*j-2] = self.matrix_K[2*j-2][2*j-2] + element_matrix_k[3-1][3-1] self.matrix_K[2*j-2][2*j-1] = self.matrix_K[2*j-2][2*j-1] + element_matrix_k[3-1][4-1] self.matrix_K[2*j-2][2*k-2] = self.matrix_K[2*j-2][2*k-2] + element_matrix_k[3-1][5-1] self.matrix_K[2*j-2][2*k-1] = self.matrix_K[2*j-2][2*k-1] + element_matrix_k[3-1][6-1] self.matrix_K[2*j-1][2*i-2] = self.matrix_K[2*j-1][2*i-2] + element_matrix_k[4-1][1-1] self.matrix_K[2*j-1][2*i-1] = self.matrix_K[2*j-1][2*i-1] + element_matrix_k[4-1][2-1] self.matrix_K[2*j-1][2*j-2] = self.matrix_K[2*j-1][2*j-2] + element_matrix_k[4-1][3-1] self.matrix_K[2*j-1][2*j-1] = self.matrix_K[2*j-1][2*j-1] + element_matrix_k[4-1][4-1] self.matrix_K[2*j-1][2*k-2] = self.matrix_K[2*j-1][2*k-2] + element_matrix_k[4-1][5-1] self.matrix_K[2*j-1][2*k-1] = self.matrix_K[2*j-1][2*k-1] + element_matrix_k[4-1][6-1] #k self.matrix_K[2*k-2][2*i-2] = self.matrix_K[2*k-2][2*i-2] + element_matrix_k[5-1][1-1] self.matrix_K[2*k-2][2*i-1] = self.matrix_K[2*k-2][2*i-1] + element_matrix_k[5-1][2-1] self.matrix_K[2*k-2][2*j-2] = self.matrix_K[2*k-2][2*j-2] + element_matrix_k[5-1][3-1] self.matrix_K[2*k-2][2*j-1] = self.matrix_K[2*k-2][2*j-1] + element_matrix_k[5-1][4-1] self.matrix_K[2*k-2][2*k-2] = self.matrix_K[2*k-2][2*k-2] + element_matrix_k[5-1][5-1] self.matrix_K[2*k-2][2*k-1] = self.matrix_K[2*k-2][2*k-1] + element_matrix_k[5-1][6-1] self.matrix_K[2*k-1][2*i-2] = self.matrix_K[2*k-1][2*i-2] + element_matrix_k[6-1][1-1] self.matrix_K[2*k-1][2*i-1] = self.matrix_K[2*k-1][2*i-1] + element_matrix_k[6-1][2-1]

Page 274: Desarrollo de un laboratorio virtual de geotecnia enfocado

254 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.matrix_K[2*k-1][2*j-2] = self.matrix_K[2*k-1][2*j-2] + element_matrix_k[6-1][3-1] self.matrix_K[2*k-1][2*j-1] = self.matrix_K[2*k-1][2*j-1] + element_matrix_k[6-1][4-1] self.matrix_K[2*k-1][2*k-2] = self.matrix_K[2*k-1][2*k-2] + element_matrix_k[6-1][5-1] self.matrix_K[2*k-1][2*k-1] = self.matrix_K[2*k-1][2*k-1] + element_matrix_k[6-1][6-1] return self.matrix_K elif self.problem_type == 'large_displacements': #i self.matrix_K[2*i-2][2*i-2] = self.matrix_K[2*i-2][2*i-2] + element_matrix_k[1-1][1-1] self.matrix_K[2*i-2][2*i-1] = self.matrix_K[2*i-2][2*i-1] + element_matrix_k[1-1][2-1] self.matrix_K[2*i-2][2*j-2] = self.matrix_K[2*i-2][2*j-2] + element_matrix_k[1-1][3-1] self.matrix_K[2*i-2][2*j-1] = self.matrix_K[2*i-2][2*j-1] + element_matrix_k[1-1][4-1] self.matrix_K[2*i-2][2*k-2] = self.matrix_K[2*i-2][2*k-2] + element_matrix_k[1-1][5-1] self.matrix_K[2*i-2][2*k-1] = self.matrix_K[2*i-2][2*k-1] + element_matrix_k[1-1][6-1] self.matrix_K[2*i-2][2*l-2] = self.matrix_K[2*i-2][2*l-2] + element_matrix_k[1-1][7-1] self.matrix_K[2*i-2][2*l-1] = self.matrix_K[2*i-2][2*l-1] + element_matrix_k[1-1][8-1] self.matrix_K[2*i-2][2*m-2] = self.matrix_K[2*i-2][2*m-2] + element_matrix_k[1-1][9-1] self.matrix_K[2*i-2][2*m-1] = self.matrix_K[2*i-2][2*m-1] + element_matrix_k[1-1][10-1] self.matrix_K[2*i-2][2*n-2] = self.matrix_K[2*i-2][2*n-2] + element_matrix_k[1-1][11-1] self.matrix_K[2*i-2][2*n-1] = self.matrix_K[2*i-2][2*n-1] + element_matrix_k[1-1][12-1] self.matrix_K[2*i-1][2*i-2] = self.matrix_K[2*i-1][2*i-2] + element_matrix_k[2-1][1-1] self.matrix_K[2*i-1][2*i-1] = self.matrix_K[2*i-1][2*i-1] + element_matrix_k[2-1][2-1] self.matrix_K[2*i-1][2*j-2] = self.matrix_K[2*i-1][2*j-2] + element_matrix_k[2-1][3-1] self.matrix_K[2*i-1][2*j-1] = self.matrix_K[2*i-1][2*j-1] + element_matrix_k[2-1][4-1] self.matrix_K[2*i-1][2*k-2] = self.matrix_K[2*i-1][2*k-2] + element_matrix_k[2-1][5-1] self.matrix_K[2*i-1][2*k-1] = self.matrix_K[2*i-1][2*k-1] + element_matrix_k[2-1][6-1] self.matrix_K[2*i-1][2*l-2] = self.matrix_K[2*i-1][2*l-2] + element_matrix_k[2-1][7-1]

Page 275: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 255

self.matrix_K[2*i-1][2*l-1] = self.matrix_K[2*i-1][2*l-1] + element_matrix_k[2-1][8-1] self.matrix_K[2*i-1][2*m-2] = self.matrix_K[2*i-1][2*m-2] + element_matrix_k[2-1][9-1] self.matrix_K[2*i-1][2*m-1] = self.matrix_K[2*i-1][2*m-1] + element_matrix_k[2-1][10-1] self.matrix_K[2*i-1][2*n-2] = self.matrix_K[2*i-1][2*n-2] + element_matrix_k[2-1][11-1] self.matrix_K[2*i-1][2*n-1] = self.matrix_K[2*i-1][2*n-1] + element_matrix_k[2-1][12-1] #j self.matrix_K[2*j-2][2*i-2] = self.matrix_K[2*j-2][2*i-2] + element_matrix_k[3-1][1-1] self.matrix_K[2*j-2][2*i-1] = self.matrix_K[2*j-2][2*i-1] + element_matrix_k[3-1][2-1] self.matrix_K[2*j-2][2*j-2] = self.matrix_K[2*j-2][2*j-2] + element_matrix_k[3-1][3-1] self.matrix_K[2*j-2][2*j-1] = self.matrix_K[2*j-2][2*j-1] + element_matrix_k[3-1][4-1] self.matrix_K[2*j-2][2*k-2] = self.matrix_K[2*j-2][2*k-2] + element_matrix_k[3-1][5-1] self.matrix_K[2*j-2][2*k-1] = self.matrix_K[2*j-2][2*k-1] + element_matrix_k[3-1][6-1] self.matrix_K[2*j-2][2*l-2] = self.matrix_K[2*j-2][2*l-2] + element_matrix_k[3-1][7-1] self.matrix_K[2*j-2][2*l-1] = self.matrix_K[2*j-2][2*l-1] + element_matrix_k[3-1][8-1] self.matrix_K[2*j-2][2*m-2] = self.matrix_K[2*j-2][2*m-2] + element_matrix_k[3-1][9-1] self.matrix_K[2*j-2][2*m-1] = self.matrix_K[2*j-2][2*m-1] + element_matrix_k[3-1][10-1] self.matrix_K[2*j-2][2*n-2] = self.matrix_K[2*j-2][2*n-2] + element_matrix_k[3-1][11-1] self.matrix_K[2*j-2][2*n-1] = self.matrix_K[2*j-2][2*n-1] + element_matrix_k[3-1][12-1] self.matrix_K[2*j-1][2*i-2] = self.matrix_K[2*j-1][2*i-2] + element_matrix_k[4-1][1-1] self.matrix_K[2*j-1][2*i-1] = self.matrix_K[2*j-1][2*i-1] + element_matrix_k[4-1][2-1] self.matrix_K[2*j-1][2*j-2] = self.matrix_K[2*j-1][2*j-2] + element_matrix_k[4-1][3-1] self.matrix_K[2*j-1][2*j-1] = self.matrix_K[2*j-1][2*j-1] + element_matrix_k[4-1][4-1] self.matrix_K[2*j-1][2*k-2] = self.matrix_K[2*j-1][2*k-2] + element_matrix_k[4-1][5-1] self.matrix_K[2*j-1][2*k-1] = self.matrix_K[2*j-1][2*k-1] + element_matrix_k[4-1][6-1]

Page 276: Desarrollo de un laboratorio virtual de geotecnia enfocado

256 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.matrix_K[2*j-1][2*l-2] = self.matrix_K[2*j-1][2*l-2] + element_matrix_k[4-1][7-1] self.matrix_K[2*j-1][2*l-1] = self.matrix_K[2*j-1][2*l-1] + element_matrix_k[4-1][8-1] self.matrix_K[2*j-1][2*m-2] = self.matrix_K[2*j-1][2*m-2] + element_matrix_k[4-1][9-1] self.matrix_K[2*j-1][2*m-1] = self.matrix_K[2*j-1][2*m-1] + element_matrix_k[4-1][10-1] self.matrix_K[2*j-1][2*n-2] = self.matrix_K[2*j-1][2*n-2] + element_matrix_k[4-1][11-1] self.matrix_K[2*j-1][2*n-1] = self.matrix_K[2*j-1][2*n-1] + element_matrix_k[4-1][12-1] #k self.matrix_K[2*k-2][2*i-2] = self.matrix_K[2*k-2][2*i-2] + element_matrix_k[5-1][1-1] self.matrix_K[2*k-2][2*i-1] = self.matrix_K[2*k-2][2*i-1] + element_matrix_k[5-1][2-1] self.matrix_K[2*k-2][2*j-2] = self.matrix_K[2*k-2][2*j-2] + element_matrix_k[5-1][3-1] self.matrix_K[2*k-2][2*j-1] = self.matrix_K[2*k-2][2*j-1] + element_matrix_k[5-1][4-1] self.matrix_K[2*k-2][2*k-2] = self.matrix_K[2*k-2][2*k-2] + element_matrix_k[5-1][5-1] self.matrix_K[2*k-2][2*k-1] = self.matrix_K[2*k-2][2*k-1] + element_matrix_k[5-1][6-1] self.matrix_K[2*k-2][2*l-2] = self.matrix_K[2*k-2][2*l-2] + element_matrix_k[5-1][7-1] self.matrix_K[2*k-2][2*l-1] = self.matrix_K[2*k-2][2*l-1] + element_matrix_k[5-1][8-1] self.matrix_K[2*k-2][2*m-2] = self.matrix_K[2*k-2][2*m-2] + element_matrix_k[5-1][9-1] self.matrix_K[2*k-2][2*m-1] = self.matrix_K[2*k-2][2*m-1] + element_matrix_k[5-1][10-1] self.matrix_K[2*k-2][2*n-2] = self.matrix_K[2*k-2][2*n-2] + element_matrix_k[5-1][11-1] self.matrix_K[2*k-2][2*n-1] = self.matrix_K[2*k-2][2*n-1] + element_matrix_k[5-1][12-1] self.matrix_K[2*k-1][2*i-2] = self.matrix_K[2*k-1][2*i-2] + element_matrix_k[6-1][1-1] self.matrix_K[2*k-1][2*i-1] = self.matrix_K[2*k-1][2*i-1] + element_matrix_k[6-1][2-1]

Page 277: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 257

self.matrix_K[2*k-1][2*j-2] = self.matrix_K[2*k-1][2*j-2] + element_matrix_k[6-1][3-1] self.matrix_K[2*k-1][2*j-1] = self.matrix_K[2*k-1][2*j-1] + element_matrix_k[6-1][4-1] self.matrix_K[2*k-1][2*k-2] = self.matrix_K[2*k-1][2*k-2] + element_matrix_k[6-1][5-1] self.matrix_K[2*k-1][2*k-1] = self.matrix_K[2*k-1][2*k-1] + element_matrix_k[6-1][6-1] self.matrix_K[2*k-1][2*l-2] = self.matrix_K[2*k-1][2*l-2] + element_matrix_k[6-1][7-1] self.matrix_K[2*k-1][2*l-1] = self.matrix_K[2*k-1][2*l-1] + element_matrix_k[6-1][8-1] self.matrix_K[2*k-1][2*m-2] = self.matrix_K[2*k-1][2*m-2] + element_matrix_k[6-1][9-1] self.matrix_K[2*k-1][2*m-1] = self.matrix_K[2*k-1][2*m-1] + element_matrix_k[6-1][10-1] self.matrix_K[2*k-1][2*n-2] = self.matrix_K[2*k-1][2*n-2] + element_matrix_k[6-1][11-1] self.matrix_K[2*k-1][2*n-1] = self.matrix_K[2*k-1][2*n-1] + element_matrix_k[6-1][12-1] #l self.matrix_K[2*l-2][2*i-2] = self.matrix_K[2*l-2][2*i-2] + element_matrix_k[7-1][1-1] self.matrix_K[2*l-2][2*i-1] = self.matrix_K[2*l-2][2*i-1] + element_matrix_k[7-1][2-1] self.matrix_K[2*l-2][2*j-2] = self.matrix_K[2*l-2][2*j-2] + element_matrix_k[7-1][3-1] self.matrix_K[2*l-2][2*j-1] = self.matrix_K[2*l-2][2*j-1] + element_matrix_k[7-1][4-1] self.matrix_K[2*l-2][2*k-2] = self.matrix_K[2*l-2][2*k-2] + element_matrix_k[7-1][5-1] self.matrix_K[2*l-2][2*k-1] = self.matrix_K[2*l-2][2*k-1] + element_matrix_k[7-1][6-1] self.matrix_K[2*l-2][2*l-2] = self.matrix_K[2*l-2][2*l-2] + element_matrix_k[7-1][7-1] self.matrix_K[2*l-2][2*l-1] = self.matrix_K[2*l-2][2*l-1] + element_matrix_k[7-1][8-1] self.matrix_K[2*l-2][2*m-2] = self.matrix_K[2*l-2][2*m-2] + element_matrix_k[7-1][9-1] self.matrix_K[2*l-2][2*m-1] = self.matrix_K[2*l-2][2*m-1] + element_matrix_k[7-1][10-1] self.matrix_K[2*l-2][2*n-2] = self.matrix_K[2*l-2][2*n-2] + element_matrix_k[7-1][11-1]

Page 278: Desarrollo de un laboratorio virtual de geotecnia enfocado

258 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.matrix_K[2*l-2][2*n-1] = self.matrix_K[2*l-2][2*n-1] + element_matrix_k[7-1][12-1] self.matrix_K[2*l-1][2*i-2] = self.matrix_K[2*l-1][2*i-2] + element_matrix_k[8-1][1-1] self.matrix_K[2*l-1][2*i-1] = self.matrix_K[2*l-1][2*i-1] + element_matrix_k[8-1][2-1] self.matrix_K[2*l-1][2*j-2] = self.matrix_K[2*l-1][2*j-2] + element_matrix_k[8-1][3-1] self.matrix_K[2*l-1][2*j-1] = self.matrix_K[2*l-1][2*j-1] + element_matrix_k[8-1][4-1] self.matrix_K[2*l-1][2*k-2] = self.matrix_K[2*l-1][2*k-2] + element_matrix_k[8-1][5-1] self.matrix_K[2*l-1][2*k-1] = self.matrix_K[2*l-1][2*k-1] + element_matrix_k[8-1][6-1] self.matrix_K[2*l-1][2*l-2] = self.matrix_K[2*l-1][2*l-2] + element_matrix_k[8-1][7-1] self.matrix_K[2*l-1][2*l-1] = self.matrix_K[2*l-1][2*l-1] + element_matrix_k[8-1][8-1] self.matrix_K[2*l-1][2*m-2] = self.matrix_K[2*l-1][2*m-2] + element_matrix_k[8-1][9-1] self.matrix_K[2*l-1][2*m-1] = self.matrix_K[2*l-1][2*m-1] + element_matrix_k[8-1][10-1] self.matrix_K[2*l-1][2*n-2] = self.matrix_K[2*l-1][2*n-2] + element_matrix_k[8-1][11-1] self.matrix_K[2*l-1][2*n-1] = self.matrix_K[2*l-1][2*n-1] + element_matrix_k[8-1][12-1] #m self.matrix_K[2*m-2][2*i-2] = self.matrix_K[2*m-2][2*i-2] + element_matrix_k[9-1][1-1] self.matrix_K[2*m-2][2*i-1] = self.matrix_K[2*m-2][2*i-1] + element_matrix_k[9-1][2-1] self.matrix_K[2*m-2][2*j-2] = self.matrix_K[2*m-2][2*j-2] + element_matrix_k[9-1][3-1] self.matrix_K[2*m-2][2*j-1] = self.matrix_K[2*m-2][2*j-1] + element_matrix_k[9-1][4-1] self.matrix_K[2*m-2][2*k-2] = self.matrix_K[2*m-2][2*k-2] + element_matrix_k[9-1][5-1] self.matrix_K[2*m-2][2*k-1] = self.matrix_K[2*m-2][2*k-1] + element_matrix_k[9-1][6-1] self.matrix_K[2*m-2][2*l-2] = self.matrix_K[2*m-2][2*l-2] + element_matrix_k[9-1][7-1] self.matrix_K[2*m-2][2*l-1] = self.matrix_K[2*m-2][2*l-1] + element_matrix_k[9-1][8-1]

Page 279: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 259

self.matrix_K[2*m-2][2*m-2] = self.matrix_K[2*m-2][2*m-2] + element_matrix_k[9-1][9-1] self.matrix_K[2*m-2][2*m-1] = self.matrix_K[2*m-2][2*m-1] + element_matrix_k[9-1][10-1] self.matrix_K[2*m-2][2*n-2] = self.matrix_K[2*m-2][2*n-2] + element_matrix_k[9-1][11-1] self.matrix_K[2*m-2][2*n-1] = self.matrix_K[2*m-2][2*n-1] + element_matrix_k[9-1][12-1] self.matrix_K[2*m-1][2*i-2] = self.matrix_K[2*m-1][2*i-2] + element_matrix_k[10-1][1-1] self.matrix_K[2*m-1][2*i-1] = self.matrix_K[2*m-1][2*i-1] + element_matrix_k[10-1][2-1] self.matrix_K[2*m-1][2*j-2] = self.matrix_K[2*m-1][2*j-2] + element_matrix_k[10-1][3-1] self.matrix_K[2*m-1][2*j-1] = self.matrix_K[2*m-1][2*j-1] + element_matrix_k[10-1][4-1] self.matrix_K[2*m-1][2*k-2] = self.matrix_K[2*m-1][2*k-2] + element_matrix_k[10-1][5-1] self.matrix_K[2*m-1][2*k-1] = self.matrix_K[2*m-1][2*k-1] + element_matrix_k[10-1][6-1] self.matrix_K[2*m-1][2*l-2] = self.matrix_K[2*m-1][2*l-2] + element_matrix_k[10-1][7-1] self.matrix_K[2*m-1][2*l-1] = self.matrix_K[2*m-1][2*l-1] + element_matrix_k[10-1][8-1] self.matrix_K[2*m-1][2*m-2] = self.matrix_K[2*m-1][2*m-2] + element_matrix_k[10-1][9-1] self.matrix_K[2*m-1][2*m-1] = self.matrix_K[2*m-1][2*m-1] + element_matrix_k[10-1][10-1] self.matrix_K[2*m-1][2*n-2] = self.matrix_K[2*m-1][2*n-2] + element_matrix_k[10-1][11-1] self.matrix_K[2*m-1][2*n-1] = self.matrix_K[2*m-1][2*n-1] + element_matrix_k[10-1][12-1] #n self.matrix_K[2*n-2][2*i-2] = self.matrix_K[2*n-2][2*i-2] + element_matrix_k[11-1][1-1] self.matrix_K[2*n-2][2*i-1] = self.matrix_K[2*n-2][2*i-1] + element_matrix_k[11-1][2-1] self.matrix_K[2*n-2][2*j-2] = self.matrix_K[2*n-2][2*j-2] + element_matrix_k[11-1][3-1]

Page 280: Desarrollo de un laboratorio virtual de geotecnia enfocado

260 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.matrix_K[2*n-2][2*j-1] = self.matrix_K[2*n-2][2*j-1] + element_matrix_k[11-1][4-1] self.matrix_K[2*n-2][2*k-2] = self.matrix_K[2*n-2][2*k-2] + element_matrix_k[11-1][5-1] self.matrix_K[2*n-2][2*k-1] = self.matrix_K[2*n-2][2*k-1] + element_matrix_k[11-1][6-1] self.matrix_K[2*n-2][2*l-2] = self.matrix_K[2*n-2][2*l-2] + element_matrix_k[11-1][7-1] self.matrix_K[2*n-2][2*l-1] = self.matrix_K[2*n-2][2*l-1] + element_matrix_k[11-1][8-1] self.matrix_K[2*n-2][2*m-2] = self.matrix_K[2*n-2][2*m-2] + element_matrix_k[11-1][9-1] self.matrix_K[2*n-2][2*m-1] = self.matrix_K[2*n-2][2*m-1] + element_matrix_k[11-1][10-1] self.matrix_K[2*n-2][2*n-2] = self.matrix_K[2*n-2][2*n-2] + element_matrix_k[11-1][11-1] self.matrix_K[2*n-2][2*n-1] = self.matrix_K[2*n-2][2*n-1] + element_matrix_k[11-1][12-1] self.matrix_K[2*n-1][2*i-2] = self.matrix_K[2*n-1][2*i-2] + element_matrix_k[12-1][1-1] self.matrix_K[2*n-1][2*i-1] = self.matrix_K[2*n-1][2*i-1] + element_matrix_k[12-1][2-1] self.matrix_K[2*n-1][2*j-2] = self.matrix_K[2*n-1][2*j-2] + element_matrix_k[12-1][3-1] self.matrix_K[2*n-1][2*j-1] = self.matrix_K[2*n-1][2*j-1] + element_matrix_k[12-1][4-1] self.matrix_K[2*n-1][2*k-2] = self.matrix_K[2*n-1][2*k-2] + element_matrix_k[12-1][5-1] self.matrix_K[2*n-1][2*k-1] = self.matrix_K[2*n-1][2*k-1] + element_matrix_k[12-1][6-1] self.matrix_K[2*n-1][2*l-2] = self.matrix_K[2*n-1][2*l-2] + element_matrix_k[12-1][7-1] self.matrix_K[2*n-1][2*l-1] = self.matrix_K[2*n-1][2*l-1] + element_matrix_k[12-1][8-1] self.matrix_K[2*n-1][2*m-2] = self.matrix_K[2*n-1][2*m-2] + element_matrix_k[12-1][9-1] self.matrix_K[2*n-1][2*m-1] = self.matrix_K[2*n-1][2*m-1] + element_matrix_k[12-1][10-1]

Page 281: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 261

self.matrix_K[2*n-1][2*n-2] = self.matrix_K[2*n-1][2*n-2] + element_matrix_k[12-1][11-1] self.matrix_K[2*n-1][2*n-1] = self.matrix_K[2*n-1][2*n-1] + element_matrix_k[12-1][12-1] return self.matrix_K def write_ijk_in_matrix_PHI(self, matrix_phi0, i, j, k): matrix_phi = deepcopy(matrix_phi0) self.matrix_PHI[i-1][i-1] = self.matrix_PHI[i-1][i-1] + matrix_phi[1-1][1-1] self.matrix_PHI[i-1][j-1] = self.matrix_PHI[i-1][j-1] + matrix_phi[1-1][2-1] self.matrix_PHI[i-1][k-1] = self.matrix_PHI[i-1][k-1] + matrix_phi[1-1][3-1] self.matrix_PHI[j-1][i-1] = self.matrix_PHI[j-1][i-1] + matrix_phi[2-1][1-1] self.matrix_PHI[j-1][j-1] = self.matrix_PHI[j-1][j-1] + matrix_phi[2-1][2-1] self.matrix_PHI[j-1][k-1] = self.matrix_PHI[j-1][k-1] + matrix_phi[2-1][3-1] self.matrix_PHI[k-1][i-1] = self.matrix_PHI[k-1][i-1] + matrix_phi[3-1][1-1] self.matrix_PHI[k-1][j-1] = self.matrix_PHI[k-1][j-1] + matrix_phi[3-1][2-1] self.matrix_PHI[k-1][k-1] = self.matrix_PHI[k-1][k-1] + matrix_phi[3-1][3-1] return self.matrix_PHI def write_ijk_in_matrix_L(self,matrix_le0, i, j, k): matrix_le = deepcopy(matrix_le0) self.matrix_L[2*i-2][i-1] = self.matrix_L[2*i-2][i-1] + matrix_le[1-1][1-1] self.matrix_L[2*i-2][j-1] = self.matrix_L[2*i-2][j-1] + matrix_le[1-1][2-1] self.matrix_L[2*i-2][k-1] = self.matrix_L[2*i-2][k-1] + matrix_le[1-1][3-1] self.matrix_L[2*i-1][i-1] = self.matrix_L[2*i-1][i-1] + matrix_le[2-1][1-1] self.matrix_L[2*i-1][j-1] = self.matrix_L[2*i-1][j-1] + matrix_le[2-1][2-1] self.matrix_L[2*i-1][k-1] = self.matrix_L[2*i-1][k-1] + matrix_le[2-1][3-1] self.matrix_L[2*j-2][i-1] = self.matrix_L[2*j-2][i-1] + matrix_le[3-1][1-1] self.matrix_L[2*j-2][j-1] = self.matrix_L[2*j-2][j-1] + matrix_le[3-1][2-1] self.matrix_L[2*j-2][k-1] = self.matrix_L[2*j-2][k-1] + matrix_le[3-1][3-1] self.matrix_L[2*j-1][i-1] = self.matrix_L[2*j-1][i-1] + matrix_le[4-1][1-1] self.matrix_L[2*j-1][j-1] = self.matrix_L[2*j-1][j-1] + matrix_le[4-1][2-1] self.matrix_L[2*j-1][k-1] = self.matrix_L[2*j-1][k-1] + matrix_le[4-1][3-1] self.matrix_L[2*k-2][i-1] = self.matrix_L[2*k-2][i-1] + matrix_le[5-1][1-1] self.matrix_L[2*k-2][j-1] = self.matrix_L[2*k-2][j-1] + matrix_le[5-1][2-1] self.matrix_L[2*k-2][k-1] = self.matrix_L[2*k-2][k-1] + matrix_le[5-1][3-1] self.matrix_L[2*k-1][i-1] = self.matrix_L[2*k-1][i-1] + matrix_le[6-1][1-1] self.matrix_L[2*k-1][j-1] = self.matrix_L[2*k-1][j-1] + matrix_le[6-1][2-1] self.matrix_L[2*k-1][k-1] = self.matrix_L[2*k-1][k-1] + matrix_le[6-1][3-1]

Page 282: Desarrollo de un laboratorio virtual de geotecnia enfocado

262 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

return self.matrix_L def writing_loop(self, model, Dx = None, Dy = None, nu = None, kx = None, ky = None, fluid_unit_weight = None, e = None, nonlinear = False, _resp = None, H = None, phi = None, c = None): """Builds the temporal global matrices"""

for elemento in model.elements: # Here the element matrices are written if self.problem_type == 'field_problem': matrix_ke = self.set_element_matrices( elemento, Dx = Dx, Dy = Dy, nu = nu, kx = kx, ky = ky, fluid_unit_weight = fluid_unit_weight) elif self.problem_type == 'consolidation': matrix_ke, matrix_le, matrix_phi = self.set_element_matrices( elemento, Dx = Dx, Dy = Dy, nu = nu, kx = kx, ky = ky, fluid_unit_weight = fluid_unit_weight, e = e) elif self.problem_type == 'large_displacements': matrix_ke = self.set_element_matrices( elemento, nu = nu, e = e, _resp = _resp, H = H, phi = phi, c = c) if nonlinear != False: matrix_kl = self.element_matrices.matrix_kL matrix_ksigm = self.element_matrices.matrix_ksigma # In nonlinear analysis use the tangential stiffness matrix, Zeevaert page 88 """ACÁ PONER EL CONDICIONAL PARA HACER ANÁLISIS CONSIDERANDO DEFORMACIONES INFINITESIMALES Es decir, Kl y ksigma serían cero""" condicionalDeDeformacionesInfinitesimales = True if condicionalDeDeformacionesInfinitesimales: matrix_kl = matrix_kl - matrix_kl matrix_ksigm = matrix_ksigm - matrix_ksigm matrix_ke = matrix_ke + matrix_kl + matrix_ksigm

# Every time the ijk format are needed is neccesary to invert them self.invert_coordinates(elemento) if elemento.ccxtype in ['CPS3', 'CAX3', 'CPE3']: nodei, nodej, nodek = self.set_ijk(elemento) i = nodei.id j = nodej.id k = nodek.id self.invert_coordinates(elemento) elif elemento.ccxtype in ['CPS6', 'CAX6', 'CPE6']: nodei, nodej, nodek, nodel, nodem, noden = self.set_ijk(elemento) i = nodei.id j = nodej.id k = nodek.id l = nodel.id m = nodem.id

Page 283: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 263

n = noden.id self.invert_coordinates(elemento) # Writing process if self.problem_type in ['field_problem', 'consolidation']: self.matrix_K = self.write_ijk_in_matrix_K(matrix_ke, i, j, k) elif self.problem_type in ['large_displacements']: self.matrix_K = self.write_ijk_in_matrix_K(matrix_ke, i, j, k, l, m, n) if self.problem_type == 'consolidation': self.matrix_PHI = self.write_ijk_in_matrix_PHI(matrix_phi, i, j, k) self.matrix_L = self.write_ijk_in_matrix_L(matrix_le, i, j, k)

return self.matrix_K # def store_matrix_in_txt(self, matrix, nombre):# store_in_txt.Store(matrix, nombre)# # def set_general_matrix(self, model):# """Builds the general matrix for the consolidation coupled problem"""# # horizontal = np.append(self.matrix_K, self.matrix_L, axis = 1)# vertical = np.append(np.transpose(self.matrix_L), self.matrix_PHI, axis = 1)# self.general_matrix = np.append(horizontal, vertical, axis = 0)# #print('det_mat_gen', np.linalg.det(self.general_matrix))# # self.store_matrix_in_txt(self.general_matrix, 'matrix_general')# # return self.general_matrix

h_variation.py# -*- coding: utf-8 -*-"""Created on Wed Jan 29 10:29:33 2020

@author: JOscar"""

import numpy as np

class clase_variacion_de_H(): """Esta clase está escrita con el esfuerzo de ingresar dentro del algoritmo la variación de la pendiente de la curva esfuerzo deformación en el rango de deformaciones elastoplásticas""" 1 def __init__(self, listH, listSigma): self.listH = listH self.listSigma = listSigma # Hay que comprobar que los vectores estén organizados

Page 284: Desarrollo de un laboratorio virtual de geotecnia enfocado

264 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# listH de forma creciente # listSigma de forma decreciente # deben tener el mismo tamaño self.listH.sort(reverse = True) # De mayor a menor self.listSigma.sort() # De menor a mayor if len(self.listH) != len(self.listSigma): raise ValueError('La cantidad de datos para H y Sigma debe ser la misma') def setH(self, sigmaPromedio): H = np.interp(abs(sigmaPromedio), self.listSigma, self.listH) return H

integration_points.py"""This module especifies the integration points""" #JOscar

class Integration_points(): """ Args: write here the arguments

Attributes: write here the used attributes in this module """ def __init__(self): self.integration_points = self.set_points_of_integration() def set_points_of_integration(self): """Sets the sampling points and weighting coefficients for triangular regions (7 points of integration)""" alpha = 0.0597159 beta = 0.470142 gamma = 0.101287 delta = 0.797427 # puntos a = {'l1' : 1/3, 'l2' : 1/3, 'w' : 0.11250, 'id': 1} b = {'l1' : alpha, 'l2' : beta, 'w' : 0.0661971, 'id': 2} c = {'l1' : beta, 'l2' : beta, 'w' : 0.0661971, 'id': 3} d = {'l1' : beta, 'l2' : alpha, 'w' : 0.0661971, 'id': 4} e = {'l1' : gamma, 'l2' : gamma, 'w' : 0.0629696, 'id': 5} f = {'l1' : delta, 'l2' : gamma, 'w' : 0.0629696, 'id': 6} g = {'l1' : gamma, 'l2' : delta, 'w' : 0.0629696, 'id': 7} points = {'a': a, 'b': b, 'c': c, 'd': d, 'e': e, 'f': f, 'g': g}

Page 285: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 265

return points

inv_coord.py"""This module recieves x and y in a alternate form from pycalculixand changes it's values""" #JOscar

class Inv_coord(): """ Args: write here the arguments

Attributes: write here the used attributes in this module

""" def __init__(self, element): self.invert_coordinates(element) def invert_coordinates(self, element): for node in element.nodes: # Recieves x and y in a alternate form from pycalculix #print(node.id, node.x, node.y) temp = node.x node.x = node.y node.y = temp

jacobiano.py"""This module builds the jacobian matrix between natural an global coordinatesystems""" #JOscar

import ccw_formatimport numpy as np

class Jacobiano(): """ Args: write here the arguments element(mesh.element) Attributes: write here the used attributes in this module """

Page 286: Desarrollo de un laboratorio virtual de geotecnia enfocado

266 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

def __init__(self, element, l1 = None, l2 = None): if l1 != None and l2 != None: self.l1 = l1 self.l2 = l2 else: self.l1 = None self.l2 = None self.matrix_J = self.set_J(element)

def set_J(self, element): if element.ccxtype in ['CPS3', 'CAX3', 'CPE3']: formato = ccw_format.Ccw(element) nodei = formato.nodei nodej = formato.nodej nodek = formato.nodek #print('nodei, nodej, nodek: ade', nodei, nodej, nodek) return np.array([[nodei.x - nodek.x, nodei.y - nodek.y], [nodej.x - nodek.x, nodej.y - nodek.y]])

elif element.ccxtype in ['CPS6', 'CAX6', 'CPE6']: formato = ccw_format.Ccw(element) node1 = formato.nodei node2 = formato.nodej node3 = formato.nodek node4 = formato.nodel node5 = formato.nodem node6 = formato.noden dx_dL1 = 1*((4*self.l1 - 1)*node1.x + 4*self.l2*node2.x - 4*self.l2*node4.x + (4*(self.l1 + self.l2) - 3)*node5.x + 4*(1 - 2*self.l1 - self.l2)*node6.x) dy_dL1 = 1*((4*self.l1 - 1)*node1.y + 4*self.l2*node2.y - 4*self.l2*node4.y + (4*(self.l1 + self.l2) - 3)*node5.y + 4*(1 - 2*self.l1 - self.l2)*node6.y) dx_dL2 = 1*(4*self.l1*node2.x + (4*self.l2 - 1)*node3.x + 4*(1 - self.l1 - 2*self.l2)*node4.x + (4*(self.l1 + self.l2) - 3)*node5.x - 4*self.l1*node6.x) dy_dL2 = 1*(4*self.l1*node2.y +

Page 287: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 267

(4*self.l2 - 1)*node3.y + 4*(1 - self.l1 - 2*self.l2)*node4.y + (4*(self.l1 + self.l2) - 3)*node5.y - 4*self.l1*node6.y) return np.array([[dx_dL1, dy_dL1], [dx_dL2, dy_dL2]])

matrix_Dep.py# -*- coding: utf-8 -*-"""Created on Thu Oct 24 10:53:48 2019

@author: JOscar"""

import numpy as npfrom math import sin, sqrt

import h_variation

class Matrix_Dep(): def __init__(self, matrix_D, slope_H, phi, cauchy): """ Builds the elastic-plastic matrix for the i step in the nonlinear analysis using updated lagrangean procedure, and axi-symmetrical case is used an associative flow rule too Args: matrix_D(np.array): elastic strain-strain constitutive matrix slope_H: slope of the uniaxial stress plastic strain curve defined in page 132 Zeevaert 1980 Attributes: self.matrix_Dep(np.array): elastic-plastic constitutive matrix Self.par_A(float): plasticity parameter """ self.par_A = self.set_parameter_A(slope_H, phi, cauchy) self.dF_dSigma = self.set_dF_dsigma(cauchy) primera = np.matmul(matrix_D, self.dF_dSigma) segunda = np.matmul(np.transpose(self.dF_dSigma), matrix_D) denom_a = np.matmul(matrix_D, self.dF_dSigma) denom = np.matmul(np.transpose(self.dF_dSigma), denom_a) self.matrix_Dep = matrix_D - 1/(self.par_A + denom)*np.matmul(primera, segunda)# print('self.matrix_Dep', self.matrix_Dep) def set_parameter_A(self, slope_H, phi, cauchy): """Args: slope_H(float): slope sigma vs plastic strains phi(float): friction angle, measured in radians """

Page 288: Desarrollo de un laboratorio virtual de geotecnia enfocado

268 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

sigmar = cauchy[1-1][1-1] sigmaz = cauchy[2-1][2-1] sigmatheta = cauchy[3-1][3-1] sigmam = (sigmar + sigmaz +sigmatheta)/3 self.alpha = 2*sin(phi)/(sqrt(3)*(3 - sin(phi))) try: par_A = slope_H*(self.alpha + 1/sqrt(3))**2 except: instancia_h_variation = h_variation.clase_variacion_de_H(slope_H[0], slope_H[1]) H_interpolado = instancia_h_variation.setH(sigmam) par_A = H_interpolado*(self.alpha + 1/sqrt(3))**2

return par_A def set_dF_dsigma(self, cauchy): dF_dsigmam = 3*self.alpha sigmar = cauchy[1-1][1-1] sigmaz = cauchy[2-1][2-1] trz = cauchy[2-1][1-1] sigmatheta = cauchy[3-1][3-1]

sigmam = (sigmar + sigmaz +sigmatheta)/3 sr = sigmar - sigmam stheta = sigmatheta - sigmam sz = sigmaz - sigmam raizJ = sqrt(1/2*(sr**2 + stheta**2 + sz**2) + trz**2) dF_dJ2 = 1/(2*raizJ) # According to my definition of D m0 = 1/(9*sigmam)*np.array([[1,1,0,1], [1,1,0,1], [0,0,0,0], [1,1,0,1]]) m1 = np.array([[2/3,-1/3,0,-1/3], [-1/3,2/3,0,-1/3], [0,0,2,0], [-1/3,-1/3,0,2/3]]) vector_Sigma = np.array([[sigmar], [sigmaz], [trz], [sigmatheta]]) dF_dSigma = np.matmul((dF_dsigmam*m0 + dF_dJ2*m1), vector_Sigma) return dF_dSigma

modified_matrix.py"""This module modifies the global stiffness matrices, the modification is done acording to the boundary conditions.""" #JOscar

import numpy as npimport copy as copiaimport mathimport store_in_txt

Page 289: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 269

class Modified_matrix(): """ Args: write here the arguments model(feamodel): feamodel to solve matrix_K(array): global stiffness matrix related with all the displacements, includes the kij elements of prescribed displacements

Attributes: write here the used attributes in this module self.numero_de_nodos(int) self.load_dict(dict) self.presiones(dict) : pressure or stress boundary conditions self.desplazamientos_X(dict): prescribed displacements in x direction self.desplazamientos_Y(dict): prescribed displacements in y direction self.pore_press(dict): presscribed pore pressure self.degrees_freedom_d(list): list of degrees of freedom with no prescribed displacement addressing its ubication in the ku matrix self.degrees_freedom_p(list): list of degrees of freedom with no prescribed pore pressure addressing its ubication in the phiu matrix self.degrees_freedom_dp(list): list of degrees of freedom with prescribed displacement addressing its ubication in the kupT and kp matrices self.degrees_freedom_pp(list): list of degrees of freedom with prescribed pore pressure addressing its ubication in the Lp and phip matrices self.modif_matrix_K(array): Ku corresponding to: [[Ku, Kup], [KupT, Kp]]T*{delta du, delta dp}T = {delta Ru, delta Rp}

self.delta_dp(np.array): prescribed displacements in the same order to self. """ def __init__(self, model): self.numero_de_nodos = len(model.nodes) self.load_dict = model.loads self.presiones = {} # También conocidas como esfuerzos en la frontera self.desplazamientos_X = {} self.desplazamientos_Y = {} self.pore_press = {} self.degrees_freedom_d = [] self.degrees_freedom_p = [] self.degrees_freedom_dp = [] self.degrees_freedom_pp = [] self.esfuerzos_X = [] self.esfuerzos_Y = [] def get_boundary_conditions(self, model): # store all node and element components # uy horizontal

Page 290: Desarrollo de un laboratorio virtual de geotecnia enfocado

270 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# ux vertical count = 0 for time in model.loads: for load in model.loads[time]: if load.ltype in ['press']: count = count + 1 for signlinea in load.comp.items: long_v_perp = 1/(math.sqrt( (signlinea.line.get_perp_vec().y)**2 + (signlinea.line.get_perp_vec().x)**2)) v_unit = long_v_perp*np.array( [[signlinea.line.get_perp_vec().y, signlinea.line.get_perp_vec().x]]) # If rigid the displacement below that load is tied self.presiones[signlinea] = {'ltype': load.ltype, 'val': load.val, 'nodes': [], 'vect_perp': v_unit, 'count': count, 'rigid': load.rigid, 'id': count}

for face in load.comp.get_children(): # Cuando se buscan los #nodos en los que actúa una presión, children() devuelve la cara #del elemento(s) en donde actúa esa presión for node in face.nodes: if node not in self.presiones[signlinea]['nodes']: self.presiones[signlinea]['nodes'].append(node) elif load.ltype in ['ux']:

for node in load.comp.get_children(): # Cuando se buscan los nodos con #desplazamientos preestablecidos, children() devuelve los nodos #en donde se dan esos desplazamientos self.desplazamientos_X[node.id] = {'ltype': load.ltype, 'val': load.val} elif load.ltype in ['uy']: for node in load.comp.get_children(): # Cuando se buscan los nodos con #desplazamientos preestablecidos, children() devuelve los nodos #en donde se dan esos desplazamientos self.desplazamientos_Y[node.id] = {'ltype': load.ltype, 'val': load.val} elif load.ltype in ['fluid_press']: for node in load.comp.get_children(): # Cuando se buscan los nodos con #desplazamientos preestablecidos, children() devuelve los nodos #en donde se dan esos desplazamientos self.pore_press[node.id] = {'ltype': load.ltype, 'val': load.val}

def put_prescribed_displacement(self, matrix_K): """Registers the ubication of the degrees of freedom in the global stiffness matrix K, and modifies it according to prescried displacements""" local_matrix_Ku = copia.deepcopy(matrix_K)

Page 291: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 271

self.lista_a_borrar_d = [] self.delta_dp = [] # Having into account the prescribed displacements vect_de_loc_temp = np.arange(1, self.numero_de_nodos + 1, 1) # writes the ubication of the degrees of freedom to the matrix K # in self.degrees_freedom_d for node in vect_de_loc_temp: self.degrees_freedom_d.append({node: 'uy'}) self.degrees_freedom_d.append({node: 'ux'}) # stores the original list self.degrees_freedom_d in another list to # modify the matrix K direcciones = copia.deepcopy(self.degrees_freedom_d) # Elimina los grados de libertad con desplazamientos prescritos de # self.degrees_freedom_d for node in self.desplazamientos_Y: #print(node) tipo = self.desplazamientos_Y[node] #print(tipo) if tipo['ltype'] == 'uy': dicc = {node: tipo['ltype']} #print(dicc) if dicc in self.degrees_freedom_d: #print(dicc) indice_a_borrar = direcciones.index(dicc) self.lista_a_borrar_d.append(indice_a_borrar) self.degrees_freedom_d.remove(dicc) self.delta_dp.append(tipo['val']) for node in self.desplazamientos_X: #print(node) tipo = self.desplazamientos_X[node] #print(tipo) if tipo['ltype'] == 'ux': dicc = {node: tipo['ltype']} #print(dicc) if dicc in self.degrees_freedom_d: #print(dicc) indice_a_borrar = direcciones.index(dicc) self.lista_a_borrar_d.append(indice_a_borrar) self.degrees_freedom_d.remove(dicc) self.delta_dp.append(tipo['val']) # Storing the order of the prescribed degrees of freedom (displacements) for index in self.lista_a_borrar_d: self.degrees_freedom_dp.append(direcciones[index])

Page 292: Desarrollo de un laboratorio virtual de geotecnia enfocado

272 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.delta_dp = np.reshape(self.delta_dp, (len(self.delta_dp), 1))

# remove the specified rows (0 index) and columns (1 index) local_matrix_Ku = np.delete(local_matrix_Ku, self.lista_a_borrar_d, 0) local_matrix_Ku = np.delete(local_matrix_Ku, self.lista_a_borrar_d, 1) self.matrix_Ku = local_matrix_Ku # store the ith file (row) corresponding to the prescribed displacement # in the ith degree of freedom grados_delta_dp = self.lista_a_borrar_d

for i, linea in enumerate(grados_delta_dp, 0): if i == 0: kupT_0 = np.zeros((1, len(matrix_K[linea]))) kupT_0[0] = copia.deepcopy(matrix_K[linea])

else: kupT_0_temp = np.zeros((1, len(matrix_K[linea]))) kupT_0_temp[0] = copia.deepcopy(matrix_K[linea]) kupT_0 = np.append(kupT_0, kupT_0_temp, 0) # write the matrix_KupT self.kupT = np.delete(kupT_0, self.lista_a_borrar_d, 1) # build the kp matrix self.kp = np.zeros((len(grados_delta_dp), len(grados_delta_dp))) for i, linea in enumerate(grados_delta_dp, 0): for j, columna in enumerate(grados_delta_dp, 0): self.kp[i, j] = kupT_0[i, columna] def put_prescribed_pore_pressure(self, matrix_PHI): """Registers the ubication of the degrees of freedom in the global stiffness matrix PHI, and modifies it according to prescried pore pressures""" local_matrix_PHIu = copia.deepcopy(matrix_PHI) self.lista_a_borrar_p = [] self.delta_pp = [] # Having into account the prescribed pore pressures vect_de_loc_temp = np.arange(1, self.numero_de_nodos + 1, 1) # writes the ubication of the degrees of freedom to the matrix PHI # in self.degrees_freedom_p for node in vect_de_loc_temp: self.degrees_freedom_p.append({node: 'fluid_press'}) # stores the original list self.degrees_freedom_p in another list to # modify the matrix PHI direcciones = copia.deepcopy(self.degrees_freedom_p)

Page 293: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 273

# Elimina los grados de libertad con presiones prescritas de # self.degrees_freedom_p for node in self.pore_press: tipo = self.pore_press[node] # tipo is a dict if tipo['ltype'] == 'fluid_press': dicc = {node: tipo['ltype']} if dicc in self.degrees_freedom_p: indice_a_borrar = direcciones.index(dicc) self.lista_a_borrar_p.append(indice_a_borrar) # self.degrees_freedom_p contiene el orden en el que # dan los resultados de los grados de libertad self.degrees_freedom_p.remove(dicc) self.delta_pp.append(tipo['val']) # Storing the order of the prescribed degrees of freedom (pore pressure) for index in self.lista_a_borrar_p: self.degrees_freedom_pp.append(direcciones[index])

self.delta_pp = np.reshape(self.delta_pp, (len(self.delta_pp), 1))# print('lista a borrar p: ', self.lista_a_borrar_p)# print('grados p: ', self.degrees_freedom_p) # remove the specified rows (0 index) and columns (1 index) local_matrix_PHIu = np.delete(local_matrix_PHIu, self.lista_a_borrar_p, 0) local_matrix_PHIu = np.delete(local_matrix_PHIu, self.lista_a_borrar_p, 1) self.matrix_PHIu = local_matrix_PHIu # store the ith file (row) corresponding to the prescribed pore pressure # in the ith degree of freedom grados_delta_pp = self.lista_a_borrar_p for i, linea in enumerate(grados_delta_pp, 0): if i == 0: phiupT_0 = np.zeros((1, len(matrix_PHI[linea]))) phiupT_0[0] = copia.deepcopy(matrix_PHI[linea]) else: phiupT_0_temp = np.zeros((1, len(matrix_PHI[linea]))) phiupT_0_temp[0] = copia.deepcopy(matrix_PHI[linea]) phiupT_0 = np.append(phiupT_0, phiupT_0_temp, 0) # np.reshape(phiupT_0, (len(grados_delta_pp), len(matrix_PHI[linea]))) #print('phiupT_0', phiupT_0) # write the local_matrix_phiupT self.phiupT = np.delete(phiupT_0, self.lista_a_borrar_p, 1) #print('phiupT', phiupT) # build the phip matrix

self.phip = np.zeros((len(grados_delta_pp), len(grados_delta_pp))) for i, linea in enumerate(grados_delta_pp, 0): for j, columna in enumerate(grados_delta_pp, 0):

Page 294: Desarrollo de un laboratorio virtual de geotecnia enfocado

274 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.phip[i, j] = phiupT_0[i, columna] def modif_matrix_L(self, matrix_L): """Recieves the ubication of the degrees of freedom in the global stiffness matrix PHI and matrix L, and modifies the matrix L according to prescried pore pressures and displacements""" local_matrix_Lu = copia.deepcopy(matrix_L) local_matrix_L_temp = copia.deepcopy(matrix_L) list_1, list_2 = self.lista_a_borrar_d, self.lista_a_borrar_p # remove the specified rows (0 index) and columns (1 index) local_matrix_Lu = np.delete(local_matrix_Lu, list_1, 0) local_matrix_Lu = np.delete(local_matrix_Lu, list_2, 1) self.matrix_Lu = local_matrix_Lu #print('Lu',local_matrix_Lu) # store the ith file (row) corresponding to the prescribed pore pressure # in the ith degree of freedom grados_delta_dp = self.lista_a_borrar_d grados_delta_pp = self.lista_a_borrar_p for i, linea in enumerate(grados_delta_dp, 0): if i == 0: lup2_0 = np.zeros((1, len(matrix_L[linea]))) lup2_0[0] = copia.deepcopy(matrix_L[linea]) else: lup2_0_temp = np.zeros((1, len(matrix_L[linea]))) lup2_0_temp[0] = copia.deepcopy(matrix_L[linea]) lup2_0 = np.append(lup2_0, lup2_0_temp, 0) # write the local_matrix_lupT self.lup2 = np.delete(lup2_0, self.lista_a_borrar_p, 1) #print('lupT', self.lupT) # build the lp matrix self.lp = np.zeros((len(grados_delta_dp), len(self.lista_a_borrar_p))) for i, linea in enumerate(grados_delta_dp, 0): for j, columna in enumerate(self.lista_a_borrar_p, 0): self.lp[i, j] = lup2_0[i, columna] self.lup1 = np.zeros((len(self.matrix_Lu), len(grados_delta_pp))) local_matrix_L_temp = np.delete(local_matrix_L_temp, list_1, 0) for i, linea in enumerate(local_matrix_L_temp, 0): for j, columna in enumerate(grados_delta_pp, 0): self.lup1[i, j] = linea[columna]

Page 295: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 275

def put_tied_degrees(self): """Recieves the tied degrees of freedom and modifies the K and L matrices""" direcciones = copia.deepcopy(self.degrees_freedom_d) rigidNumber = 1 # Finding the tied degrees of freedom for one load for signlinea in self.presiones.keys(): if self.presiones[signlinea]['rigid']: rigidNumber = rigidNumber + 1 lista_amarrados_y = [] lista_amarrados_x = [] self.presiones[signlinea]['uy'] = {} self.presiones[signlinea]['ux'] = {} for node in self.presiones[signlinea]['nodes']: if self.presiones[signlinea]['vect_perp'][0, 0] == 1 and self.presiones[signlinea]['vect_perp'][0, 1] == 0: lista_amarrados_y.append({node: 'uy'})

elif self.presiones[signlinea]['vect_perp'][0, 0] == 0 and self.presiones[signlinea]['vect_perp'][0, 1] == 1: lista_amarrados_x.append({node: 'ux'}) else: lista_amarrados_y.append({node: 'uy'}) lista_amarrados_x.append({node: 'ux'}) if self.presiones[signlinea]['vect_perp'][0, 0] == 1 and self.presiones[signlinea]['vect_perp'][0, 1] == 0: self.tied_X_or_Y(lista_amarrados_y, direcciones, signlinea, 'uy') #horizontal elif self.presiones[signlinea]['vect_perp'][0, 0] == 0 and self.presiones[signlinea]['vect_perp'][0, 1] == 1: self.tied_X_or_Y(lista_amarrados_x, direcciones, signlinea, 'ux') # vertical else: self.tied_X_or_Y(lista_amarrados_y, direcciones, signlinea, 'uy') self.tied_X_or_Y(lista_amarrados_x, direcciones, signlinea, 'ux') #print('self.presiones', self.presiones) # To find the diagonal term for each rigid load for signlinea1 in self.presiones.keys(): if self.presiones[signlinea1]['rigid']: for str_Code1 in ['uy', 'ux']: if self.presiones[signlinea1][str_Code1] != {}: vector = np.array([[]]) #print('self.presiones[signlinea1][str_Code1] \n', self.presiones[signlinea1][str_Code1]) for signlinea2 in self.presiones.keys(): if self.presiones[signlinea2]['rigid']: for str_Code2 in ['uy', 'ux']: if self.presiones[signlinea2][str_Code2] != {}: #print('self.presiones[signlinea2][str_Code2] \n', self.presiones[signlinea2][str_Code2]) indices = self.presiones[signlinea2][str_Code2]['list']

Page 296: Desarrollo de un laboratorio virtual de geotecnia enfocado

276 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

suma = np.array([np.sum(np.take( self.presiones[signlinea1][str_Code1]['tied_row_K'], indices, axis = 1), axis = 1)]) vector = np.append(vector, suma, axis = 1) self.presiones[signlinea1][str_Code1]['vector'] = copia.deepcopy(vector) # Removing the rows listas_a_borrar = []# self.presiones[signlinea][str_Code] Contiene los nodos amarrados en la carga signlinea for signlinea in self.presiones.keys(): if self.presiones[signlinea]['rigid']: for str_Code in ['uy', 'ux']: if self.presiones[signlinea][str_Code] != {}: listas_a_borrar += self.presiones[signlinea][str_Code]['list']

# Removing the influence of the other nodes for signlinea in self.presiones.keys(): if self.presiones[signlinea]['rigid']: for str_Code in ['uy', 'ux']: if self.presiones[signlinea][str_Code] != {}: self.presiones[signlinea][str_Code]['tied_row_K'] = np.delete( self.presiones[signlinea][str_Code]['tied_row_K'], listas_a_borrar, axis = 1)

#print('lista a borrar', listas_a_borrar) self.matrix_Ku = np.delete(self.matrix_Ku, listas_a_borrar, axis = 0) self.matrix_Ku = np.delete(self.matrix_Ku, listas_a_borrar, axis = 1) kup = np.delete(np.transpose(self.kupT), listas_a_borrar, axis = 0) self.kupT = np.transpose(kup) if self.degrees_freedom_pp == []: 1 else: self.matrix_Lu = np.delete(self.matrix_Lu, listas_a_borrar, axis = 0) self.lup1 = np.delete(self.lup1, listas_a_borrar, axis = 0) # Adding the new rows # In Ku abajo_Ku = np.zeros((1, len(self.matrix_Ku))) submatrix_Ku = np.zeros((1, rigidNumber-1))#self.presiones[signlinea][str_Code]['vector'] #print('submatrix_Ku', submatrix_Ku) for signlinea in self.presiones.keys(): if self.presiones[signlinea]['rigid']: for str_Code in ['uy', 'ux']: if self.presiones[signlinea][str_Code] != {}: abajo_Ku = np.append(abajo_Ku, self.presiones[signlinea][str_Code]['tied_row_K'],

Page 297: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 277

axis = 0) #print('submatrix_Ku', submatrix_Ku) submatrix_Ku = np.append(submatrix_Ku, self.presiones[signlinea][str_Code]['vector'], axis = 0) #print('abajo_Ku', abajo_Ku) abajo_Ku = np.delete(abajo_Ku, [0], axis = 0) submatrix_Ku = np.delete(submatrix_Ku, [0], axis = 0)

if listas_a_borrar != []: horizontal1 = np.append(self.matrix_Ku, np.transpose(abajo_Ku), axis = 1) horizontal2 = np.append(abajo_Ku, submatrix_Ku, axis = 1) self.matrix_Ku = np.append(horizontal1, horizontal2, axis = 0)

for signlinea in self.presiones.keys(): if self.presiones[signlinea]['rigid']: for str_Code in ['uy', 'ux']: if self.presiones[signlinea][str_Code] != {}: if self.degrees_freedom_pp == []: 1

else: self.matrix_Lu = np.append(self.matrix_Lu, self.presiones[signlinea] [str_Code]['tied_row_L'], axis = 0) self.lup1 = np.append(self.lup1, self.presiones[signlinea] [str_Code]['tied_row_Lup1'], axis = 0) self.kupT = np.append(self.kupT, self.presiones[signlinea] [str_Code]['tied_column_KupT'], axis = 1)

def tied_X_or_Y(self, lista_amarrados, direcciones, signlinea, str_Code): """finds the direction of the tied degrees of freedom""" # writing its locations lista_a_borrar = [] for amarrado in lista_amarrados: for node in amarrado.keys(): tipo = amarrado[node] dicc = {node.id: tipo} if dicc in self.degrees_freedom_d: indice_a_borrar = direcciones.index(dicc) lista_a_borrar.append(copia.deepcopy(indice_a_borrar)) self.degrees_freedom_d.remove(dicc) # Storing it self.presiones[signlinea][str_Code]['list'] = copia.deepcopy(lista_a_borrar) # location of the tied degree of freedom# self.degrees_freedom_d.append(self.presiones[signlinea][str_Code]) self.degrees_freedom_d.append({'carga': self.presiones[signlinea]['id']}) # writing its rows in a single one # for signlinea in self.presiones.keys():

Page 298: Desarrollo de un laboratorio virtual de geotecnia enfocado

278 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

if self.presiones[signlinea][str_Code] != {}: lista = self.presiones[signlinea][str_Code]['list'] local_submatrix_K = np.take(self.matrix_Ku, lista, axis = 0) reemplazo_K = np.array([np.sum(local_submatrix_K, axis = 0)]) # al reemplazo_K hay que hacerle lo mismo y sumar los que están cerca de la diagonal # principal, eliminar las columnas y agregrarlo debajo de Ku. Para # agragarlo a la derecha de ku se le debe agregar la suma de esos elementos # reemplazo_K sub_reemplazo_K = np.array([np.sum(np.take(reemplazo_K, lista, axis = 1), axis = 1)]) # el siguiente np.delete necesita ser eliminado e implementado con el de Ku #reemplazo_K = np.delete(reemplazo_K, lista, axis = 1) # Construcción del vector de las otras presiones o cargas con desplazamientos atados # Pending if self.degrees_freedom_pp == []: 1 else: local_submatrix_L = np.take(self.matrix_Lu, lista, axis = 0) reemplazo_L = np.array([np.sum(local_submatrix_L, axis = 0)]) local_submatrix_Lup1 = np.take(self.lup1, lista, axis = 0) reemplazo_Lup1 = np.array([np.sum(local_submatrix_Lup1, axis = 0)]) local_submatrix_Kup = np.take(np.transpose(self.kupT), lista, axis = 0) reemplazo_Kup = np.array([np.sum(local_submatrix_Kup, axis = 0)]) # local_delta_dp = np.take(self.delta_dp, lista, axis = 0)# reemplazo_delta_dp = np.array([np.sum(local_delta_dp, axis = 0)])# # local_delta_pp = np.take(self.delta_pp, lista, axis = 0)# reemplazo_delta_pp = np.array([np.sum(local_delta_pp, axis = 0 )]) self.presiones[signlinea][str_Code]['tied_row_K'] = copia.deepcopy(reemplazo_K) self.presiones[signlinea][str_Code]['tied_row_K_diag'] = copia.deepcopy(sub_reemplazo_K) self.presiones[signlinea][str_Code]['tied_column_KupT'] = copia.deepcopy( np.transpose(reemplazo_Kup)) if self.degrees_freedom_pp == []: 1 else: self.presiones[signlinea][str_Code]['tied_row_L'] = copia.deepcopy(reemplazo_L) self.presiones[signlinea][str_Code]['tied_row_Lup1'] = copia.deepcopy(reemplazo_Lup1)

Page 299: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 279

# self.presiones[signlinea][str_Code]['tied_row_dp'] = copia.deepcopy(reemplazo_delta_dp)# self.presiones[signlinea][str_Code]['tied_row_pp'] = copia.deepcopy(reemplazo_delta_pp) return def mod_general_matrix(self): """Builds the general matrix for the consolidation coupled problem""" horizontal = np.append(self.matrix_Ku, self.matrix_Lu, axis = 1) vertical = np.append(np.transpose(self.matrix_Lu), self.matrix_PHIu, axis = 1) self.modif_general_matrix = np.append(horizontal, vertical, axis = 0) # print('det_mat_gen', np.linalg.det(self.modif_general_matrix)) #store_in_txt.Store(self.modif_general_matrix, 'mod_matrix_general').store_matrix_in_txt return self.modif_general_matrix #def store_node_ubication_on_matrix(self):

modified_vector.py"""This module modifies the global force vector F, the modification is done acording to the boundary conditions.""" #JOscar

import numpy as npimport copy as copia

class Modified_vector(): """ Args: write here the arguments Attributes: write here the used attributes in this module

""" def __init__(self, vector_F, vector_nG, lista_1, lista_2): """ Modify the global force vector (vector_F) according to the prescribed displacements (lista_1) and the pore pressures force vector (vector_nG) according to the prescribed pore pressures (lista_2). """ self.modif_v_Fp = np.take(vector_F, lista_1) self.modif_v_nGp = np.take(vector_nG, lista_2) self.modif_v_F = np.delete(vector_F, lista_1, 0) self.modif_v_nG = np.delete(vector_nG, lista_2, 0)

Page 300: Desarrollo de un laboratorio virtual de geotecnia enfocado

280 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

return def put_tied_degrees(self, presiones): """Recieves the the presiones dictinary from modified_matrix.py and modifies the general force vector (displacements) according to the presses applied in rigid plates (i.e. tied degrees of freedom) args: presiones[dict] """ self._presiones = presiones # writing the 'tied' rows in a single one for signlinea in self._presiones.keys(): if self._presiones[signlinea]['rigid']: for str_Code in ['uy', 'ux']: if self._presiones[signlinea][str_Code] != {}: lista = self._presiones[signlinea][str_Code]['list'] local_subvector_F = np.take(self.modif_v_F, lista, axis = 0) reemplazo_modif_v_F = np.array([np.sum(local_subvector_F, axis = 0)]) self._presiones[signlinea][str_Code]['tied_row_F'] = copia.deepcopy( reemplazo_modif_v_F)

# Removing the rows listas_a_borrar = [] for signlinea in self._presiones.keys(): if self._presiones[signlinea]['rigid']: for str_Code in ['uy', 'ux']: if self._presiones[signlinea][str_Code] != {}: listas_a_borrar = listas_a_borrar + self._presiones[signlinea][str_Code]['list'] if listas_a_borrar != []: self.modif_v_F = np.delete(self.modif_v_F, listas_a_borrar, axis = 0)

# Adding the new rows for signlinea in self._presiones.keys(): if self._presiones[signlinea]['rigid']: for str_Code in ['uy', 'ux']: if self._presiones[signlinea][str_Code] != {}: self.modif_v_F = np.append(self.modif_v_F, self._presiones[signlinea] [str_Code]['tied_row_F'], axis = 0) return

multiple_times.py"""This module run the coupled consolidation model from time t to time t+1""" #JOscar

import numpy as npimport matplotlib.pyplot as plt

Page 301: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 281

from scipy.interpolate import griddata

import solve_in_timeimport global_stiffness_matriximport modified_matriximport global_force_vectorimport modified_vectorimport calc_quantitiesimport plotfrom copy import deepcopy

class Multiple_times(): """ Args: makes the analysis of the coupled consolidation problem according to the time ppress_t0(int): Initial pore presurre in all nodes

Attributes: write here the used attributes in this module

self.model_2(feamodel): to modify the original coordinates of the nodes self.primero(bool): to solve the first incremental step in delta_t """ def __init__(self, model): self._model = model self.sistema = solve_in_time.Solve_time() self.results = {} self.results_acum = {} self.ppress_max_vector = [] self.tiempo_total = 0 # para realizar la curva de consolidación self.list_tiempo = [] self.list_desplazamiento = [] # para realizar la curva de disipación en el centro de la muestra self.listPresionEnElCentroDeLaMuestra = []

#self.delta_t = total_time/5 def run_multiple_times(self, ppress_t0, nu, kx, ky, total_unit_weight, fluid_unit_weight, e, load, delta_t = None, h = None): #

Page 302: Desarrollo de un laboratorio virtual de geotecnia enfocado

282 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.tiempo_total = self.tiempo_total + delta_t print('tiempo de carga', self.tiempo_total) i = 0 while i <= 0: print('i', i) self.preparate_matrices(nu, kx, ky, total_unit_weight, fluid_unit_weight, e) print('control')

# Ubicación de los grados de libertad en el sistema general de ecuaciones self._degrees_freedom_d = self.modified_M.degrees_freedom_d self._degrees_freedom_p = self.modified_M.degrees_freedom_p # construir vector de presiones de poros hidrostáticas ppress_t0 = np.zeros((len(self._degrees_freedom_p), 1))# print('ppress_t0', ppress_t0) for grado in self._degrees_freedom_p: for nombre in grado.keys(): for node in self._model.nodes: if nombre == node.id: direccion = self._degrees_freedom_p.index(grado) ppress_t0[direccion][1-1] = -0*fluid_unit_weight*(h-node.x) # print('ppress_t0', ppress_t0)# print('self.modified_M.degrees_freedom_d', self.modified_M.degrees_freedom_d) self.sistema.solve_Cconsolidation(ppress_t0, self.modified_M, self.modified_V, i, delta_t = delta_t) # Gráfica de la razón presión inters. en el centro de la muestra presión impuesta # vs criterio de discretización ΔT self.ppress_max_vector.append(self.sistema.ppres_max) self.strains_stresses = calc_quantities.Quantities(self._model, self._degrees_freedom_d, self._degrees_freedom_p) # Guardando las presiones de poros promedio calculadas self.presiones = self.sistema.ppress_prom # Modificando las coordenadas de los elementos resp = np.transpose(self.sistema.resp_out) # Guardando los resultados de presiones de poros correspondiente # a cada carga # ii implementado debido a problemas con el cálculo de esfuerzos # y deformaciones además de la modificación de las coordenadas en # self.modif_coordinates(resp, step) ii = len(resp[1])-1 self.modif_coordinates(resp, ii)

Page 303: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 283

# Calcular deformaciones y esfuerzos self.strains_stresses.element_strain_stress(self.modified_M, self.matriz_global, self.modified_M.presiones, resp, ii) # Organizar presines de poros self.strains_stresses.element_pore_pressure(self.modified_M, self.matriz_global, self.modified_M.presiones,resp, ii) # Con i se guarda el último resultado, ii guarda todos los resultados # del proceso de marchar en el tiempo self.results[i] = self.strains_stresses._results # 'plotting' plots the incremental results for all the steps plotting = plot.Plot(self._model, self.results, i)# plotting.eplot('Sy')# plotting.eplot('Sx')# plotting.eplot('Sz')# # plotting.eplot('ey')# plotting.eplot('ex')# plotting.eplot('ez')# # plotting.nplot('ux')# plotting.nplot('uy') # 'plotting_acum' plots the total results acumulated at final step resp_acum = self.sistema.res_acum self.strains_stresses_acum = calc_quantities.Quantities(self._model, self._degrees_freedom_d, self._degrees_freedom_p) self.strains_stresses_acum.element_strain_stress(self.modified_M, self.matriz_global, self.modified_M.presiones ,resp_acum, 0) self.strains_stresses_acum.element_pore_pressure(self.modified_M, self.matriz_global, self.modified_M.presiones, resp_acum, 0) self.results_acum[0] = self.strains_stresses_acum._results plotting_acum = plot.Plot(self._model, self.results_acum, 0)# para mejorar los tiempos# plotting_acum.nplot('ux')# plotting_acum.nplot('uy') plotting_acum.nplot('fluid_press') # plotting_acum.eplot('ex') i = i + 1 if h != None: centroDeLaMuestra = (0, (h-self.sistema.desplazamientoDelCabezal)/2) valorInterpoladoEnCentroDeLaMuestra = griddata(points=plotting_acum.puntos, values=plotting_acum.zvals,

Page 304: Desarrollo de un laboratorio virtual de geotecnia enfocado

284 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

xi=centroDeLaMuestra, method='cubic') print('valorInterpoladoEnCentroDeLaMuestra', valorInterpoladoEnCentroDeLaMuestra) self.listPresionEnElCentroDeLaMuestra.append(valorInterpoladoEnCentroDeLaMuestra)

# para realizar la curva de consolidación deformacion = self.sistema.desplazamientoDelCabezal/h*100 self.list_desplazamiento.append(deformacion) self.list_tiempo.append(self.tiempo_total) # plt.plot(self.list_tiempo, self.list_desplazamiento)# plt.ylabel('deformación (%)')# plt.xlabel('tiempo (s)')# plt.xscale('log')# plt.grid(True, which='both')# plt.show() def modif_coordinates(self, resp, step): for degree in self._degrees_freedom_d: #print('degree.keys', degree, degree.keys()) for node in self._model.nodes: if node.id in degree.keys(): if degree[node.id] in ['ux']: node.x = node.x + resp[self._degrees_freedom_d.index(degree), step] if degree[node.id] in ['uy']: node.y = node.y + resp[self._degrees_freedom_d.index(degree), step] presiones = self.modified_M.presiones for signlinea in presiones.keys(): if presiones[signlinea]['rigid']: for node in presiones[signlinea]['nodes']: if presiones[signlinea]['vect_perp'][0, 0] == 1 and presiones[signlinea]['vect_perp'][0, 1] == 0: node.y = node.y + resp[self._degrees_freedom_d.index({'carga': presiones[signlinea]['id']}), step] #print('hey carga horizontal') if presiones[signlinea]['vect_perp'][0, 0] == 0 and presiones[signlinea]['vect_perp'][0, 1] == 1: node.x = node.x + resp[self._degrees_freedom_d.index({'carga': presiones[signlinea]['id']}), step] #print('hey carga vertical') return

def preparate_matrices(self, nu, kx, ky, total_unit_weight, fluid_unit_weight, e): # Global matrices model = self._model self.matriz_global = global_stiffness_matrix.Global_matrix(len(model.nodes), problem_type = 'consolidation')

Page 305: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 285

self.matriz_global.writing_loop(model, nu=nu, kx=kx, ky=ky, fluid_unit_weight=fluid_unit_weight, e=e) #self.matriz_global.set_general_matrix(model) # Modified global matrices according to prescribed quantities self.modified_M = modified_matrix.Modified_matrix(model) self.modified_M.get_boundary_conditions(model) self.modified_M.put_prescribed_displacement(self.matriz_global.matrix_K) self.modified_M.put_prescribed_pore_pressure(self.matriz_global.matrix_PHI) self.modified_M.modif_matrix_L(self.matriz_global.matrix_L) # Modified global matrices according to tied degrees of freedom self.modified_M.put_tied_degrees()

#print(self.modified_M.load_dict) #self.modified_M.mod_general_matrix() lista_1 = self.modified_M.lista_a_borrar_d lista_2 = self.modified_M.lista_a_borrar_p # Global force vector vector_F = global_force_vector.Global_force_vector(len(model.nodes), problem_type = 'consolidation') v_F, v_nG = vector_F.writing_loop(model, kx, ky, total_unit_weight, fluid_unit_weight) # 16KN example unit weight # Modified global force vector self.modified_V = modified_vector.Modified_vector(v_F, v_nG, lista_1, lista_2) self.modified_V.put_tied_degrees(self.modified_M.presiones)

nonLinear_Problem.py# -*- coding: utf-8 -*-"""Created on Mon Nov 4 11:21:42 2019

@author: JOscar"""from numpy import arangeimport matplotlib.pyplot as pltfrom copy import deepcopy

import updated_lagrangean_analysisimport triaxial_interpretation as trximport modified_matrix

class nonLinearProblem(): def __init__(self, model, triaxial = True, dSigmaAxial = None, dSigmaLateral = None, altura = None): self._model = model

Page 306: Desarrollo de un laboratorio virtual de geotecnia enfocado

286 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

if triaxial: modified_M = modified_matrix.Modified_matrix(self._model) modified_M.get_boundary_conditions(self._model) self.presiones = modified_M.presiones self.triaxial_interpretation = trx.Triaxial_interpretation(self._model, altura, self.presiones) self.dSigmaAxial = dSigmaAxial self.dSigmaLateral = dSigmaLateral else: self.triaxial_interpretation = None def solve(self, nu, e, total_unit_weight, steps, H, phi, c): """ Args: total_load(float): The total load steps(int): the total steps to run the load Attributes: """ # Aquí puedo incluir la variación de la variable H (plasticity parameter) self.lagrangeanAnalysis = updated_lagrangean_analysis.uLagAnalysis(self._model) # Asumiendo que el primer incremento de carga es elástico entonces hago un paso de más np = arange(0, steps, 1) p = 0 q = 0 deltas = [] x = [] dato = 1 c = c/1.2 for i in np: print('i', i) self._model.plot_elements('' + 'elem', display = True, title = 'Elements', enum = False, nshow = False, nnum = True) flag = self.lagrangeanAnalysis.run_time(nu, e, total_unit_weight, steps, H = H, phi = phi, c = c)

if self.triaxial_interpretation == None: 1 else: p = p + 1/(3*steps)*(self.dSigmaAxial + 2*self.dSigmaLateral) # Necesito enviarle p, q q = q + 1/(steps)*(self.dSigmaAxial - self.dSigmaLateral) self.triaxial_interpretation.pq(p, q) delta_l = self.lagrangeanAnalysis.res_acum[-1] print('delta_l', delta_l)

Page 307: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 287

self.triaxial_interpretation.strains(delta_l) deltas.append(deepcopy(delta_l)) x.append(deepcopy(dato)) dato = dato + 1 print('flag', flag) if flag == "Disminuir incremento de carga": print('Aumentar número de pasos') return

plt.title('Incremento desplazamiento cabezal') plt.grid(True, which='both') plt.xlabel('N') plt.ylabel('delta') plt.plot(x, deltas, 'ko-') plt.show() if self.triaxial_interpretation != None: self.triaxial_interpretation.plot_results()

solve_in_time.py"""This module run the coupled consolidation model from time t to time t+1""" #JOscar

import numpy as npfrom copy import deepcopyfrom numpy import linalg as LAfrom scipy.sparse.linalg import spsolveimport matplotlib.pyplot as plt1

class Solve_time(): """ Args: write here the arguments

Attributes: write here the used attributes in this module ku(np.array): lu(np.array): phiu(np.array): ru(np.array): nu(np.array):

""" def __init__(self, model = None): # beta has to be >= 0.5 in order to ensure stability

Page 308: Desarrollo de un laboratorio virtual de geotecnia enfocado

288 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# of the marching process self.beta = 0.99 self.respuestas = [] self.primero = True self.tiempo = 0 if model != None: self._model = model # para validación mediante comparación con Teh Cee Ing, Nie Xiaoyan (2002) self.presionInicialMaxima = 0 self.list_th = [] self.list_grado_de_consolidacion = [] def solve_Cconsolidation(self, ppress_t0, mod_matrix, mod_vector, i, delta_t = None):

ku = mod_matrix.matrix_Ku lu = mod_matrix.matrix_Lu phiu = mod_matrix.matrix_PHIu

self.tiempo = self.tiempo + delta_t print('delta_t', delta_t, 'tiempo total', self.tiempo) # force vector ru = mod_vector.modif_v_F ruc = - np.matmul(np.transpose(mod_matrix.kupT), mod_matrix.delta_dp) -np.matmul( mod_matrix.lup1, mod_matrix.delta_pp) nu = mod_vector.modif_v_nG uuc = - np.matmul(np.transpose(mod_matrix.lup2), mod_matrix.delta_dp) + \ self.beta*delta_t*np.matmul(np.transpose(mod_matrix.phiupT), mod_matrix.delta_pp) indices = np.arange(len(ru), len(ru)+len(nu), 1) phiu_temp = -1*self.beta*delta_t*phiu

# index specified rows (0 index) and columns (1 index) horizontal = np.append(ku, lu, axis = 1) vertical = 1*np.append(np.transpose(lu), phiu_temp, axis = 1) self.general_matrix = np.append(horizontal, vertical, axis = 0) if self.primero == True: self.primero = False #delta_t = 0 # right hand side

ppress_vector_t0 = ppress_t0 np.reshape(ppress_vector_t0, (len(nu), 1)) #print('ppress_vector_t0: \n', ppress_vector_t0) vector_Uu = delta_t*nu + delta_t*np.matmul(phiu, ppress_vector_t0)

Page 309: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 289

vector_F_temp = np.append(ru + ruc, (vector_Uu + uuc), axis = 0) # results in t+1 "t1" (respuesta) desp_zeros = np.zeros((len(ru), 1)) #print('zeros', desp_zeros) ppress_vector_t0 = ppress_vector_t0 - ppress_vector_t0 t0 = np.append(desp_zeros, ppress_vector_t0, axis = 0) self.respuestas.append(t0)

t1 = spsolve(self.general_matrix, vector_F_temp) t1 = np.reshape(t1, (len(t1), 1))

self.resp_out = np.zeros((2, len(t0))) self.resp_out[0] = np.transpose(t0) self.resp_out[1] = np.transpose(t1)

self.respuestas.append(t1) self.res_acum = np.sum(np.transpose(self.resp_out), axis = 1, keepdims = True) ppress_vector = np.take(self.res_acum, indices) ppress_vector = np.reshape(ppress_vector, (len(nu), 1)) self.ppres_max = np.min(ppress_vector) self.ppress_prom = np.mean(ppress_vector) self.presionInicialMaxima = deepcopy(self.ppres_max) print('presión máxima', self.ppres_max) print('presión promedio', self.ppress_prom) else:

if self.primero != 'verdad': ru = mod_vector.modif_v_F - mod_vector.modif_v_F ruc = ru self.primero = 'falso'

self.res_acum = np.sum(np.transpose(self.resp_out), axis = 1, keepdims = True) ppress_vector = np.take(self.res_acum, indices)

ppress_vector = np.reshape(ppress_vector, (len(nu), 1))

vector_Uu = delta_t*0*nu + delta_t*np.matmul(phiu, ppress_vector) vector_F_temp = np.append(ru + ruc, (vector_Uu + uuc) , axis = 0)

tj = spsolve(self.general_matrix, vector_F_temp) tj = np.reshape(tj, (len(tj), 1))

self.respuestas.append(tj) self.resp_out = np.append(self.resp_out, np.transpose(tj), axis = 0)

self.res_acum = np.sum(np.transpose(self.resp_out), axis = 1, keepdims = True)

Page 310: Desarrollo de un laboratorio virtual de geotecnia enfocado

290 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

ppress_vector = np.take(self.res_acum, indices) ppress_vector = np.reshape(ppress_vector, (len(nu), 1))

# promedio de presión de poros al interior de la muestra self.ppres_max = np.min(ppress_vector) self.ppress_prom = np.mean(ppress_vector) print('presión máxima', self.ppres_max) print('presión promedio', self.ppress_prom)

# para validación mediante comparación con Teh Cee Ing, Nie Xiaoyan (2002) # ideal drain tecIng = False if tecIng: ch = 2*5000*(10**(-8))/9.81 print('ch', ch) De = 3.0 th = ch*self.tiempo/(De**2)

grado_de_consolidacion = (self.presionInicialMaxima -self.ppres_max)/self.presionInicialMaxima print('th', th, 'maximaI/maximaInicial', grado_de_consolidacion) self.list_th.append(th) self.list_grado_de_consolidacion.append(grado_de_consolidacion)

# plt1.title('u vs Th')# plt1.grid(True, which='both')# plt1.xlabel('Th')# plt1.ylabel('grado de consolidación promedio (%)') #plt1.plot(self.list_th, self.list_grado_de_consolidacion, 'k.-') # Desplazamiento del cabezal print('desplazamiento-cabezal', self.res_acum[len(ru)-1]) print('deformación', self.res_acum[len(ru)-1]/0.015*100) self.desplazamientoDelCabezal = self.res_acum[len(ru)-1]

# Calculando las reacciones calculated = deepcopy(np.transpose(self.resp_out[-1])) calculated = np.reshape(calculated, (len(calculated), 1))# print('calculated', calculated) index = np.arange(0, len(ru), 1) du = np.take(calculated, index) pu = np.take(calculated, indices) du = np.reshape(du, (len(du), 1))

pu = np.reshape(pu, (len(pu), 1))# print('du', du)# print('pu', pu) a = np.matmul(mod_matrix.kupT, du) b = np.matmul(mod_matrix.kp, mod_matrix.delta_dp)

Page 311: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 291

c = np.matmul(mod_matrix.lup2, pu) d = np.matmul(mod_matrix.lp, mod_matrix.delta_pp) reacc = a + b + c + d# print('reacc', reacc, len(reacc)) # Calculando el caudal a = np.matmul(np.transpose(mod_matrix.lup1), du) b = np.matmul(np.transpose(mod_matrix.lp), mod_matrix.delta_dp) c = - self.beta*delta_t*np.matmul(mod_matrix.phiupT, pu) d = - self.beta*delta_t*np.matmul(mod_matrix.phip, mod_matrix.delta_pp) e = np.array([mod_vector.modif_v_nGp]) f = np.matmul(mod_matrix.phip, mod_matrix.delta_pp) q = 1/delta_t*(a + b + c + d) - delta_t*(np.transpose(e) + f)# print('Q', q, len(q))

test_rc.pyfrom PyQt5 import QtCoreqt_resource_data = NOTA: esta variable consiste en una imagen rasterizada que no se incluye en este documento dado que su extensión es de más de 500 páginas.qt_version = [int(v) for v in QtCore.qVersion().split('.')]if qt_version < [5, 8, 0]: rcc_version = 1 qt_resource_struct = qt_resource_struct_v1else: rcc_version = 2 qt_resource_struct = qt_resource_struct_v2

def qInitResources(): QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)

def qCleanupResources(): QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)

qInitResources()

triaxial_interpretation.py# -*- coding: utf-8 -*-"""Created on Tue Nov 26 09:54:36 2019

@author: JOscar"""import numpy as npimport matplotlib.pyplot as pltfrom math import piimport pickle

class Triaxial_interpretation():

Page 312: Desarrollo de un laboratorio virtual de geotecnia enfocado

292 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

def __init__(self, model, longitud_inicial, presiones): """ """ self._model = model self._presiones = presiones self.ubicacion_de_nodos = [] self.p_line = [] self.q_line = [] self.despl_acum = 0 self.delta_volumen_acum = 0 self.def_axial_line = [] self.def_volumetrica_line = [] self.def_cortante_line = [] self.volumen_line = [] self.volumen_inicial = self.volumen_total() self.longitud_inicial = longitud_inicial

def pq(self, p, q): self.p_line.append(p) self.q_line.append(q) def area_total_section(self): area = 0 for element in self._model.elements: area = area + element.get_area() def volumen_total(self): # Da el volumen en la configuración en la que se encuentra la geometría """si plana de deformación o de esfuerzos presion = None si axisimétrica presiones = modified_matrix.Modified_matrix.presiones""" volumen = 0 for element in self._model.elements: if element.ccxtype in ['CPS6', 'CPE6']: volumen = volumen + 1*element.get_area() elif element.ccxtype in ['CAX6']: # Hacer integral de volumen de revolución con los lados de los elementos como # funciones lineales # encontrar los nodos, organizarlos definir las funciones de rectas, # integrar esas funciones, sumar los resultados volumen = self.volumen_de_revolucion() return volumen return volumen def volumen_de_revolucion(self): volumen = 0 nodos_coor = [] if self.ubicacion_de_nodos == []:

Page 313: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 293

for signlinea in self._presiones.values(): if signlinea['rigid'] == False: # encontrando los nodos for node in signlinea['nodes']: nodos_coor.append((node.x, node.y, node)) nodos_coor.sort(key=lambda coor: coor[0]) self.ubicacion_de_nodos = nodos_coor else: for node in self.ubicacion_de_nodos: nodos_coor.append((node[2].x, node[2].y)) for i, punto in enumerate(nodos_coor, 0): # el contador i comienza en 1 b = nodos_coor[i][1] try: m = (nodos_coor[i+1][1]-nodos_coor[i][1])/(nodos_coor[i+1][0]-nodos_coor[i][0]) except: m = 0 # Definir los límites de integración limiteInferior = nodos_coor[i][0] try: limiteSuperior = nodos_coor[i+1][0]# print('limiteSuperior', limiteSuperior, 'limiteInferior', limiteInferior) integral = (m**2*(limiteSuperior**3-limiteInferior**3)/3 + m*b*( limiteSuperior**2-limiteInferior**2) + b**2*(limiteSuperior - limiteInferior))*pi except: integral = 0 volumen = volumen + integral print('volumen_adentro', volumen)# print('nodos_coor',nodos_coor) return volumen def strains(self, delta_l): # Trabaja de acuerdo a una configuración Lagrangiana Total en la cual el cambio # volumen se hace respecto a la configuración inicial (no deformada) # de la muestra de ensayo # Una apreciación igual se puede hacer respecto a delta_l delta_volumen = self.volumen_total() - self.volumen_inicial # La deformación axial solamente está tomando los incrementos y no está # guardando los datos acumulados self.despl_acum = delta_l #+ self.despl_acum self.delta_volumen_acum = delta_volumen #+ self.delta_volumen_acum def_axial = -self.despl_acum/self.longitud_inicial def_volumetrica = -self.delta_volumen_acum/self.volumen_inicial def_cortante = def_axial - 1/3*def_volumetrica v = self.volumen_inicial*(1-def_volumetrica)

Page 314: Desarrollo de un laboratorio virtual de geotecnia enfocado

294 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.def_axial_line.append(def_axial) self.def_volumetrica_line.append(def_volumetrica) self.def_cortante_line.append(def_cortante) self.volumen_line.append(v*1000000) # graficar la variación de estas cantidades def plot_results(self): self.fig, axs = plt.subplots(3, 2, figsize=(6, 6)) self.fig.tight_layout(pad=1.85)

axs[0, 0].grid(True, which='both') axs[0, 0].minorticks_on() axs[0, 0].grid(which='major', linestyle='-', linewidth='0.4', color='red') axs[0, 0].grid(which='minor', linestyle=':', linewidth='0.4', color='black') axs[0, 0].set_xlabel('εs') axs[0, 0].set_ylabel("q' (kPa)") axs[0, 0].plot(self.def_cortante_line, self.q_line, 'k.-')

axs[1, 0].grid(True, which='both') axs[1, 0].minorticks_on() axs[1, 0].grid(which='major', linestyle='-', linewidth='0.4', color='red') axs[1, 0].grid(which='minor', linestyle=':', linewidth='0.4', color='black')# axs[1, 0].xaxis.tick_top() axs[1, 0].set_xlabel('εₛ') axs[1, 0].set_ylabel("εᵥ") axs[1, 0].invert_yaxis() axs[1, 0].plot(self.def_cortante_line, self.def_volumetrica_line, 'k.-')

axs[0, 1].grid(True, which='both') axs[0, 1].minorticks_on() axs[0, 1].grid(which='major', linestyle='-', linewidth='0.4', color='red') axs[0, 1].grid(which='minor', linestyle=':', linewidth='0.4', color='black') axs[0, 1].set_xlabel("p' (kPa)") axs[0, 1].set_ylabel("q' (kPa)") axs[0, 1].plot(self.p_line, self.q_line, 'k.-')

axs[1, 1].grid(True, which='both') axs[1, 1].minorticks_on() axs[1, 1].grid(which='major', linestyle='-', linewidth='0.4', color='red') axs[1, 1].grid(which='minor', linestyle=':', linewidth='0.4', color='black') axs[1, 1].set_xlabel("p' (kPa)") axs[1, 1].set_ylabel("v (cm³)") # v volumen axs[1, 1].ticklabel_format(axis="y", style="sci", scilimits=(0,0)) axs[1, 1].plot(self.p_line, self.volumen_line, 'k.-') axs[2, 1].grid(True, which='both') axs[2, 1].minorticks_on() axs[2, 1].grid(which='major', linestyle='-', linewidth='0.4', color='red') axs[2, 1].grid(which='minor', linestyle=':', linewidth='0.4', color='black')

Page 315: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 295

axs[2, 1].set_xlabel("εₐ") axs[2, 1].set_ylabel("q' (kPa)") axs[2, 1].plot(self.def_axial_line, self.q_line, 'k.-')# axs[2, 1].invert_yaxis() # plt.title('Compresión triaxial') plt.show() # Para validar mis resultados procedo a exportar los valores de # las variable macro# with open('resultados/def_cortante_line.txt', 'wb') as fp:# pickle.dump(self.def_cortante_line, fp)# # with open('resultados/def_axial_line.txt', 'wb') as fp:# pickle.dump(self.def_axial_line, fp)# # with open('resultados/def_volumetrica_line.txt', 'wb') as fp:# pickle.dump(self.def_volumetrica_line, fp)# # with open('resultados/p_line.txt', 'wb') as fp:# pickle.dump(self.p_line, fp)# # with open('resultados/q_line.txt', 'wb') as fp:# pickle.dump(self.q_line, fp)# # with open('resultados/volumen_line.txt', 'wb') as fp:# pickle.dump(self.volumen_line, fp) # genero el código para cargar los resultados en posteriores análisis # with open ('resultados/def_cortante_line.txt', 'rb') as fp:# def_cortante_line = pickle.load(fp)# # with open ('resultados/def_axial_line.txt', 'rb') as fp:# def_axial_line = pickle.load(fp)# # with open ('resultados/def_volumetrica_line.txt', 'rb') as fp:# def_volumetrica_line = pickle.load(fp)# # with open ('resultados/p_line.txt', 'rb') as fp:# p_line = pickle.load(fp)# # with open ('resultados/q_line.txt', 'rb') as fp:# q_line = pickle.load(fp)# # with open ('resultados/volumen_line.txt', 'rb') as fp:# volumen_line = pickle.load(fp)

trx_interface.py# -*- coding: utf-8 -*-

Page 316: Desarrollo de un laboratorio virtual de geotecnia enfocado

296 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# Form implementation generated from reading ui file 'trx_interface21May.ui'## Created by: PyQt5 UI code generator 5.11.3## WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(735, 549) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_13 = QtWidgets.QHBoxLayout() self.horizontalLayout_13.setObjectName("horizontalLayout_13") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_13.addItem(spacerItem) self.label_Titulo = QtWidgets.QLabel(self.centralwidget) self.label_Titulo.setObjectName("label_Titulo") self.horizontalLayout_13.addWidget(self.label_Titulo) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_13.addItem(spacerItem1) self.gridLayout.addLayout(self.horizontalLayout_13, 0, 0, 1, 2) spacerItem2 = QtWidgets.QSpacerItem(20, 397, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem2, 1, 1, 1, 1) self.scrollArea = QtWidgets.QScrollArea(self.centralwidget) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents = QtWidgets.QWidget() self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 195, 429)) self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") self.groupBox_Loads = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) self.groupBox_Loads.setGeometry(QtCore.QRect(10, 10, 171, 174)) self.groupBox_Loads.setObjectName("groupBox_Loads") self.labelMostrarCarga = QtWidgets.QLabel(self.groupBox_Loads) self.labelMostrarCarga.setGeometry(QtCore.QRect(10, 20, 151, 51)) self.labelMostrarCarga.setObjectName("labelMostrarCarga")

Page 317: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 297

self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.gridLayout.addWidget(self.scrollArea, 1, 0, 2, 2) self.horizontalLayout_12 = QtWidgets.QHBoxLayout()

self.horizontalLayout_12.setObjectName("horizontalLayout_12") self.pushButton_ejecutar = QtWidgets.QPushButton(self.centralwidget) self.pushButton_ejecutar.setCheckable(False) self.pushButton_ejecutar.setObjectName("pushButton_ejecutar") self.horizontalLayout_12.addWidget(self.pushButton_ejecutar) self.gridLayout.addLayout(self.horizontalLayout_12, 3, 0, 1, 1) self.tabWidget_trx = QtWidgets.QTabWidget(self.centralwidget) self.tabWidget_trx.setTabPosition(QtWidgets.QTabWidget.North) self.tabWidget_trx.setTabShape(QtWidgets.QTabWidget.Rounded) self.tabWidget_trx.setObjectName("tabWidget_trx") self.tab_geometry = QtWidgets.QWidget() self.tab_geometry.setObjectName("tab_geometry") self.gridLayout_4 = QtWidgets.QGridLayout(self.tab_geometry) self.gridLayout_4.setObjectName("gridLayout_4") self.graphicsView_geometry = QtWidgets.QGraphicsView(self.tab_geometry) self.graphicsView_geometry.setObjectName("graphicsView_geometry") self.gridLayout_4.addWidget(self.graphicsView_geometry, 0, 0, 1, 1) self.tabWidget_trx.addTab(self.tab_geometry, "") self.tab_elements = QtWidgets.QWidget() self.tab_elements.setObjectName("tab_elements") self.gridLayout_2 = QtWidgets.QGridLayout(self.tab_elements) self.gridLayout_2.setObjectName("gridLayout_2") self.graphicsView_elements = QtWidgets.QGraphicsView(self.tab_elements) self.graphicsView_elements.setObjectName("graphicsView_elements") self.gridLayout_2.addWidget(self.graphicsView_elements, 0, 0, 1, 1) self.tabWidget_trx.addTab(self.tab_elements, "") self.tab_resultados = QtWidgets.QWidget() self.tab_resultados.setObjectName("tab_resultados") self.gridLayout_9 = QtWidgets.QGridLayout(self.tab_resultados) self.gridLayout_9.setObjectName("gridLayout_9") self.graphicsView_resultados = QtWidgets.QGraphicsView(self.tab_resultados) self.graphicsView_resultados.setObjectName("graphicsView_resultados") self.gridLayout_9.addWidget(self.graphicsView_resultados, 0, 0, 1, 1) self.tabWidget_trx.addTab(self.tab_resultados, "") self.gridLayout.addWidget(self.tabWidget_trx, 0, 2, 4, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 735, 21)) self.menubar.setObjectName("menubar") self.menuArchivo = QtWidgets.QMenu(self.menubar) self.menuArchivo.setObjectName("menuArchivo") self.menu_Proyecto = QtWidgets.QMenu(self.menubar) self.menu_Proyecto.setObjectName("menu_Proyecto") self.menuA_yuda = QtWidgets.QMenu(self.menubar) self.menuA_yuda.setObjectName("menuA_yuda") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow)

Page 318: Desarrollo de un laboratorio virtual de geotecnia enfocado

298 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.propertiesAction = QtWidgets.QAction(MainWindow) self.propertiesAction.setObjectName("propertiesAction") self.discretizeAction = QtWidgets.QAction(MainWindow) self.discretizeAction.setObjectName("discretizeAction") self.fileNewAction = QtWidgets.QAction(MainWindow) self.fileNewAction.setObjectName("fileNewAction") self.action_Instrucciones = QtWidgets.QAction(MainWindow) self.action_Instrucciones.setObjectName("action_Instrucciones") self.saveAction = QtWidgets.QAction(MainWindow) self.saveAction.setObjectName("saveAction") self.loadAction = QtWidgets.QAction(MainWindow) self.loadAction.setObjectName("loadAction") self.executeAction = QtWidgets.QAction(MainWindow) self.executeAction.setObjectName("executeAction") self.saveAsAction = QtWidgets.QAction(MainWindow) self.saveAsAction.setObjectName("saveAsAction") self.menuArchivo.addAction(self.fileNewAction) self.menuArchivo.addSeparator() self.menuArchivo.addAction(self.saveAction) self.menuArchivo.addAction(self.saveAsAction) self.menuArchivo.addAction(self.loadAction) self.menu_Proyecto.addAction(self.propertiesAction) self.menu_Proyecto.addAction(self.discretizeAction) self.menu_Proyecto.addAction(self.executeAction) self.menuA_yuda.addAction(self.action_Instrucciones) self.menubar.addAction(self.menuArchivo.menuAction()) self.menubar.addAction(self.menu_Proyecto.menuAction()) self.menubar.addAction(self.menuA_yuda.menuAction())

self.retranslateUi(MainWindow) self.tabWidget_trx.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Triaxial")) self.label_Titulo.setText(_translate("MainWindow", "______TRX________")) self.groupBox_Loads.setTitle(_translate("MainWindow", "Carga de ensayo")) self.labelMostrarCarga.setText(_translate("MainWindow", "<html><head/><body><p>σ\'<span style=\" vertical-align:sub;\">1</span>: 0.0 kPa, σ\'<span style=\" vertical-align:sub;\">3</span>: 0.0 kPa</p></body></html>")) self.pushButton_ejecutar.setText(_translate("MainWindow", "E&jecutar")) self.tabWidget_trx.setTabText(self.tabWidget_trx.indexOf(self.tab_geometry), _translate("MainWindow", "Geometría")) self.tabWidget_trx.setTabText(self.tabWidget_trx.indexOf(self.tab_elements), _translate("MainWindow", "Elementos")) self.tabWidget_trx.setTabText(self.tabWidget_trx.indexOf(self.tab_resultados), _translate("MainWindow", "Resultados"))

Page 319: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 299

self.menuArchivo.setTitle(_translate("MainWindow", "&Archivo")) self.menu_Proyecto.setTitle(_translate("MainWindow", "A&nálisis")) self.menuA_yuda.setTitle(_translate("MainWindow", "A&yuda")) self.propertiesAction.setText(_translate("MainWindow", "&Propiedades")) self.discretizeAction.setText(_translate("MainWindow", "&Discretización")) self.fileNewAction.setText(_translate("MainWindow", "&Nuevo")) self.action_Instrucciones.setText(_translate("MainWindow", "&Instrucciones")) self.saveAction.setText(_translate("MainWindow", "&Guardar")) self.loadAction.setText(_translate("MainWindow", "&Cargar")) self.executeAction.setText(_translate("MainWindow", "&Ejecutar")) self.saveAsAction.setText(_translate("MainWindow", "Guardar como..."))

updated_lagrangean_analysis.py# -*- coding: utf-8 -*-"""Created on Tue Oct 22 15:06:49 2019

@author: JOscar"""

import numpy as npfrom copy import deepcopyimport time

import global_stiffness_matriximport modified_matriximport global_force_vectorimport modified_vectorimport calc_quantitiesimport plotimport unbalanced_force_vectorimport linear_mapping

class uLagAnalysis(): def __init__(self, model): """ Performs the analysis for the piecewise solution of the nonlinear and large displacement model according to Zeevaert (1980) and an associative flow rule The maximum elastic displacement of the system when subjected to full load is then, calculated using the displacements obtained from the first load increment. A norm is set as a percentage of the maximum elastic displacement of any node in the system, with appropriate values being between 3% and 5% Args: model: feamodel

Page 320: Desarrollo de un laboratorio virtual de geotecnia enfocado

300 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Attributes: _model: feamodel nonlinear: boolean, indicates if the step is nonlinear results: dict, store the incremental quantities calculated in each step results_acum: dict, store the total quantites resp_out: np.array, store the displacements (to calculate the accumulated displacements) cont: int, indicate the number of the step norm: float, the maximum allowable displacement _degrees_freedom_d: the ubication of the degrees of freedom in the global stiffness matrix """ self._model = model

self.nonlinear = False self.results = {} self.results_acum = None self.resp_out = None self.cont = 1 self.norm = None self._degrees_freedom_d = None self.desbalanceadasDeZeevaert = True

self.usingSecondPiolaKirchhoff = False self.actualizandoKGparaCargaDesbalanceada = False self.teniendoEnCuentaElVectorDeFuerzasResiduales = False def run_time(self, nu, e, total_unit_weight, steps, H = None, phi = None, c = None): # The initial increment is asummed to be elastic (Burd y Zeevaert) # i.e. the kL and kσ matrices are zero if self.norm == None: # Aquí se analiza la totalidad de la carga en un modelo totalmente elástico # sin criterio de falla self.preparate_matrices(total_unit_weight, nu, e) dd = np.matmul(np.linalg.inv(self.modified_M.matrix_Ku), self.modified_V.modif_v_F) self.norm = 0.03*np.max(np.absolute(dd)) if self.nonlinear == False: # The first load increment has to be very small, I need it to be elastic # self.preparate_matrices(total_unit_weight, nu, e) dd1 = np.matmul(np.linalg.inv(self.modified_M.matrix_Ku), 1/(steps)*self.modified_V.modif_v_F) # Guardando el primer incremento en los desplazamientos self.resp_out = dd1 # Ubicación de los grados de libertad en el sistema general de ecuaciones self._degrees_freedom_d = self.modified_M.degrees_freedom_d

Page 321: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 301

# print('self._degrees_freedom_d', self._degrees_freedom_d) # modificar coordenadas

self.modif_coordinates(dd1, 0) # Instancia de la clase Quantities deformaciones y esfuerzos # 'None' grados de libertad de presión de poros self.strains_stresses = calc_quantities.Quantities(self._model, self._degrees_freedom_d, None)

# Calculando los incrementos de deformaciones y esfuerzos # para los esfuerzos se debe verificar si los puntos de muestreos # entran en fluencia self.strains_stresses.element_strain_stress(self.modified_M, self.matriz_global, self.modified_M.presiones, dd1, 0, global_force_vector = self.vector_F, first = True, c = c, phi = phi, usingSecondPiolaKirchhoff = self.usingSecondPiolaKirchhoff) self.results[self.cont] = deepcopy(self.strains_stresses._results) self.cont = self.cont + 1 # recovering the linear mapping F ϵ {M}^3 if self.usingSecondPiolaKirchhoff: self.preparate_matrices(total_unit_weight, nu, e, _resp = self.results[self.cont-1], H = H, phi = phi, c = c) # Actualizando los estados de esfuerzos acumulando los incrementos # para cada iteración, se tiene la opción del segundo tensor de Piola-Kirchhoff # o sumarlos directamente updating_results = linear_mapping.lineMapping(self._model) if self.usingSecondPiolaKirchhoff: self.results = updating_results.transform_stresses( self.matriz_global, self.results, self.cont-1) elif not self.usingSecondPiolaKirchhoff: # actualizar los esfuerzos sumándolos de manera directa self.results = updating_results.transform_stresses( self.matriz_global,self.results, self.cont-1, usingSecondPiolaKirchhoff = self.usingSecondPiolaKirchhoff) # Ahora se busca hallar la respuesta no linear elastoplástica self.nonlinear = True flag = "Elastico" self.desplazamientos_acumulados() else: flag = self.solve_nonLinear(steps, total_unit_weight, nu, e, self.results[self.cont-1], H, phi, c)# print('self.results', self.results.keys())

Page 322: Desarrollo de un laboratorio virtual de geotecnia enfocado

302 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

return flag#------------------------------------------------------------------------------------------- def solve_nonLinear(self, steps, total_unit_weight, nu, e, _resp, H, phi, c): self.preparate_matrices(total_unit_weight, nu, e, _resp = self.results[self.cont-1], H = H, phi = phi, c = c) ddi = np.matmul(np.linalg.inv(self.modified_M.matrix_Ku), 1/steps*self.modified_V.modif_v_F) criterioParaCompararVectorResidual = 0.10*np.max(np.absolute(1/steps*self.modified_V.modif_v_F)) # Antes de encontrar la carga desbalanceada se debe validar este incremento # si el desplazamiento máximo es menor al permisivo que no he definido self.resp_out = np.append(self.resp_out, ddi, axis = 1) self.desplazamientos_acumulados()# print('self.resp_out', self.resp_out) max_ddi = np.max(ddi) min_ddi = np.min(ddi) if abs(min_ddi) > max_ddi: max_ddi = abs(min_ddi) print('max_ddi', max_ddi, '\n ddi', ddi[-1])# 999 if max_ddi > 0.3*self.norm:# # Disminuir la carga y repetir el cálculo# return "Disminuir incremento de carga" # Si el máximo desplazamiento es más grande que el admisible se debe disminuir # el tamaño del incremento de carga # modificar coordenadas self.modif_coordinates(ddi, 0) # Calcular deformaciones y esfuerzos. 'None' grados de libertad de presión de poros self.strains_stresses = calc_quantities.Quantities(self._model, self._degrees_freedom_d, None) # Deformaciones y esfuerzos self.strains_stresses.element_strain_stress(self.modified_M,

self.matriz_global, self.modified_M.presiones, ddi, 0, global_force_vector = self.vector_F, c = c, phi = phi, e = e, nu = nu, H = H, resultado_anterior = self.results[self.cont-1], usingSecondPiolaKirchhoff = self.usingSecondPiolaKirchhoff) self.results[self.cont] = deepcopy(self.strains_stresses._results) self.cont = self.cont + 1 # recovering the linear mapping F ϵ {M}^3 if self.usingSecondPiolaKirchhoff: self.preparate_matrices(total_unit_weight, nu, e, _resp = self.results[self.cont-1], H = H, phi = phi, c = c) # Actualizando los estados de esfuerzos acumulando los incrementos # para cada iteración, se tiene la opción del segundo tensor de Piola-Kirchhoff

Page 323: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 303

# o sumarlos directamente updating_results = linear_mapping.lineMapping(self._model) if self.usingSecondPiolaKirchhoff: self.results = updating_results.transform_stresses( self.matriz_global, self.results, self.cont-1) elif not self.usingSecondPiolaKirchhoff: # actualizar los esfuerzos sumándolos de manera directa self.results = updating_results.transform_stresses( self.matriz_global,self.results, self.cont-1, usingSecondPiolaKirchhoff = self.usingSecondPiolaKirchhoff)

# Falta hacer el equilibrio para encontrar la carga desbalanceada # El vector de carga desbalanceada se halla por elemento # Tengo que poner un condicional que trate sobre la carga desbalanceada # para disminuirla y llegado un valor parar # Esto como avance para el análisis con el método de Newton Newton-Raphson modificado if self.desbalanceadasDeZeevaert: self.results[self.cont-1] = unbalanced_force_vector.set_UnbForcVector(self._model, self.results[self.cont-1], self.results[1]) unbalanced_force = self.results[self.cont-1] class_UnbForcVector = global_force_vector.Global_force_vector(len(self._model.nodes), problem_type = 'large_displacements') kx, ky, total_unit_weight = None, None, None _UnbForcVector = class_UnbForcVector.writing_loop(self._model, kx, ky, total_unit_weight, unbalanced_force = unbalanced_force) norm_unbalanced_force = np.max(np.absolute(_UnbForcVector)) d_load = np.max(np.absolute(self.modified_V.modif_v_F)) print('d_load', d_load) norm_d = np.max(np.absolute(ddi)) ddjAcumulado = np.zeros((len(ddi), 1)) i = 0 if not self.teniendoEnCuentaElVectorDeFuerzasResiduales: return "success" # 123# ------------------------------------------------------------------------------------------- while norm_d > self.norm: print('norm_d', norm_d, 'self.norm', self.norm)# self.desplazamientos_acumulados()# return "success"# while norm_unbalanced_force > 1*d_load:# for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]: # Iterar hasta que la carga desbalanceada sea muy pequeña # Modificar el vector de fuerzas global con el de las desbalanceadas

Page 324: Desarrollo de un laboratorio virtual de geotecnia enfocado

304 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# para todos los elementos calcular el segundo de Piola y Cauchy # Set the global force vector

# ddj refers to displacements due to unbalaced forces if self.desbalanceadasDeZeevaert: ddj = self.set_GlobalUnbProblem(unbalanced_force, total_unit_weight, nu, e, _resp = self.results[self.cont-1], H = H, phi = phi, c = c) i = i + 1 if i == 1: ddjAcumulado = np.append(ddjAcumulado, ddi, axis = 1) ddjAcumulado = np.append(ddjAcumulado, ddj, axis = 1) else: ddjAcumulado = np.append(ddjAcumulado, ddj, axis = 1) ddjAcumulado = np.sum(ddjAcumulado, axis = 1, keepdims = True) if i == 8: norm_d = 0 else: norm_d = np.max(np.absolute(ddj)) print('ddj', ddj[-1], 'norm_d', norm_d) if self.desbalanceadasDeZeevaert: 999 #implementación no construída norm_unbalanced_force = np.max(np.absolute(self._UnbForcVector)) print('norm_unbalanced_force', norm_unbalanced_force, np.max(self._UnbForcVector), np.min(self._UnbForcVector))

print('residual', norm_unbalanced_force, 'criterio', criterioParaCompararVectorResidual) if norm_unbalanced_force < criterioParaCompararVectorResidual: norm_d = 0 # Calcular deformaciones y esfuerzos. 'None' grados de libertad de presión de poros self.strains_stresses = calc_quantities.Quantities(self._model, self._degrees_freedom_d, None) # Deformaciones y esfuerzos if self.desbalanceadasDeZeevaert: self.strains_stresses.element_strain_stress(self.modified_M, self.class_matrizGlobal, self.modified_M.presiones, ddj, 0, global_force_vector = self.class_UnbForcVector, c = c, phi = phi, e = e, nu = nu, H = H, resultado_anterior = self.results[self.cont-1], usingSecondPiolaKirchhoff=self.usingSecondPiolaKirchhoff) self.results[self.cont] = deepcopy(self.strains_stresses._results) self.cont = self.cont + 1 self.results[self.cont-1] = unbalanced_force_vector.set_UnbForcVector(self._model,

Page 325: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 305

self.results[self.cont-1], self.results[1], acumulado = True, _resp2 = self.results[self.cont-2]) # recovering the linear mapping F ϵ {M}^3 if self.usingSecondPiolaKirchhoff: if self.actualizandoKGparaCargaDesbalanceada: self.class_matrizGlobal.writing_loop(self._model, Dx = None, Dy = None, nu = nu, kx = None, ky = None, fluid_unit_weight = None, e=e, nonlinear = self.nonlinear, _resp = self.results[self.cont-1], H = H, phi = phi, c = c) else: 1 # usar la matriz_global updating_results = linear_mapping.lineMapping(self._model) if self.usingSecondPiolaKirchhoff: if self.actualizandoKGparaCargaDesbalanceada: self.results = updating_results.transform_stresses( self.class_matrizGlobal, self.results, self.cont-1) else: self.results = updating_results.transform_stresses( self.matriz_global, self.results, self.cont-1)

elif not self.usingSecondPiolaKirchhoff: # actualizar los esfuerzos sumándolos de manera directa self.results = updating_results.transform_stresses( self.matriz_global,self.results, self.cont-1, usingSecondPiolaKirchhoff = self.usingSecondPiolaKirchhoff)

unbalanced_force = self.results[self.cont-1] # modificar coordenadas self.modif_coordinates(ddj, 0) self.resp_out = np.append(self.resp_out, ddjAcumulado, axis = 1) self.desplazamientos_acumulados() return "success" def desplazamientos_acumulados(self): # Para sumar los desplazamientos calculados en los incrementos de carga self.res_acum = np.sum(self.resp_out, axis = 1, keepdims = True) # se necesita saber la ubicación de los grados de libertad def modif_coordinates(self, resp, step):# print('self._degrees_freedom_d', self._degrees_freedom_d) for degree in self._degrees_freedom_d: for node in self._model.nodes: if node.id in degree.keys(): if degree[node.id] in ['ux']: node.x = node.x + resp[self._degrees_freedom_d.index(degree), step]

Page 326: Desarrollo de un laboratorio virtual de geotecnia enfocado

306 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

if degree[node.id] in ['uy']: node.y = node.y + resp[self._degrees_freedom_d.index(degree), step] presiones = self.modified_M.presiones

for signlinea in presiones.keys(): if presiones[signlinea]['rigid']:# for str_Code in ['uy', 'ux']: for node in presiones[signlinea]['nodes']: if presiones[signlinea]['vect_perp'][0, 0] == 1 and presiones[signlinea]['vect_perp'][0, 1] == 0: node.y = node.y + resp[self._degrees_freedom_d.index({'carga': presiones[signlinea]['id']}), step] if presiones[signlinea]['vect_perp'][0, 0] == 0 and presiones[signlinea]['vect_perp'][0, 1] == 1: node.x = node.x + resp[self._degrees_freedom_d.index({'carga':presiones[signlinea]['id']}), step] return def set_GlobalUnbProblem(self, unbalanced_force = None, total_unit_weight = None, nu = None, e = None, _resp = None, H = None, phi = None, c = None): self.class_matrizGlobal = global_stiffness_matrix.Global_matrix(len(self._model.nodes), problem_type = 'large_displacements') self.class_matrizGlobal.writing_loop(self._model, Dx = None, Dy = None, nu = nu, kx = None, ky = None, fluid_unit_weight = None, e=e, nonlinear = self.nonlinear, _resp = _resp, H = H, phi = phi, c = c) self.class_UnbForcVector = global_force_vector.Global_force_vector(len(self._model.nodes), problem_type = 'large_displacements') kx, ky, total_unit_weight = None, None, None if self.desbalanceadasDeZeevaert: self._UnbForcVector = self.class_UnbForcVector.writing_loop(self._model, kx, ky, total_unit_weight, unbalanced_force = unbalanced_force) # modifing this matrices matrices according to prescribed quantities modified_M = modified_matrix.Modified_matrix(self._model) modified_M.get_boundary_conditions(self._model) modified_M.put_prescribed_displacement(self.class_matrizGlobal.matrix_K) # Modified global matrices according to tied degrees of freedom modified_M.put_tied_degrees()

Page 327: Desarrollo de un laboratorio virtual de geotecnia enfocado

Anexo D. código desarrollado 307

lista_1 = modified_M.lista_a_borrar_d lista_2 = [0] v_nG = [0, 0] # Modified global force vector if self.desbalanceadasDeZeevaert: modified_V = modified_vector.Modified_vector(self._UnbForcVector, v_nG, lista_1, lista_2) modified_V.put_tied_degrees(modified_M.presiones) if not self.desbalanceadasDeZeevaert: return modified_M ddj = np.matmul(np.linalg.inv(modified_M.matrix_Ku), modified_V.modif_v_F) time.sleep(3.5) return ddj def preparate_matrices(self, total_unit_weight, nu, e, _resp = None, H = None, phi = None, c = None): """ Args: total_unit_weight(float) nu(float): Poisson's ratio e(float): Young's modulus H(float): slope of the uniaxial stress-plastic strain curve phi(float): internal friction angle c(float): cohesion Attributes: """ # global matrices self.matriz_global = global_stiffness_matrix.Global_matrix( len(self._model.nodes), problem_type = 'large_displacements') self.matriz_global.writing_loop(self._model, Dx = None, Dy = None, nu = nu, kx = None, ky = None,

fluid_unit_weight = None, e=e, nonlinear = self.nonlinear, _resp = _resp, H = H, phi = phi, c = c)

# modifing this matrices matrices according to prescribed quantities self.modified_M = modified_matrix.Modified_matrix(self._model) self.modified_M.get_boundary_conditions(self._model) self.modified_M.put_prescribed_displacement(self.matriz_global.matrix_K) # Modified global matrices according to tied degrees of freedom self.modified_M.put_tied_degrees() #Todavía falta poner condicional para grandes deformaciones

Page 328: Desarrollo de un laboratorio virtual de geotecnia enfocado

308 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

# Global force vector self.vector_F = global_force_vector.Global_force_vector(len(self._model.nodes), problem_type = 'large_displacements') kx = None ky = None lista_1 = self.modified_M.lista_a_borrar_d lista_2 = [0] v_F = self.vector_F.writing_loop(self._model, kx, ky, total_unit_weight) v_nG = [0, 0] # Modified global force vector self.modified_V = modified_vector.Modified_vector(v_F, v_nG, lista_1, lista_2)# print('modificado', self.modified_V.modif_v_F) self.modified_V.put_tied_degrees(self.modified_M.presiones) return

Page 329: Desarrollo de un laboratorio virtual de geotecnia enfocado

Bibliografía

Alnuaim, A. M. (2014). Performance of micropiled raft in sand and clay-centrifuge and

numerical studies.

Atkinson, J. (2007). The Mechanics of Soils and Foundations. London: CRC Press,

https://doi.org/10.1201/9781315273549

Bathe, K.-J. (2014). Finite Element Procedures (2nd ed.). Watertown: Klaus-Jürgen Bathe;

second edition (August 25, 2014).

Biot, M. A. (1941). General Theory of Tridimensional Consolidation. Reprinted from Journal

of applied physics, Vol. 12, No. 2, pp. 155-164.

Bishop, A. & Henkel, D. (1957). The Measurement of Soil Properties in the Triaxial Test

(1st ed.). Edward Arnold LTD.

Black, J., (2014). Pycalculix Build FEA Models in Python. Recuperado de:

http://justinablack.com/pycalculix/

Booker, J.R., Small, J.C., (1975). An investigation of the stability of numerical solutions of

Biot’s equations of consolidation. International Journal of Solids & Structures;11:907–11.

Borja R.I. (1991), "Cam clay plasticity, part 11: Implicit integration of constitutive equations

based on nonlinear elastic stress prediction", Comput. Meth. Appl. Mech. Eng., Vol. 88, pp

225-240

Borja, R., Tamagnini, C., & Alarcón, E. (1999). Consolidación elastoplástica con

deformaciones finitas: Implementación con elementos finitos y ejemplos numéricos.

Métodos Numéricos Para Cálculo y Diseño En Ingeniería: Revista Internacional, 15(2),

269–296.

Page 330: Desarrollo de un laboratorio virtual de geotecnia enfocado

310 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Budhu, M. (2001). A Multimedia Geotechnical Laboratory Test. ASEE Annual Conference

and Exposition, Charlotte.

Burd, H. J. (1986). A Large Displacement Finite Element Analysis of a Reinforced Unpaved

Road. University of Oxford.

Cardoso, V. E. (2016). Finit3element. Recuperado de:

https://finit3element.wordpress.com/2016/04/27/intro/

Casanova, F. & Atilus , W. (2013). Desarrollo de una red neuronal artificial para validar

cálculos en el diseño estructural de puentes. Revista Académica de la Facultad de

Ingeniería, Universidad Autónoma de Yucatán. Vol. 17, No.3

Chen, W. F. (Ed.). (2013). Limit analysis and soil plasticity. Elsevier.

Cividini, A (1993). Constitutive behaviour and numerical modelling. In: Hudson J (ed)

Comprehensive rock engineering, vol 1. Pergamon Press, Oxford, pp 395–426

Cueto, O., Herrera, M., Coronel, C., & Bravo. (2013). Análisis de los modelos constitutivos

empleados para simular la compactación del suelo mediante el método de elementos

finitos. 22. 75-80.

Drucker, D. C. & Prager, W. (1952). Soil mechanics and plastic analysis for limit design.

Quarterly of Applied Mathematics, vol. 10, no. 2, pp. 157–165.

Duque, G. & Escobar C. (2016). Geomecánica. Universidad Nacional de Colombia - Sede

Manizales, Manizales, Colombia.

Engineers Edge, (s. f.). Von Mises Criterion (Maximum Distortion Energy Criterion) Strength

(Mechanics) of Materials. Recuperado el 23 de Junio de 2020 de

https://www.engineersedge.com/material_science/von_mises.htm

England, R. (1969). Error estimates for Runge – Kutta type solutions to systems of ordinary

differential equations. Computer Journal, 12, 166-170.

Gear, C., W. (1971). Numerical Initial Value Problems in Ordinary Deferential Equations,

Prentice-Hall, New Jersey.

Page 331: Desarrollo de un laboratorio virtual de geotecnia enfocado

Bibliografía 311

Germaine, J. T., & Ladd, C. C. (1988). Triaxial of saturated cohesive soils. Advanced triaxial

testing of souls and rock, ASTM STP 977, Robert T. Donaghe, Ronald C. Chaney and

Marshall L. Silver, Eds., American Society for Testing and Materials, Philadelphia, pp. 421-

459.

Gockenbach, M. S. (2006). Understanding and Implementing the Finite Element Method.

(SIAM, Ed.) (1st ed.). Society for Industrial and Applied Mathematics (SIAM, 3600 Market

Street, Floor 6, Philadelphia, PA 19104).

Granados, J. S. A. P. (2018). Las nuevas generaciones como un reto para la educación

actual. Bogotá: Universidad Sergio Arboleda.

Griffiths, D., & Smith, L. (1988). Programming the Finite Element Method (2nd ed.). Wiley.

Griffiths, D., V. (1982). Computation of Bearing Capacity Factors using Finite Elements.

Geotechnique vol. 32(3) pp 195-202

Griffiths, D. V. (1994). Coupled Analyses in Geomechanics. Visco-Plastic Behaviour of

Geomaterials, 245–317. https://doi.org/10.1007/978-3-7091-2710-0_5

Guerrero M, L. F., Gómez P, D., Sandoval V, E., Thomson, P., & Marulanda Casas, J.

(2014). SISMILAB, un laboratorio virtual de ingeniería sísmica, y su impacto en la

educación.

Gutierrez, M., Ishihara, K., & Towhata, I. (1991). Flow theory for sand during rotation of

principal stress direction. Soils and foundations, 31(4), 121-132.

Hatherly, P. A. (2016). The Virtual Laboratory and Interactive Screen Experiments.

Connecting Research in Physics Education with Teacher Education, 1–7.

Hammer, P. C., Marlowe O. P., & Stroud, A. H. (1956). "Numerical Integration Over

Simplexes and Cones", Mathematics Tables Aids Computation, Vol. 10, pp. 130 -137.

Harkness, J., Zervos, A., Le Pen, L. Aingaran S., Powrie William (2016). Discrete element

simulation of railway ballast: modelling cell pressure effects in triaxial tests. Granular Matter

18, 65. https://doi.org/10.1007/s10035-016-0660-y

Page 332: Desarrollo de un laboratorio virtual de geotecnia enfocado

312 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Henkel, D. J. (1956). The effect of overconsolidation on the behaviour of clays during shear.

Geotechnique, 6 :139-1 50.

Hird, C. C., Pyrah, I. C. & Russell, D. (1992). Finite element modelling of vertical drains

beneath embankments on soft ground. Geotechnique 42, No. 3, 499-511.

Ho, I. H., & Hsieh, C. C. (2013). Numerical modeling for undrained shear strength of clays

subjected to different plasticity indexes. Journal of GeoEngineering, 8(3), 91-100.

Holzbecher, E. (2016). Multiphysics modelling of the Mandel – Cryer effect. International

Journal of Multiphysics, 10(1), 11–20. https://doi.org/10.21152/1750-9548.10.1.11

Jeon, H.-M., Lee, P.-S., & Bathe, K.-J. (2014). The MITC3 shell finite element enriched by

interpolation covers. Computers & Structures, 134, 128–142.

https://doi.org/https://doi.org/10.1016/j.compstruc.2013.12.003

Labuz, J.F., Zang, A. (2012). Mohr–Coulomb Failure Criterion. Rock Mech Rock Eng 45,

975–979. https://doi.org/10.1007/s00603-012-0281-7

Ma, B., Muhunthan, B. & Xie, X. (2013), Stress history effects on 1‐D consolidation of soft

soils: a rheological model. Int. J. Numer. Anal. Meth. Geomech., 37: 2671-2689.

doi:10.1002/nag.2156

Masala, S.; Biggar, K. (2005). The Geotechnical Virtual Laboratory. II. Consolidation.

Geotechnical Centre at the University of Alberta (LEE4).

Matsuoka, H. (1976). On the Significance of the Spatial Mobilised Plane. Soils and

Foundations, Vol 16(1) pp 91-100.

Mckenna, F., Fenves, G.L., Filippou, F.C, Mazzoni, S. (2008), “Open System for

Earthquake Engineering Simulation, University of California”, Berkeley,

http://opensees.berkeley.edu

Medzvieckas, J., Dirgėlienė, N., & Skuodis, Š. (2017). Stress-strain states differences in

specimens during triaxial compression and direct shear tests. Procedia Engineering, 172,

739-745.

Page 333: Desarrollo de un laboratorio virtual de geotecnia enfocado

Bibliografía 313

NASA (1993), FAST User Guide, Recuperado el 01 de Agosto de 2020 de

https://www.nas.nasa.gov/Software/FAST/RND-93-010.walatka-

clucas/htmldocs/titlepage.html

Papakaliatakis, G., & Simos, T. E. (1999). Integration of Some Constitutive Relations of

Plane Strain Elastoplasticity Using Modified Runge-Kutta Methods. Civil Engineering and

Environmental Systems, 16(2), 77–92. https://doi.org/10.1080/02630259908970254

Payen, D. J., & Bathe, K.-J. (2011). Improved stresses for the 4-node tetrahedral element.

Computers & Structures, 89(13), 1265–1273.

https://doi.org/https://doi.org/10.1016/j.compstruc.2011.02.009

Penumadu, D., Zhao, R., & Frost, D. (2000). Virtual geotechnical laboratory experiments

using a simulator. International journal for numerical and analytical methods in

geomechanics, 24(5), 439-451.

Potts, D. (2003). Numerical analysis: A virtual dream or practical reality? Geotechnique. 53.

535-573. 10.1680/geot.53.6.535.37330.

Potts, D., & Axelsson, K. (Eds.). (2002). Guidelines for the use of advanced numerical

analysis. Thomas Telford.

Potts D. & Ganendra D. (1994), "An evaluation of substepping and implicit stress point

algorithms", Comput. Meth. Appl. Mech. Eng., Vol. 119, pp 341-354.

Potts D. & Gens A. (1985), "A critical assessment of methods of correcting for drift from the

yield surface in elasto-plastic finite element analysis", Int. Jnl. Num. Anal. Meth. Geomech.,

Vol. 9, pp 149-159.

Potts, D., & Zdravkovic, L. (1999). Finite Element Analysis in Geotechnical Engineering:

Volume 1 - Theory. https://doi.org/10.1680/feaiget.27534

Potts, D., & Zdravkovic, L. (1999-b). Some Pitfalls when using Modified Cam Clay.

Potts, D., & Zdravkovic, L. (2001). Finite Element Analysis in Geotechnical Engineering:

Volume 2 - Application (Vol. 1). https://doi.org/10.1680/feaigea.27831

Page 334: Desarrollo de un laboratorio virtual de geotecnia enfocado

314 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Ramírez, J M. & Rivera, S. (2017) Aplicación del ciclo de vida y el análisis estructurado en

el desarrollo de un laboratorio virtual de transformadores monofásicos. Revista Educación

en Ingeniería 12 (23) 43-48.

Rendulic, L. (1935). Der Hydrodynamische Spannungsausgleich in Zentral Entwaserten

Tonzylindern Wasserwirtschaft und Technik, Wein 1935;2:250–3.

Sagrilo, L.V., Sousa, J.R., Lima, E.C., Porto, E.C., & Fernandes, J.V. (2012). A Study on

the Holding Capacity Safety Factors for Torpedo Anchors. J. Applied Mathematics, 2012,

102618:1-102618:18.

Segerlind, L. J. (1984). Applied Finite Element Analysis (2nd ed., Vol. 1). Michigan: Wiley.

Simo, J. C. & Hughes, T. J. R., (1998), Computational Inelasticity, Springer.

Simulsoft, (2018). Listado updates_octubre_2018. Recuperado el 16 de Julio de 2020 de:

descargas.simulsoft-

ingenieros.es/gts_nx/documentacion/listadoupdates_octubre_2018.pdf

Sloan, S., W. (1981). Numerical Analysis of Incompressible and Plastic Solids Using Finite

Elements. Ph.D. Thesis university of Cambridge.

Sloan S., W. (1987). Substepping schemes for numerical integration of elastoplastic stress-

strain relations. Int. Jnl. Num. Meth. Eng., Vol. 24, pp 893-911

Smith I., & Hobbs R. (1976). Biot analysis of consolidation beneath embankments.

Geotechnique 26, 149–171.

Smith, I., Griffiths, D., & Margetts, L. (2014). Programming the Finite Element Method. (J.

W. & S. Ltd, Ed.) (5th ed., Vol. 1). Chennai, India: Wiley.

Schneider & Hans (1977). "Olga Taussky-Todd's influence on matrix theory and matrix

theorists". Linear and Multilinear Algebra. 5 (3): 197 – 224. Doi:

10.1080/03081087708817197

Summerfield, M. (2007). Rapid GUI Programming with Python and Qt: The Definitive Guide

to PyQt Programming (paperback). Pearson Education.

Page 335: Desarrollo de un laboratorio virtual de geotecnia enfocado

Bibliografía 315

Sutterer, K. (2010). Undergraduate Geotechnical Laboratory and Field Testing : A Review

of Current Practice and Future Needs, 1–10.

Ing, T. & Xiaoyan, N. (2002). Coupled consolidation theory with non-Darcian flow.

Computers and Geotechnics -COMPUT GEOTECH. 29. 169-209. 10.1016/S0266352X

(01)00022-2.

Terzaghi, K., (1943), Theoretical Soil Mechanics, John Wiley.

Terzaghi, K., & Peck, R, B. (1968), Soil Mechanics in Engineering Practice, 2nd Ed., John

Wiley.

Universidad de Castilla - La Mancha, (s. f). Diagrama de Flujo del MEF. Recuperado el 08

de mayo de 2020 de:

https://previa.uclm.es/profesorado/evieira/asignatura/meccomp/book/MEF/Flux_diag.htm

Universidad de Valencia (1998). Método de Newton. Recuperado el 09 de mayo de 2020

de: https://www.uv.es/~diaz/mn/node20.html

Valarezo, M. (2010). Laboratorio virtual de ingeniería geotécnica. Universidad Técnica

Particular de Loja.

Valerio, O. (2011). Ensayos triaxiales para suelos. Métodos Y Materiales, 1(1), 14-24.

https://doi.org/10.15517/mym.v1i1.8391

Westergaard, H. M. (1952), Theory of Elasticity and Plasticity, Harvard University Press,

John Wiley.

Wood, D. (1991). Soil Behaviour and Critical State Soil Mechanics. Cambridge: Cambridge

University Press. doi:10.1017/CBO9781139878272

Yu, H. S. (2007). Plasticity and geotechnics (Vol. 13). Springer Science & Business Media.

Zeevaert, A. E. (1980). Finite Element Formulation for the Analysis of Interfaces, Nonlinear

and Large Displacement problems in geotechnical engineering. Georgia Institute of

Technology.

Page 336: Desarrollo de un laboratorio virtual de geotecnia enfocado

316 Desarrollo de un laboratorio virtual de geotecnia enfocado en el

ensayo de compresión triaxial modalidad compresión axial.

Zelle, J. M. (2004). Python programming: an introduction to computer science. Franklin,

Beedle & Associates, Inc.