Archivo de la etiqueta: abaqus

Lo que he aprendido: programar tareas desde cmd en Windows

Siguiendo en mi cruzada de hacer que el ordenador trabaje mientras yo leo movidas en el interneto, he aprendido a “retrasar” una tarea en Windows sin usar el Programador de tareas: usar el comando timeout. Lo que hace es esperar un determinado tiempo antes de ejecutar el próximo comando. Es megaguay porque pone una cuenta atrás y parece que el ordenador va a explotar o algo. Es especialmente interesante para usarlo en un ordenador comunitario y no avisar a los demás de lo que andas tramando. Sí, soy malvada y me encanta.

Es tan fácil de usar como hacer:

timeout <T>

Donde <T> es el tiempo que tiene que esperar en segundos. Tenemos la opción de añadir /nobreak para que si alguien pulsa una tecla no se nos active la tarea.

De propinilla vamos a aprender cómo escribir comentarios en la línea de comandos de Windows:

  • Comentar línea completa: usamos ::
  • Comentario dentro de la línea: usamos & :: ya que el & es el comando separador de líneas, es decir, permite poner varios comandos en una única línea.

Lo he usado para programar un cálculo de Abaqus y aprovechar el ordenador por la noche. Para ello he creado un archivo cmd y he escrito lo siguiente en él:

:: Wait 10'
timeout 600 /nobreak 
abaqus job=<JOBNAME> interactive
pause & :: wait until keystroke

El pause del final es para que no se me cierre la ventanita al acabar y poder ver cómo ha ido el tema la mañana siguiente.

Nada más por hoy, estamos un poco más cerca de este señor 😛

Fuentes

Man de timeout

How to comment in Windows command line? en StackOverflow

10 Keys to Command Shell Scripting

Difference Between CMD and BAT

Lo que he aprendido: subestructuras en Abaqus

Hace un tiempecillo compartí con vosotros un poco de código para leer matrices de subestructura de Abaqus en Matlab. Hoy voy a contar cómo se usan las subestructuras en Abaqus porque difícilmente vamos a poder importar una en Matlab si no la hemos creado antes. La teoría de lo que es una subestructura, para qué sirve y tal seguro que ya la sabéis, pero algún día igual me vengo arriba y os la repito 😉

Vamos al lío.


Usar subestructuras tiene dos partes diferenciadas: hacer el modelo de la subestructura y hacer el modelo completo donde se usará la subestructura. Esto tiene toda la lógica si pensáis en la teoría: en el modelo de subestructura condensaremos las matrices a los nodos que nos parezca y luego en el modelo completo importaremos las matrices reducidas.

Empecemos con el primer pasito:

Lo que es la subestructura en sí

Esto en sí es bastante fácil, el problema está en que reduzcamos como es debido, cosa que está más relacionada con nuestra capacidad de modelización que con el programa. Son cuatro pasos de nada:

1) Hacemos un modelo que solo contenga la subestructura

2) Creamos un Step de generación de subestructuras:

elegir

Tenemos que darle un número identificador y decirle qué modos y qué matrices necesitamos. Si no le decimos nada, solo calcula la matriz de rigidez porque supone que estamos haciendo una condensación estática, es muy listo él.

step

Yo voy a hacer una condesación dinámica porque me gusta que las cosas se muevan, pero la estática funciona parecido, es más fácil de hecho 🙂

3) Creamos una condición de contorno de nodos retenidos (Retained nodal dofs) y elegimos las superficies y grados de libertad a los que condensaremos las matrices1, las fronteras en jerga subestructuril.

4) Creamos y enviamos el Job.

Ese es el esquema general, pero debemos tener en cuenta lo siguiente:

  • Para que retenga modos tendremos que hacer un cálculo de modos antes de la
    creación de la subestructura

  • Para que aplique las cargas en la subestructura en el modelo completo será necesario que creemos un Load Case en el modelo de la subestructura. En el modelo completo tendremos que crear un Substructure Load donde se escalara la carga.

  • Todas las condiciones de contorno y cargas hay que aplicarlas en un Step
    previo al de la creación de la subestructura y liberarla en el Step de subestructura. Es algo que hay que tener especialmente en cuenta si somos fans de síntesis modal con fronteras fijas.

Para exportar las matrices de la subestructura tendremos que escribir lo siguiente en el step de generar la subestructura:

*SUBSTRUCTURE MATRIX OUTPUT, OUTPUT FILE=USER DEFINED, FILE
NAME=nombre, STIFFNESS=YES, MASS=YES

Generará un archivo .mtx por cada matriz que podremos leer con el código aquel de Matlab. Estos archivos de matriz tendrán una estructura diferente dependiendo de si la matriz es simétrica o asimétrica:

  • Si es simétrica exporta solamente media matriz, básicamente va escribiendo el triángulo y cuando se queda sin espacio en la línea salta:

symmetric

  • Si no es simétrica tiene que exportar la matriz completa:

asymmetric

La mayor parte de las veces las matrices serán simétricas, así que voy a quedarme con este caso. Si importamos la matriz de rigidez en Matlab nos encontraremos con algo como esto:

K

El primer triángulo representa los grados de libertad retenidos. Hacen un total de nodos_Retenidos*gdl_por_nodo. El resto es una matriz diagonal cuya dimension es igual al número de modos retenidos. Por ejemplo, en este caso he retenido 4 nodos con 3 gdl por nodo y 40 modos, por eso hay un triángulo de 4*3 = 12 filas y una parte diagonal de 40 filas, haciendo un total de 12+40 = 52 filas.

La matriz de masa es algo asi:

M

La explicación de una matriz tan raruna es hace Craig – Bampton2, es decir, parte las matrices de la siguiente manera:

Craig

Ahí también se ve claro por qué la matriz de rigidez tiene la pinta que tiene.

Ahora nos falta importar la subestructura en el modelo completo. Hagámoslo.

En el modelo completo

La subestructuras importan como si fueran partes normales en File > Import > Part y eligiendo el archivo .sim que hemos generado en los pasos anteriores, que tendrá un nombre del tipo nombreModelo_Z Identificador.sim. También se tratan como piezas normales, la única diferencia es que solo podremos interaccionar con los nodos retenidos.

En Part > Query podemos ver el número de grados de libertad retenidos y tal, para hacernos una idea de cómo es nuestro modelo:

query

statistics

Y ya está, señores. Podemos jugar todo lo que queramos con ello, ver qué modos necesitamos, cómo afecta usar fronteras fijas o libres, ver la calidad de los resultados… Horas de entretenimiento 😛


  1. Cuidado con lo que elegís, que me he puesto a hacer una prueba chorra y he creado sin querer un archivo de 8GB 
  2. Algún día os contaré más sobre este método, de momento podéis echarle un ojo aquí 

Lo que he aprendido: extraer matrices globales de Abaqus

Seguimos con Abaqus, gente. Hoy os cuento cómo extraer las matrices globales y cómo leerlas después en Matlab. Un día no muy lejano todo esto que escribo aquí se unirá y creará una historia gigante. Paciencia, ese día llegará. De momento leamos matrices.


Abaqus nos permite exportar las matrices de dos maneras: como matrices elementales que luego deberemos ensamblar o las matrices globales. Yo soy vagancias y paso de ensamblar así que elegí la opción 2. El tema de para qué quiero yo las matrices globales os lo contaré en el futuro, el día que se alineen los astros.

Además, Abaqus puede exportar estas matrices en diferentes formatos. Nosotros vamos a quedarnos con el .mtx que es un fichero de texto plano y es fácil de leer. Una vez que sabemos esto, lo que tenemos que hacer es incluir este step en el .inp:

*STEP, name=exportmatrix
*MATRIX GENERATE, STIFFNESS, MASS, STRUCTURAL DAMPING
*MATRIX OUTPUT, STIFFNESS,MASS, STRUCTURAL DAMPING, FORMAT=MATRIX INPUT
*END STEP
**

Lógicamente, le llamáis como os apetezca, teniendo en cuenta que Abaqus bautizará los archivos que cree como nombreStep_STIF#.mtx, nombreStep_MASS#.mtx … donde # es el número del step. Y, lógicamente también, incluis solamente las matrices que queráis sacar, podéis elegir entre STIFFNESS, MASS, STRUCTURAL DAMPING, VISCOUS DAMPING y LOAD.

Ahora que ya hemos exportado, nos queda entender el archivo .mtx. Este archivo tiene 5 columnas que representan los valores no nulos de la matriz. Las columnas representan:

  1. El nodo al que corresponde la fila
  2. El grado de libertad del nodo de la fila
  3. El nodo al que corresponde la columna
  4. El grado de libertad del nodo de la columna
  5. El valor de la matriz para esa posición

Es decir: nodo1, gdl, nodo2, gdl, valor.

Esto lo podemos leer muy fácilmente en Matlab, aquí tenéis el código que yo he utilizado, que es una modificación para el caso tridimensional del código que hay aquí

Por último, algunas cosas a tener en cuenta para no liarla:

  • Si colocáis este step después de un step en el que se apliquen codiciones de contorno, exportará con las condiciones de contorno aplicadas. Cuidado con esto porque nos puede dar problemas por el condicionamiento de la matriz. Mejor exportar libre y aplicar las condiciones de contorno en Matlab, sobre todo si estáis calculando frecuencias naturales.

  • No carrula bien para los elementos de modos incompatibles, exporta cosas raras delante1. Esto nos la lía a todos los que tenemos problemas de flexión y nos obliga o a mallar ultrafino o a usar elementos cuadráticos.

  • Si vais a aplicar las condiciones de contorno en Matlab os recomiendo activar “Do not use part and assembly” en los atributos del modelo y os ahorráis el lío de que llame diferente a los nodos en el Part y en el Assembly.

Y hasta aquí hemos llegado, chavalería. Ya podemos usar Abaqus para que nos cree matrices y luego usarlas nosotros para fines perversos. Os quejaréis.


  1. Estas cosas raras son, supongo, cómo aplica Abaqus la condición de cortante cero en caso de flexión pura y tal, pero no me hagáis mucho caso, aun no sé interpretarlo. 

Lo que he aprendido: estudio paramétrico en Abaqus

Lo que os traigo hoy es algo bastante especializado en mi campo y la probabilidad de que os interese es sumamente pequeña, pero bueno, lo he aprendido así que aquí va como mandan los cánones.


Bien, os voy a contar cómo hacer un estudio paramétrico en Abaqus. Voy a dar por hecho que Abaqus sabéis usar más o menos (como yo) porque, verdaderamente, si no sabéis usarlo no sé qué andáis leyendo cosas extrañas sobre él 😉

Cuando digo estudio paramétrico me refiero a que en lugar de darle un valor fijo a una o varias variables les vamos a dar una ristra de valores diferentes y luego vamos a pintar como cambia nuestro resultado según estos valores. Que suena muy bien pero luego ya veis la chorrada que es.

En fin, Abaqus nos permite escribir una archivo .psf (Python Scripting File) que crea archivos .inp a partir de una plantilla y luego trata los resultados. Son archivos de Python que se lanzan en el terminal1 con:

abaqus script=archivo

Se organizan así:

  • Se crea el estudio paramétrico con ParStudy(). ParStudy es una clase, lo que viene a continuación son métodos que se aplican a dicha clase.
  • Se definen los parámetros: tipo (continuo o discreto), el dominio… con define()
  • Se muestrean lo parámetros dando las opciones de muestreo con sample()
  • Se combinan los parámetros para generar los puntos de muestreo con combine()
  • Se generan los diseños y los .inp correspondiente con generate()
  • Se ejecutan los .inp con execute()
  • Se recopilan los resultados deseados con gather()
  • Se saca un informe de los resultados con report()

Como dice el proverbio, las palabras son enanos y los ejemplos gigantes, así que aquí va un ejemplo de cómo se haría esto para el caso que queramos estudiar el efecto del módulo de Young en los modos de una pieza:

# Definir el estudio paramétrico 
# (name es el nombre del inp parametrizado)

aStudy=ParStudy (par='E', name='modos')

# Definir el dominio de la variable

aStudy.define(CONTINUOUS, par='E', domain=(100e9, 300e9)) 
aStudy.sample(NUMBER, par='E', number=5) 
aStudy.combine(MESH)

# Generar inps basándose en el inp original

aStudy.generate(template='modos')

# Ejecutar todos

aStudy.execute(ALL)

# Especificar que se quiere como output

aStudy.output(file=ODB, step=1)

# Se pueden coger las variables que se quiera y meterlas en una tabla

aStudy.gather(results='modos', variable='MODAL',  step=1, mode=2)
aStudy.report(PRINT, results='modos')

Nos queda la segunda parte, el .inp plantilla. Esto es muy fácil, solo hay que añadir esto al .inp:

*PARAMETER
Variable = valor

Y cuando aparezca el valor de la variable cambiarlo por . Siguiendo con el ejemplo del módulo de Young, tendríamos:

* PARAMETER
E = 210000000000

** MATERIALS
**
*Material, name=Material-1
*Density
7900.,
*Elastic
 <E>, 0.3

Ahora ya podemos lanzar el script. Empezaremos a ver algo parecido a esto:

cmd

Que nos irá diciendo cómo va el tema y finalmente nos enseñará los resultados.

En resumen, hay que hacer dos cosas: (1) crear un archivo .psf que defina el estudio paramétrico y (2) crear un .inp plantilla donde se diga qué parámetros van a estudiarse. Muy sencillo todo.

Bueno pues, ¡todos a parametrizar!

Más


  1. En Run script o en execfile() no funcionan, no me digáis por qué. 

Lo que he aprendido: importar matrices de subestructura de Abaqus en Matlab

No me gusta Abaqus y no me gusta Matlab. No son software libre. Pero en el currelo me obligan a usarlos. Y en conjunción además, como los astros. Para remediar un poco el odio cerval que dicha situación me produce, intento compartir al máximo las movidas que hago.

Hoy sin más os pongo aquí la minifunción que he escrito para leer las matrices de subestructura que exporta el señor Abaqus. Otro día con tiempo y ganas os explico mejor el tema, pero de momento si a alguien le puede resultar útil aquí lo tiene.

Lo que he aprendido: funciones anónimas en Matlab

¡Hoy he descubierto la existencia de funciones anónimas en Matlab! Son una historia muy típica de los lenguajes funcionales generalmente conocidas como funciones lambda. Son funciones pequeñas (en general de una única línea) que no hace falta guardar en un archivo aparte como pasa con las funciones normales de Matlab. Que sean pequeñas no quiere decir que no sean muy útiles sino que te obligan a pensar de una manera totalmente diferente (¡no pueden ponerse ifs ni fors dentro de ellas!)

Como primera aproximación las he utilizado en una función que extrae las coordenadas de los nodos de las piezas de un archivo inp de Abaqus. Si no tenéis ni idea de qué hablo pensad que tengo un archivo de texto con un montón de información y solo quiero sacar unos datos concretos.

El código quedaría algo así (como veis soy la persona que más comenta del mundo):


function C = coordenadasInp(archivoLectura)

% Extraer coordenadas de un archivo inp de Abaqus (sin part y assembly)
% Devuelve un cell cuyos elementos son las coordenadas de cada pieza 
% en el sistema global

texto = fileread(archivoLectura); % Leer inp

% Parte el texto en numero de piezas + 1 trozos. 
% El primer trozo es el heading
C = strsplit(texto,'*Node'); 
C = C(2:end); % Quitar el heading

% Coger el trozo entre *Node y *Element
C = cellfun(@(x) strsplit(x,'*Element'), C, 'UniformOutput', 0); 

% Hay que quedarse con el primer trozo de cada celda excepto 
% de la primera
C = cellfun(@(x) x{1}, C, 'UniformOutput', 0); 

% Convertir el string a número
C = cellfun(@str2num, C, 'UniformOutput', 0); 

En este programilla las funciones anónimas son el primer argumento de la función cellfun, que aplica una función a todos los elementos de un cell array. Su estructura es:


@(x,y) f(x,y)

Es decir, se definen las variables de entrada, x e y en este caso y lo que queramos hacer con esas variables, f(x,y). Por ejemplo, esta función:


@(x) strsplit(x,'*Element')

Coge un texto x y lo parte por donde ponga *Element.

Hasta aquí lo que he aprendido sobre las funciones anónimas hoy, como veis son una herramienta interesante pero que nos obliga a ver el problema desde otro punto de vista.

NOTA: estas cosillas las subo a Github así que podéis hurgar si queréis aquí