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 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
(Dedicatoria)
A mis padres.
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.
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.
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.
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
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
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
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
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
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 𝑚
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
𝑎𝑑𝑖𝑚
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
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).
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.
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:
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
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).
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)
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.
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
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
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.
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.
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.
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).
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).
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
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).
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.
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.
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
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.
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.
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 𝐴𝐵
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-
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).
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
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 𝑃 = 𝐹.
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
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
(𝐸𝑢).
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)
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)
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
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
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)
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,
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
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).
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).
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.
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)
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):
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).
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).
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)
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
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
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.
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
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:
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
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).
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)
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.
Sí
a
a
No
Fin.
Segunda aproximación al estado corregido de esfuerzos.
Sí
Inicio
Estimación del error local (E) y el error relativo (R).
Inicia el subpaso i.
Actualización de las variables acumuladas.
?
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
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.
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
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.
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.
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
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)
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
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.
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).
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
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):
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.
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.
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.
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)
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
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.
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
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’).
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
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'
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'
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
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.
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.
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.
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.
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.
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
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 𝐻’.
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.
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.
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:
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
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:
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
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
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.
_________________________________________________________________
_________________________________________________________________
__________________________________________________
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 𝐻′.
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
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
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
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
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𝑘𝑃𝑎 =
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
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
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
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.
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.
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).
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.
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)
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)
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
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.
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).
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
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.
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
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.
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 [𝐵]
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.
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
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:
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)
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).
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)
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}.
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)
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)
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.
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).
Anexo B. Anotaciones sobre la implementación del modelo acoplado 129
{𝑄} =1
∆𝑡([𝐿𝑢𝑝1]
𝑇{Δ𝑑𝑢} + [𝐿𝑝]
𝑇{Δ𝑑𝑝} − 𝛽∆𝑡[Φ𝑢𝑝]
𝑇{Δ𝑝𝑢}
− 𝛽∆𝑡[Φ𝑝]{Δ𝑝𝑝}) − [{𝑛𝐺𝑝} + [Φ𝐺𝑝] ({∆𝑝𝑓}𝑛𝐺𝑝)𝑡] ∆𝑡
(B.8)
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).
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.
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).
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.
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
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
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
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]
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]
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)
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(
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])
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)
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],
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
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
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):
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)
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
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"
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)
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'
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 '.'
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']))
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
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)
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)
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()
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")
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)
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)
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
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)
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)
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
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,
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())
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)
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')
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()
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²')
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)
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
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)"
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
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()))
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')
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 -*-"""
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,
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)
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])
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")
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)
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:
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:
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")
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"))
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")
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")
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 "Análisis" > "Propiedades":</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
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 "Análisis" > "Propiedades" > "Avanzado"</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
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")
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 "Análisis" > "Propiedades":</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 "Análisis" > "Propiedades" > "Avanzado"</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>"))
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)
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:
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!
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)
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)
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")
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)
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)
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
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:
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"
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!
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)
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")
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)
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)
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)
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)
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"))
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']:
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
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],
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]])
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]
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
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]
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():
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
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))
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
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']:
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)
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
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
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,
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
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)
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)
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')
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)
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],
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
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Φ'))
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
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],
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]
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],
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"
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):
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]
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
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(
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']
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(
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:
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.
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,
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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
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
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}
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 """
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 +
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 """
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
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
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)
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])
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)
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):
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]
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']
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'],
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():
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)
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)
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
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): #
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)
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,
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')
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
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)
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
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)
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)
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)
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():
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 == []:
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)
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')
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 -*-
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")
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)
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"))
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
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
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())
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
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
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,
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]
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()
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
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
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.
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.
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
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.
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
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.
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.
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.