Jmol English Français Nederlands Español Inicio | Páginas de demostración | Sitios web
Documentación | Wiki | Historia | Preguntas frecuentes
Verificación del navegador | Descarga | Páginas del proyecto

Notas técnicas de Jmol

Motor gráfico
¿Qué ocurre con el suavizado?
Sin asignación de memoria de pila durante el ciclo de redibujo
Representaciones de números reales
Tecnologías de mejora del navegador
Flotantes frente a dobles

Motor gráfico

El motor gráfico de Jmol está escrito completamente en Java. No hay Java3D, OpenGL ni ningún tipo de aceleración por hardware.

El motor gráfico no es una biblioteca de gráficos 3D general, sino que está especializado, se construyó específicamente para mostrar moléculas. Por ello es muy eficaz dibujando esferas y cilindros.

Se trata de una implementación de un z-buffer completamente mediante software. Hay un int[] pixelBuffer que guarda los valores ARGB y un short[] zBuffer que guarda la profundidad de píxeles en ese punto.

Durante el ciclo de redibujado, se genera la pantalla completa en ese pixelBuffer. Luego se dibuja la escena completa como una sola imagen en una sola operación Graphics.drawImage(...).

No se usa una lista de representación de mallas triangulares; eso sería muy lento. En su lugar, hay rutinas optimizadas para trazar esferas y cilindros.

Si ves la posibilidad de mejorar la velocidad de trazado, por favor háznoslo saber.

¿Qué ocurre con el suavizado?

El suavizado de bordes (anti-aliasing) está desactivado en Jmol. La mayoría del mecanismo ya está ahí, pero por ahora está desactivado. Esto se debe a problemas de rendimiento en el hardware antiguo. Planeamos completar su implementación y reactivarlo en una futura versión ... cuando tegamos más tiempo para averiguar cómo manejarlo en equipos antiguos.

El motor gráfico 3D de Jmol se ha implementado completamente mediante software. No puede usar las llamadas internas de gráficos Sun 2D debido a que no ofrecen la funcionalidad zBuffer para decidir píxel a píxel si se debe dibujar cada píxel.

La técnica de suavizado de bordes usada en el motor gráfico de Jmol se denomina suavizado de escena completa (full-scene-anti-aliasing). Se representa la escena completa en una memoria intermedia que es dos veces más ancha y dos veces más alta. Luego se convierten 4 píxeles en uno, mezclando adecuadamente los valores RBG.

El resultado final es que requiere más memoria mantener el zBuffer y el pixelBuffer, y muchos más ciclos CPU para representar una escena. La parte de dibujo lleva 4 veces más tiempo. En conjunto, se necesita probablemente 3 veces más tiempo para representar una escena.

En los ordenadores más recientes, con más que suficiente potencia de cálculo, probablemente esto no sea un problema, pero en equipos antiguos sería inaceptable. Por ello, necesitamos habilitar unas opciones.

Sin asignación de memoria de pila durante el ciclo de redibujo

Jmol no asigna memoria de pila (heap memory) durante el ciclo de redibujo. Por razones de eficiencia, es importante que continuemos siguiendo este criterio.

[Dave leyó un borrador de este memorando y dio permiso para usar su código como ejemplo]

Revisando el código aportado por Dave para cintas/malla, vi algo que merece discutirse.

Para ser claro, Dave ha escrito un código excelente. Pero con una pequeña modificación podemos asegurar una eficiencia óptima. Voy a usar este código como ejemplo para advertir de cuestiones de asignación de memoria en Jmol.

Para dibujar las cintas, Dave necesitaba dos matrices de objectos Point3i que contuvieran las coordenadas en pantalla de los bordes de sus cintas. Por ello él asigna las matrices y las rellena con nuevos objetos Point3i. Se calcula todo, se dibuja y aparecen en la pantalla unas bonitas cintas.

Entonces los objetos temporales se descartan. Y ahí reside un pequeño problema: hay objetos temporales que están siendo asignados y eliminados durante el ciclo de redibujo.

¿Por qué es un problema?

Bien, los ciclos de redibujo pueden tener lugar bastante rápido, probablemente 30 veces por segundo durante las rotaciones. Por ello, si estamos asignando objetos sobre la pila [usando new SomeObject(...)] podemos terminar asignando muchos de ellos en poco tiempo.

Realmente, el problema no está en la asignación, sino en la *desasignación*; estamos descartando los objetos inmediatamente. Estos objetos descartados ponen una carga innecesaria sobre el recolector de basura de Java, que se ve obligado a recorrer la memoria buscando estructuras de datos descartadas.

Cuando el recolector de basura se ejecuta, puede en ocasiones generar pausas en la respuesta del sistema ... una mala cosa.

Por tanto, deberíamos atacar este problema haciendo un esfuerzo para 'reciclar' los objetos en memoria durante el ciclo de redibujo.

Podemos conseguir esto asociando los objetos temporales con elementos de las clases Renderer. Podemos solicitar a Renderer elementos para que nos asigne o almacene los objetos temporales, y reutilizar los mismos temporales cada vez a lo largo del ciclo de redibujo.

Es interesante señalar que hay otras partes del sistema donde esta pauta no es realmente aplicable. Por ejemplo, durante las operaciones de entrada o salida podemos libremente asignar y descartar casi tanta basura como queramos. Durante estas operaciones necesitamos hacer mucha interpretación de texto. Ésta genera muchas cadenas de caracteres temporales que tienen vidas muy cortas. Esto está bien porque realmente no leemos archivos con tanta frecuencia y porque los usuarios esperan que ésa sea una operación relativamente lenta.

Representaciones de números reales

Alguien ha planteado la cuestión siguiente, que creo puede ser de interés general.

Con respecto a la visualización de parámetros de la celda cristalina:

      > En algunos casos los valores a, b o c se muestran con decimales 'extra';
      > por ejemplo, la versión 10pre8 de la miniaplicación muestra a=10.436999 mientras que 
      > el registro CRYST1 del archivo pdb tiene el valor 10.437. Presumiblemente esto sea
      > una anomalía en el redondeo durante los cálculos de las coordenadas de la celda.
    
En realidad, este caso en concreto es algo más sutil. No era realmente un problema de redondeo, pues no se había realizado ningún cálculo.

Pero sigue siendo un problema. La fuente de este problema tiene interés general para aquéllos que trabajan con números reales (o de 'coma flotante').

Estamos habituados a trabajar en base 10 (tenemos 10 dedos). De vez en cuando, nos topamos con números racionales que no se pueden representar en base 10. Quizás los ejemplos más comunes sean 1/3 y 2/3. Los escribimos como 0.33 o 0.67, o bien los extendemos unos cuantos dígitos más (0.33333 0.66667) si necesitamos más precisión en nuestros cálculos.

Bien, llegamos al mismo problema en el mundo de la computación. Y la gente ha estado peleando con las maneras de atacar este problema desde los comienzos de los ordenadores digitales.

La mayoría de ordenadores actuales utilizan generalmente una representación de coma flotante definida en 1985 por el organismo normalizador IEEE: IEEE Std 754-1985 IEEE Standard for Binary Floating-Point Arithmetic . Ésta es una representación en 'base 2' (binaria) de los números reales, no una representación en 'base 10'. Básicamente, esto significa que hay un juego diferente de números racionales que no se pueden representar con exactitud.

En este caso, no hubo ningún cálculo sobre el número 10.437, que se leyó directamente del archivo. Pero este número 10.437 no se puede representar exactamente en binario, por lo que terminamos con 10.436999 (no he verificado esto realmente, pero asumo que es lo que ocurre).

Otros hechos aleatorios:

  • COBOL admitía números decimales y de coma fija para tratar con este problema en el caso de dólares y centavos en un entorno de negocio.
  • Una de las representaciones en los macrocomputadores IBM era base 16 (en lugar de base 2). Aunque esto no resolvía este problema en particular, sí proporcionaba un rendimiento más rápido (durante el proceso de 'normalización').
  • Quienes quieren alto rendimiento, generalmente no siguen la norma IEEE.
  • La especificación inicial de la máquina virtual Java *requería* la representación IEEE (y su comportamiento operativo) para los números de coma flotante. Esto aseguraría la portabilidad entre plataformas; el mismo cálculo debería dar el mismo resultado en sistemas diferentes. Este requisito se ha relajado algo desde entonces, para permitir un cálculo de mayor rendimiento y debido a la aceptación de que es un problema irresoluble.
  • Creo que la mayoría de la gente está de acuerdo en que la norma IEEE tiene errores, pero debemos seguirla.
  • Los sistemas dedicados a matemáticas simbólicas o puras (Mathematica, MATLAB, Macsyma) admiten números racionales (la representación fraccional con enteros: 1/3, 2/3) para intentar evitar este tipo de problema con los números racionales.

Tecnologías de mejora del navegador

Intentaré hacer un breve resumen de las cuatro técnicas diferentes que se pueden usar para añadir funcionalidad al navegador. Es importante que usemos las terminología correcta para evitar confusiones.

Ordenadas de la más simple a la más compleja:

Aplicación auxiliar

Recibe este nombre una aplicación -un programa- normal que es ejecutada automáticamente cuando el navegador recibe un archivo que no sabe cómo gestionar. El tipo de tal archivo se identifica mediante algo llamado su 'tipo MIME'.

Veamos un ejemplo usando Netscape o Mozilla recién instalados. (Nos centramos en Netscape/Mozilla porque Internet Explorer tiene algunas capacidades 'especiales' para otros productos de Microsoft).

La primera vez que Mozilla recibe un archivo .doc con un tipo mime 'application/msword' no sabe qué hacer con el archivo. Sabe que el archivo no es de tipo 'text/html' o 'image/jpeg', por lo que no sabe cómo gestionarlo de forma nativa.

En consecuencia, Mozilla pregunta al usario si quiere guardar el archivo o bien abrirlo con algún programa. Si el usario elige un programa, puede también elegir que en lo sucesivo se abra ese programa siempre que se encuentre un archivo del mismo tipo mime.

Cada navegador tiene su tabla de 'asociaciones' entre tipos mime y programas (aunque la tabla de Safari parece estar bien escondida).

Una aplicación auxiliar puede ser cualquiera, incluyendo el programa autónomo Jmol.

Debe hacerse notar que para que este sistema funcione correctamente, el servidor web debe estar configurado para enviar el tipo mime correcto. Normalmente, esto no es problema para los programas habituales. Sin embargo, sí es un problema para tipos de archivo menos conocidos en servidores web con administradres de sistema noveles ... como suele ser el caso para la gente que quiere elaborar y ofrecer páginas web con Chime.

Miniaplicación (applet) no confiable o no firmada

Se trata de una miniaplicación Java incrustada en una página web. La mayoría de las miniaplicaciones no confiables son bastante pequeñas y se descargan con rapidez, sin que el usuario se dé cuenta realmente. Hay, por ejemplo, pequeños sistemas de menú, juegos, etc.

Este tipo de miniaplicación es 'no confiable' en el sentido de que procede de un servidor web cualquiera en un sitio cualquiera de internet. En consecuencia, realmente no tenemos por qué confiar en ella. Por lo tanto, las miniaplicaciones no confiables se colocan bajo una estricta seguridad. No pueden leer ni escribir en el disco duro local y sólo pueden comunicarse con el servidor web del que vinieron. Si intentan hacer otra cosa, se las interrumpe rápidamente.

JmolApplet es una miniaplicación no confiable ... más grande y más compleja de lo habitual para la mayoría.

Miniaplicación (applet) confiable o firmada

Las restricciones de seguridad impuestas sobre una miniaplicación no confiable son bastante severas, y la gente quiere desarrollar programas basados en la web que puedan hacer cosas más interesantes, tales como grabar archivos al disco duro local.

Antes de que una miniaplicación de este tipo se ejecute, el navegador solicita permiso explícitamente al usuario para ejecutar la miniaplicación. Al contestar que sí, el usario básicamente está dando permiso para que el software se instale en el disco duro local.

Para proteger a todos, una miniaplicación confiable se *firma* con una firma digital cifrada. El cifrado asegura también que el código de la miniaplicación no ha sido modificado o alterado por una tercera persona.

Una 'autoridad certificadora' es un organismo en el que confías para que haga la verificación.

A partir de la versión preliminar 10.00.12 (incluyendo 10.2 y 11), Jmol incluye un JmolApplet 'firmado' (JmolAppletSigned.jar), aunque no está respaldada por ninguna 'autoridad certifcadora'.

Cuando un usuario visite una página web que tiene la miniaplicación firmada JmolAppletSigned, se le preguntará si confía en dicha miniaplicación. Si contesta que sí, la sesión continuará.

La JmolAppletSigned que se instale entonces en su disco duro podrá leer y escribir archivos en el propio disco duro. También podrá leer y escribir datos de y en otros sitios cualesquiera de internet.

Eso dará a la miniaplicación mucha más libertad de acción para hacer cosas interesantes, tales como leer archivos locales de modelos moleculares o extraer archivos directamente desde las bases de datos en internet.

Cabe mencionar que esta miniaplicación firmada sigue siendo una miniaplicación que sólo existe en el contexto de una página web, no es un programa que pueda ser ejecutado a voluntad.

Un usario no puede ejecutar la miniaplicación a no ser que ésta sea parte de una página web a la que tenga acceso. Sin embargo, esto incluye las páginas web procedentes de un CD-ROM y las almacenadas en un sistema de archivos local.

La miniaplicación firmada se ofrece para conveniencia de algunos usuarios. No obstante, queremos mantener la miniaplicación no firmada para quienes deseen elaborar páginas más sencillas que no soliciten permiso para escribir en el disco duro local.

Me gustaría que la miniaplicación no firmada (JmolApplet) sea ligera y básica, con funcionalidad limitada, pero con una buena prestación para simplemente mostrar moléculas a los estudiantes que comienzan y a los visitantes casuales.

La miniaplicación firmada (JmolAppletSigned) es para usuarios más avanzados que quieran mayor funcionalidad.

Conector (plug-in)

Para entender un conector es útil recordar la aplicación auxiliar. Ésta no está asociada con una página web concreta, sino con un determinado tipo de archivo, un tipo mime específico. Por ejemplo, el navegador web abrirá MS Word cada vez que se encuentre con un documento cuyo tipo mime sea 'application/msword'.

Un conector funciona de manera similar, pero los datos se muestran incrustados en la ventana del navegador. De algún modo, es software que amplía las capacidades del navegador. No importa de dónde vengan los archivos. Cuando el navegador encuentra un tipo mime no nativo puede verificar su propia lista de conectores instalados para ver si alguno de ellos lo puede gestionar.

Dos ejemplos frecuentes son Flash y Adobe Reader. La gente normalmente los instala una vez y no se vuelve a preocupar de ellos.

Una vez que un conector se ha instalado, puede hacer cualquier cosa, al igual que otro tipo de programa instalado.

Desarrollar y mantener conectores es muy costoso. Aunque Netscape definió una interfaz de programación (API) para ellos, la realidad es que el comportamiento dinámico de cada navegador en cada plataforma es diferente. Además, muchos navegadores implementan o admiten el API de conectores de Netscape, pero son implementaciones distintas y se comportan de modo diferente. El principal problema es que se intenta tomar un elemento de software complicado (el conector) e incrustarlo dentro de otro elemento de software complicado (el navegador web), junto con otros conectores. Y, en general, están compartiendo la misma memoria y algunas estructuras de datos. Por ello, cuando alguno comete un error las cosas tienden a fallar.

Según estoy escribiendo esto, queda bien claro que jamás existirá un conector Jmol.

Eso es todo por ahora.

Flotantes frente a dobles

Varias personas han preguntado por qué el código de Jmol usa números en coma flotante en lugar de números de precisión doble. De hecho, es probable que entre los programadores jóvenes de Java muchos nunca hayan visto un programa que use tantos flotantes.

La respuesta es que son más pequeños: los flotantes usan 4 bytes mientras que los dobles usan 8 bytes. Y, a pesar de ello, ofrecen suficiente intervalo y precisión para nuestros propósitos.

¿Por qué es importante que sean más pequeños? Posiblemente opines que la memoria es barata y, en general, tienes razón.

Sin embargo, Jmol necesita ejecutarse en forma de miniaplicación en la versión 1.1 de las máquinas virtuales de Java, donde la cantidad de memoria virtual es algo inferior.

Lo que es más importante, el ancho de banda de la memoria nunca es barato. Los fabricantes de procesadores hacen todo lo que pueden para diseñar memorias caché, con el fin de aumentar el ancho de banda efectivo. En consecuencia, al trabajar con los flotantes de 4 bytes en lugar de con los dobles de 8 bytes, hacemos un uso más eficaz del sistema de memoria, es decir, de las varias capas de caché y ancho de banda global de la memoria. Conseguimos almacenar más datos en una caché de tamaño fijo y leer más datos de la memoria cada vez que accedemos a la caché.

Francamente, es igual de sencillo usar flotantes, y no hay razón para derrochar.



Alojado en SourceForge Logo