55
DV-Anwendungen in der Technik (Prof. Dr. Gleich) SS 2005 3. Leistungsnachweis Thomas Wöllert ([email protected]) Studiengruppe 8T Matrikel-Nr.: 05478901 Stefan Weißbach ([email protected]) Studiengruppe 8T Matrikel-Nr.: 06138801

DV-Anwendungen in der Technik · Abgeleitet von FEMCalc, überschreibt die Methode compilation() um die Gesamtsteifigkeitsmatrix mittels Gauss-Quadratur-Verfahren zu kompilieren

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

DV-Anwendungen in der Technik(Prof. Dr. Gleich)

SS 2005

3. Leistungsnachweis

Thomas Wöllert([email protected])

Studiengruppe 8TMatrikel-Nr.: 05478901

Stefan Weißbach([email protected])Studiengruppe 8T

Matrikel-Nr.: 06138801

1 Teil 1: Generierung von FEMIN-Dateien

1. Schreiben Sie ein kleines Programm, dass die Belegung der Gesamtsteifigkeitsmatrixirgendwie grafisch darstellt

UnterJavaist die Darstellung von Fenstern relativ leicht zu bewerkstelligen. Um das ganzemodular für alleMatrix Klassen nutzbar zu machen schrieben wir eine eigene KlasseMatrixPanel, die sich vonJPanelableitet.

Dies ermöglicht uns dieses Panel überall in derSwingKomponente von Java einzubauen. Beider Erzeugung dieses Panels wird einBufferedImagemit der Grösse der Matrix erzeugt.Hierbei entspricht ein Pixel genau einer Stelle in der Matrix, was uns ermöglicht die Belegungder jeweiligen Matrix durch verschiedenfarbige Punkte darzustellen. Ein schwarzer Punktbedeutet hierbei, dass sich an dieser Stelle in der Matrix ein Wert ungleich Null befindet.

Damit diesesBufferedImageauch korrekt bei verschiedenen Fenstergrössen angezeigt wird,mussten wir nur noch diepaintComponent(Graphics)Methode in unserer Panel Klasseumschreiben, welche automatisch beim Anzeigen des Panels auf dem Bildschirm von derJavaVM aufgerufen wird. Dort benutzen wir ein Objekt der KlasseAffineTransform, welches unsdabei hilft das schon bestehendeBufferedImagenach unseren wünschen zu transformieren.

Schliesslich ergänzten wir in der KlasseFEMStartupnoch eine statische Methode die es unsermöglicht eine Matrix von irgendwo im laufenden Programm heraus anzeigen zu lassen.Hierbei wird einfach das bestehendeMatrixPanelzu einemJava JFrameObjekt hinzugefügtund dieses angezeigt.

Durch die Änderungen am bestehenden Programm wurde folgende Klasse betroffen:

• FEMStartupNeue statische MethodedisplayMatrix(Matrix).

Folgende Klasse wurde neu erstellt:

• MatrixPanelAbgeleitet vonJPanel, kümmert sich um die Erzeugung des Bildes der Matrixbelegung.

Anhang zu Teil 1.1Anhang 1.1.A - Beispiel einer unoptimierten GesamtsteifigkeitsmatrixAnhang 1.1.B - Beispiel einer durch Cuthill-McKee optimierten GesamtsteifigkeitsmatrixSource Teil 1.1 - Relevanter Quellcode zu diesem Teil

2

1.1 Anhang zu Teil 1.1

1.1.1 Anhang 1.1.A - Beispiel einer unoptimierten Gesamtsteifigkeitsmatrix

MatrixPanelDarstellung der Gesamtsteifigkeitsmatrix (ohne Cuthill-McKee) (ein Punktbedeutet ein Wert ungleich Null)

3

1.1.2 Anhang 1.1.B - Beispiel einer durch Cuthill-McKee optimiertenGesamtsteifigkeitsmatrix

MatrixPanelDarstellung der Gesamtsteifigkeitsmatrix (mit Cuthill-McKee) (ein Punkt bedeutetein Wert ungleich Null)

4

Source Teil 1.1

FEMStartup[...]

/** * Display the given Matrix in a panel * @param m, the matrix to display */public static void displayMatrix(Matrix m) { JFrame frame = new JFrame("Matrix - Name: " + m.getName() + " Size: " + m.size() + "x" + m.size()); MatrixPanel mPanel = new MatrixPanel(m); frame.setSize(300, 300); frame.add(mPanel); frame.setVisible(true); }

[...]

MatrixPanel/** * Munich University of Applied Sciences, FB07 Computer Science * DV-Anwendungen in der Technik - Prof.Dr.Gleich - 7.Semester * * Class Description: * This class is an extension of JPanel to make a Matrix * displayable to the user * * @author Thomas Woellert ([email protected]) * @author Stefan Weissbach ([email protected]) * * System: Linux 2.6, Sun Java JDK 5.0 * Semestergroup: 7T */package fhm.edu.fem.calc.objects.matrix;

import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.LayoutManager;import java.awt.geom.AffineTransform;import java.awt.image.BufferedImage;

import javax.swing.JPanel;

public class MatrixPanel extends JPanel {

// The Matrix which we paint protected Matrix matrix = null; // The Background color protected Color backgroundColor = Color.WHITE; // The Draw color protected Color drawColor = Color.BLACK; // The image we draw into protected BufferedImage matrixImage = null; /** * Create a new MatrixPanel * @param matrix, the matrix to display */ public MatrixPanel(Matrix matrix) { super(); this.matrix = matrix; this.setBackground(backgroundColor); this.createImage(); } /** * Create a new MatrixPanel * @param matrix, the matrix to display * @param isDoubleBuffered */ public MatrixPanel(Matrix matrix, boolean isDoubleBuffered) { super(isDoubleBuffered); this.matrix = matrix; this.setBackground(backgroundColor); this.createImage(); } /** * Create a new MatrixPanel * @param matrix, the matrix to display * @param layout */ public MatrixPanel(Matrix matrix, LayoutManager layout) { super(layout); this.matrix = matrix; this.setBackground(backgroundColor); this.createImage(); } /** * Create a new MatrixPanel * @param matrix, the matrix to display * @param layout * @param isDoubleBuffered */ public MatrixPanel(Matrix matrix, LayoutManager layout, boolean isDoubleBuffered) { super(layout, isDoubleBuffered); this.matrix = matrix; this.setBackground(backgroundColor); this.createImage(); } /**

* Paint the Panel * @param g, the graphics we are allowed to draw into */ protected void paintComponent(Graphics g) { // Call the super paint method of the JPanel super.paintComponent(g); // Create the graphics2D object Graphics2D g2 = (Graphics2D)g; AffineTransform transform = new AffineTransform(); // Check if we need to scale the image if(this.getHeight() != this.matrix.size() || this.getWidth() != this.matrix.size()) { // We need to apply the affine transform, calculate the scale factors double xScale = (double)(this.getWidth()) / (double)(this.matrix.size()); double yScale = (double)(this.getHeight()) / (double)(this.matrix.size()); // Apply the scale factors transform.scale(xScale, yScale); } g2.setTransform(transform); g2.drawImage(this.matrixImage, 0, 0, this); } /** * Create and draw the image */ protected void createImage() { // Create the image int matrixSize = this.matrix.size(); this.matrixImage = new BufferedImage(matrixSize, matrixSize, BufferedImage.TYPE_3BYTE_BGR); Graphics2D g2 = this.matrixImage.createGraphics(); // Clear the background of the graphic g2.setPaint(this.backgroundColor); g2.fillRect(0, 0, matrixSize, matrixSize); // Draw the matrix g2.setPaint(this.drawColor); for(int row = 1; row <= matrixSize; row++) { for(int col = 1; col <= matrixSize; col++) { // Check if there is an item at this location if(this.matrix.getValue(row, col) != 0) { // Draw the current point representing a value != 0 g2.fillRect(row, col, 1, 1); } } } }}

2.Netzverfeinerung und Optimierung der Knoten-Nummerierung: Verwenden Sie alsGrundeinteilung (= Ausgangs-FEMIN-Datei) die Ergebnisdatei vom Teil 2 Ihres2.Leistungsnachweises (= Ihr Beispiel ’Umströmung eines Kreises’ mit krummlinigenElementen).

2.1 Verfeinern Sie diese Netzeinteilung (z.B. mit dem Programm fem-splitter von FlorianSchmidt) so oft bis Sie mehr als 1000 Elemente haben.

2.2 Verbessern Sie diese Knoten-Nummerierung mit einem Cuthill-McKee-Programm (z.B.ebenfalls fem-splitter). - Berechnen Sie den Vektor der Diagonalzeiger und ermitteln Sie denSpeicherplatzgewinn der Hüllenstruktur im Vergleich zur quadratischen Abspeicherung derGesamtsteifigkeitsmatrix.

Die verfeinerte Netzeinteilung enthielt bei uns am Ende 2155 Knoten (inkl. Zwischenknoten)und 1026 Elemente (1016 Vierecke und 10 Dreiecke). In der folgenden Tabelle finden Sie dieGegenüberstellung des Speicherplatzverbrauchs von hüllenorientierter und quadratischerSpeicherungsform:

in Bytes quadratische Speicherungsformhüllenorientierte Speicherungsformohne Cuthill-McKee 37.152.200 14.583.492mit Cuthill-McKee 37.152.200 962.820

Hier der prozentuale Speicherplatzgewinn abhängig von den oben angegebenen Grössen:

in Prozent quadratische Speicherungsformhüllenorientierte Speicherungsformohne Cuthill-McKee 0% 60.75%mit Cuthill-McKee 0% 97.41%

Hier ist ganz klar zu erkennen, dass bereits bei einer Belegung, die nicht durch denCuthill-McKee Algorithmus optimiert worden ist, eine 60 prozentige Verbesserung desSpeicherplatzverbrauchs bei der Gesamtsteifigkeitsmatrix eintritt, wenn man diehüllenorientierte Speicherungsform benutzt. Noch viel durchschlagender wird das Ergebnis beieiner durch Cuthill-McKee optimierten Knotennummerierung, wie in der Tabelle ersichtlich.

Sobald die hüllenorientierte Speicherungsform verwendet wird dauert zwar die Kompilationetwas länger, aber dies wird leicht durch den Speicherplatzgewinn wieder wett gemacht.Ebenso spart man sich später während der eigentlichen Berechnung der Ergebnisse wiedereiniges an Zeit, da viele Null-Werte einfach nicht mehr durchlaufen werden müssen.

Anhang zu Teil 1.2Anhang 1.2.A - Belegung der nicht durch Cuthill-McKee optimierten GesamtsteifigkeitsmatrixAnhang 1.2.B - Belegung der durch Cuthill-McKee optimierten Gesamtsteifigkeitsmatrix

7

1.2 Anhang zu Teil 1.2

1.2.1 Anhang 1.2.A - Belegung der nicht durch Cuthill-McKee optimiertenGesamtsteifigkeitsmatrix

MatrixPanelDarstellung der Gesamtsteifigkeitsmatrix (ohne Cuthill-McKee) (ein Punktbedeutet ein Wert ungleich Null)

8

1.2.2 Anhang 1.2.B - Belegung der durch Cuthill-McKee optimiertenGesamtsteifigkeitsmatrix

MatrixPanelDarstellung der Gesamtsteifigkeitsmatrix (mit Cuthill-McKee) (ein Punkt bedeutetein Wert ungleich Null)

9

2 Teil 2: Ebene Potentialströmung: Verwendungkrummliniger Elemente

Modifizieren Sie ihr FEM-Programm vom 1.Leistungsnachweis, Teil 3, nach folgendenGesichtspunkten:

Verwenden Sie statt der geradlinigen Dreiecke krummlinige Dreiecke und statt derParallelogramme krummlinige Viereckelemente (’krummlinig’: drei Knotenpunkte proElementseite).

Erstellen Sie zwei Programmversionen (bzw. ein Programm mit zwei Versionen):(A) Speicherung der Gesamtsteifigkeitsmatrix in quadratischer Form(B) Speicherung der Gesamtsteifigkeitsmatrix in hüllenorientierter Form

Verwenden Sie für die numerische Integration - wie im zweiten Leistungsnachweis - auch hierzwei verschiedene Stützstellenpaare:(I) je 4 Stützstellen für das innere und für das äussere Integral(II) 8 Stützstellen für das innere und 6 Stützstellen für das äussere Integral

Die Vorgehensweise der Berechnung ändert sich nur im Bereich der Kompilation derGesamtsteifigkeitsmatrix. Daher haben wir einfach eine neue Klasse namensFEMCalcGausserzeugt, welche sich von der bisherigen KlasseFEMCalcableitet. Diese KlasseFEMCalcwarbisher für den Ablauf aller Berechnungen verantwortlich. Da wir die verschiedenen Teile derBerechnung in unterschiedliche Methoden gegliedert hatten, mussten wir in der neuen KlasseFEMCalcGaussnun nur noch die Methodecompilation()der MutterklasseFEMCalcüberschreiben.

Danaben wurde die KlasseFEMStartupauch noch um eine Unterscheidung erweitert, die esermöglicht zu bestimmen ob nun die normaleFEMCalcoder die neueFEMCalcGaussbenutztwird. Wir haben dies so umgesetzt, dass Ansätze vom TypFEM 2mit der alten KlasseFEMCalcberechnet werden. Ansätze vom TypFEM 3 jedoch mit der neuen Klasse.

In der KlasseApplicationConstantskann zwischen der quadratischen und der hüllenorientiertenSpeicherungsform mittels der KonstanteMATRIX_USEgewählt werden (entwederMATRIX_STANDARDoderMATRIX_HULL). Die Anzahl der verwendeten Stützstellen bei derIntegration kann in der KlasseFEMCalcGaussmittels der KonstantenINNER_POINTS(inneres Integral) undOUTER_POINTS(äusseres Integral) eingestellt werden.

Durch die Änderungen am bestehenden Programm wurde folgende Klasse betroffen:

• FEMStartupIm Konstruktor wird nun die Unterscheidung durchgeführt welche Art der Berechnungerfolgen soll.

10

Folgende Klassen wurde neu erstellt:

• FEMCalcGaussAbgeleitet vonFEMCalc, überschreibt die Methodecompilation()um dieGesamtsteifigkeitsmatrix mittels Gauss-Quadratur-Verfahren zu kompilieren.

• CompilationFunctionsDiese Klasse beinhaltet sämtliche statischen Methoden, die wir während der Integrationmittels Gauss-Quadratur-Verfahren abhängig vom Elementtyp und Ansatz benötigen.

Anmerkung zum abgedruckten Quellcode zu dieser Aufgabe:In der KlasseFEMStartupfinden Sie bereits Andeutungen auf die Temperaturberechnung imTeil 3 dieses Leistungsnachweises.

1. Grundeinteilung von Teil 1

1.1 Berechnen Sie mit jeder der beiden Programmversionen (A) bzw. (B) und jeweils mit demStützstellenpaar (I) und (II) (Näherungswerte für die) Strom- und Potentialfunktion.

Anhang zu Teil 2.1.1Source Teil 2.1 - Relevanter Quellcode zu diesem Teil

11

Source Teil 2.1

FEMStartup/** * Construct a new startup object * @param femInputFile, the File object representing the input file * @param femOutputFile, the File object representing the output file * @param showCompleteStiffnessMatrix, true if the complete-stiffness-matrix should be displayed, false otherwise */public FEMStartup(File femInputFile, File femOutputFile, boolean showCompleteStiffnessMatrix) {

// Load the file FEMManager.getInstance().load(femInputFile);

// Create the Calculation object FEMCalc calc = null;

// Check which way of compilation we need to use if(FEMManager.getInstance().getFEMApproach() == 2) {

// Check if we have any CTabs and need to calculate temperature-stuff

if(FEMManager.getInstance().getCTabList().size() > 0) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "CTabs Found ! Temperature !"); localLogger.log(Level.INFO, "Forcing Compilation: B-VECTOR via GAUSS"); } // Temperature calculations calc = new FEMCalcTemperature(); } else { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "No CTabs found !"); localLogger.log(Level.INFO, "Using Compilation: STANDARD"); } // Standard way of compilation using S-Matrices calc = new FEMCalc(); }

} else if(FEMManager.getInstance().getFEMApproach() == 3) {

// Check if we have any CTabs and need to calculate temperature-stuff if(FEMManager.getInstance().getCTabList().size() > 0) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "CTabs Found ! Temperature !"); localLogger.log(Level.INFO, "Forcing Compilation: B-VECTOR via GAUSS"); } // Temperature calculations calc = new FEMCalcTemperature(); } else { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "No CTabs found !"); localLogger.log(Level.INFO, "Using Compilation: GAUSS_QUADRATURE"); } // Compilation via Gauss calc = new FEMCalcGauss(); }

} else {

// Unknown required compilation if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Unknown required way of compilation: "); } FEMStartup.abort(false); }

[...]

FEMCalcGauss/** * Munich University of Applied Sciences, FB07 Computer Science * DV-Anwendungen in der Technik - Prof.Dr.Gleich - 7.Semester * * Class Description: * This class extends from the normal FEMCalc class taking care * of the whole calculation. The difference is that in this class * we perform the compilation of the complete-stiffness-matrix with * the Gauss-Quadrature-Integration. * * @author Thomas Woellert ([email protected]) * @author Stefan Weissbach ([email protected]) * * System: Linux 2.6, Sun Java JDK 5.0 * Semestergroup: 7T */package fhm.edu.fem.calc;

import java.lang.reflect.Method;

import org.apache.log4j.Level;

import fhm.edu.fem.calc.objects.CompilationFunctions;import fhm.edu.fem.calc.objects.Element;import fhm.edu.fem.calc.objects.ElementList;import fhm.edu.fem.calc.objects.MathObject;import fhm.edu.fem.calc.objects.Node;import fhm.edu.fem.calc.objects.NodeList;import fhm.edu.fem.calc.objects.Vector;import fhm.edu.fem.calc.objects.matrix.Matrix;import fhm.edu.fem.constants.ApplicationConstants;import fhm.edu.fem.constants.GaussConstants;

public class FEMCalcGauss extends FEMCalc {

/* Inner and Outer Points ("Stuetzstellen des inneren und aeusseren Integrals") */protected static int INNER_POINTS = 8;protected static int OUTER_POINTS = 6;

/** * Do the compilation with the Gauss-Quadrature-Integration * @return true if all went well, false otherwise */ protected boolean compilation() { try { // Grab the approach from the manager int femApproach = femManager.getFEMApproach(); // Grab the list of all elements ElementList elementlist = femManager.getElementList(); // The variables to use in the Gauss Quadrature Method call double a = 0; double b = 1; Method h1 = null; Method h2 = null; Method q = null; int z1 = -1; int z2 = -1; Vector ax = GaussConstants.get(INNER_POINTS, GaussConstants.VALUE_A); Vector hx = GaussConstants.get(INNER_POINTS, GaussConstants.VALUE_H); Vector ay = GaussConstants.get(OUTER_POINTS, GaussConstants.VALUE_A); Vector hy = GaussConstants.get(OUTER_POINTS, GaussConstants.VALUE_H); MathObject firstIntegralResultObject = null; MathObject secondIntegralResultObject = null; // Calculate how many percentage one element makes up double oneElementPercentage = 100.0 / elementlist.size(); // Calculate how many elements make up one percent double onePercentElements = elementlist.size() / 100.0; // Where we store the current actual percentage double currentPercentage = 0.0; // Run through all elements for(int elementIndex = 1; elementIndex <= elementlist.size(); elementIndex++) { // Calculate the current percentage of elements already done in the compilation currentPercentage = (elementIndex-1) * oneElementPercentage;

// Make a percentage output about every 5% of completed elements if(elementIndex%(onePercentElements*5.0) < 1) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Compilation at " + currentPercentage + " %"); } }

// Get the current element Element tmpElement = elementlist.getElement(elementIndex); // Store the x- and y-values of the element's nodes in the static data structure in the Class CompilationFunctions CompilationFunctions.storeElementXYValues(tmpElement);

NodeList nodeList = tmpElement.getNodeList(); int elementType = -1; // Take a look which kind of element we have here and fill the input variables for the integration accordingly if(nodeList.size() == 6) { // Triangle h1 = CompilationFunctions.getMethod(CompilationFunctions.TRIANGLE_QUADRATIC_H1); h2 = CompilationFunctions.getMethod(CompilationFunctions.TRIANGLE_QUADRATIC_H2); q = CompilationFunctions.getMethod(CompilationFunctions.TRIANGLE_QUADRATIC_JACOBI); z1 = 6; z2 = 6; elementType = GaussConstants.FIGURE_TRIANGLE; } else if(nodeList.size() == 8) { // Quadrat h1 = CompilationFunctions.getMethod(CompilationFunctions.QUADRAT_QUADRATIC_H1); h2 = CompilationFunctions.getMethod(CompilationFunctions.QUADRAT_QUADRATIC_H2); q = CompilationFunctions.getMethod(CompilationFunctions.QUADRAT_QUADRATIC_JACOBI); z1 = 8; z2 = 8; elementType = GaussConstants.FIGURE_PARALLELOGRAM; } // Calculate the first integral firstIntegralResultObject = FEMGaussQuadrature.calcIntegration(a, b, h1, h1, q, z1, z1, ax, hx, ay, hy, elementType); // Calculate the second integral secondIntegralResultObject = FEMGaussQuadrature.calcIntegration(a, b, h2, h2, q, z2, z2, ax, hx, ay, hy, elementType); // Check if both result objects of the first and second integral match our requirements if(!(firstIntegralResultObject instanceof Matrix) || !(secondIntegralResultObject instanceof Matrix)) { // At least one of the result objects is not a Matrix => ERROR if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "One of the integral result objects is not a Matrix !"); } return false; } // Combine the first and second integral result objects to one resulting element stiffness matrix Matrix elementStiffnessMatrix = ((Matrix)(firstIntegralResultObject)).add((Matrix)(secondIntegralResultObject)); elementStiffnessMatrix.setName("ElementStiffnessMatrix: " + elementIndex); if(localLogger.isEnabledFor(Level.DEBUG)) { localLogger.log(Level.DEBUG, "ElementStiffnessMatrix for Element " + elementIndex + ": " + elementStiffnessMatrix); } // Run through all nodes in the element to get the index i of the matrix for(int indexA = 1; indexA <= elementStiffnessMatrix.size(); indexA++) { // Grab the nodeID from the first node Node tmpNodeA = nodeList.getNodeInCorrectOrder(indexA); int i = tmpNodeA.getId(); // Determine the starting valueof indexB for the next lines, depending if we use a MATRIX_STANDARD or MATRIX_HULL int startOfIndexB = -1; if(ApplicationConstants.MATRIX_USE == ApplicationConstants.MATRIX_STANDARD) {

// We are using a standard matrix startOfIndexB = 1; } else if(ApplicationConstants.MATRIX_USE == ApplicationConstants.MATRIX_HULL) { // We are using a hull matrix startOfIndexB = indexA; } // Run through all nodes in the element to get the index j of the matrix for(int indexB = startOfIndexB; indexB <= elementStiffnessMatrix.size(); indexB++) { Node tmpNodeB = nodeList.getNodeInCorrectOrder(indexB); int j = tmpNodeB.getId(); // Grab the current value from the element stiffness matrix and add it to the value in the complete stiffness matrix double elementValue = elementStiffnessMatrix.getValue(indexA, indexB); double newValue = this.completeStiffnessMatrix.getValue(i, j) + elementValue; this.completeStiffnessMatrix.setValue(i, j, newValue); } } } if(localLogger.isEnabledFor(Level.DEBUG)) { localLogger.log(Level.DEBUG, "Compilation complete !"); localLogger.log(Level.DEBUG, "Matrix size: " + this.completeStiffnessMatrix.size()); localLogger.log(Level.DEBUG, "CompleteStiffnessMatrix: " + this.completeStiffnessMatrix); } return true; } catch (Exception e) {

if(localLogger.isEnabledFor(Level.ERROR)) {localLogger.log(Level.ERROR, "Failure during compilation!", e);

}

return false; } }}

CompilationFunctions/** * Munich University of Applied Sciences, FB07 Computer Science * DV-Anwendungen in der Technik - Prof.Dr.Gleich - 7.Semester * * Class Description: * Holds all the static function methods needed for the Gauss-Quadrature * Compilation of the Complete Stiffness Matrix used in FEMGaussQuadrature * * @author Thomas Woellert ([email protected]) * @author Stefan Weissbach ([email protected]) * * System: Linux 2.6, Sun Java JDK 5.0 * Semestergroup: 7T */package fhm.edu.fem.calc.objects;

import java.lang.reflect.Method;

import org.apache.log4j.Level;import org.apache.log4j.Logger;

import fhm.edu.fem.exception.FunctionCalculationException;import fhm.edu.fem.util.logging.LoggingManager;

public class CompilationFunctions {

/* Our local logger object */protected static Logger localLogger = LoggingManager.getLogger(CompilationFunctions.class.getName());

/* The method names - For figure Triangle - Linear approach */public static final String TRIANGLE_LINEAR_N = "triangleLinearN";public static final String TRIANGLE_LINEAR_N_XI = "triangleLinearNXI";public static final String TRIANGLE_LINEAR_N_ETA = "triangleLinearNETA";public static final String TRIANGLE_LINEAR_X_XI = "triangleLinearXXI";public static final String TRIANGLE_LINEAR_X_ETA = "triangleLinearXETA";public static final String TRIANGLE_LINEAR_Y_XI = "triangleLinearYXI";public static final String TRIANGLE_LINEAR_Y_ETA = "triangleLinearYETA";public static final String TRIANGLE_LINEAR_JACOBI = "triangleLinearJAC";public static final String TRIANGLE_LINEAR_ONETHROUGHJAC = "triangleLinearJAConeThrough";

public static final String TRIANGLE_LINEAR_H1 = "triangleLinearH1";public static final String TRIANGLE_LINEAR_H2 = "triangleLinearH2";

/* The method names - For figure Triangle - Quadratic approach */public static final String TRIANGLE_QUADRATIC_N = "triangleQuadraticN";public static final String TRIANGLE_QUADRATIC_N_XI = "triangleQuadraticNXI";public static final String TRIANGLE_QUADRATIC_N_ETA = "triangleQuadraticNETA";public static final String TRIANGLE_QUADRATIC_X_XI = "triangleQuadraticXXI";public static final String TRIANGLE_QUADRATIC_X_ETA = "triangleQuadraticXETA";public static final String TRIANGLE_QUADRATIC_Y_XI = "triangleQuadraticYXI";public static final String TRIANGLE_QUADRATIC_Y_ETA = "triangleQuadraticYETA";public static final String TRIANGLE_QUADRATIC_JACOBI = "triangleQuadraticJAC";public static final String TRIANGLE_QUADRATIC_ONETHROUGHJAC = "triangleQuadraticJAConeThrough";

public static final String TRIANGLE_QUADRATIC_H1 = "triangleQuadraticH1";public static final String TRIANGLE_QUADRATIC_H2 = "triangleQuadraticH2";

/* The method names - For figure Quadrat - Linear approach */public static final String QUADRAT_LINEAR_N = "quadratLinearN";public static final String QUADRAT_LINEAR_N_XI = "quadratLinearNXI";public static final String QUADRAT_LINEAR_N_ETA = "quadratLinearNETA";public static final String QUADRAT_LINEAR_X_XI = "quadratLinearXXI";public static final String QUADRAT_LINEAR_X_ETA = "quadratLinearXETA";public static final String QUADRAT_LINEAR_Y_XI = "quadratLinearYXI";public static final String QUADRAT_LINEAR_Y_ETA = "quadratLinearYETA";public static final String QUADRAT_LINEAR_JACOBI = "quadratLinearJAC";public static final String QUADRAT_LINEAR_ONETHROUGHJAC = "quadratLinearJAConeThrough";

public static final String QUADRAT_LINEAR_H1 = "quadratLinearH1";public static final String QUADRAT_LINEAR_H2 = "quadratLinearH2";

/* The method names - For figure Quadrat - Quadratic approach */public static final String QUADRAT_QUADRATIC_N = "quadratQuadraticN";public static final String QUADRAT_QUADRATIC_N_XI = "quadratQuadraticNXI";public static final String QUADRAT_QUADRATIC_N_ETA = "quadratQuadraticNETA";

public static final String QUADRAT_QUADRATIC_X_XI = "quadratQuadraticXXI";public static final String QUADRAT_QUADRATIC_X_ETA = "quadratQuadraticXETA";public static final String QUADRAT_QUADRATIC_Y_XI = "quadratQuadraticYXI";public static final String QUADRAT_QUADRATIC_Y_ETA = "quadratQuadraticYETA";public static final String QUADRAT_QUADRATIC_JACOBI = "quadratQuadraticJAC";public static final String QUADRAT_QUADRATIC_ONETHROUGHJAC = "quadratQuadraticJAConeThrough";

public static final String QUADRAT_QUADRATIC_H1 = "quadratQuadraticH1";public static final String QUADRAT_QUADRATIC_H2 = "quadratQuadraticH2";

/* Helper Method */public static final String ZERO = "zero";public static final String ONE = "one";

/* Global data structure to remember the current x- and y-values of the element, used in the XXI, XETA, YXI, YETA methods */protected static double[] elementXValues;protected static double[] elementYValues;

/** * Get the proper method * @param methodName, the method name taken from the constants in this class * @return the method */public static Method getMethod(String methodName) throws SecurityException, NoSuchMethodException { // Build the args array Class args[] = new Class[3]; args[0] = Double.class; args[1] = Double.class; args[2] = Integer.class; return CompilationFunctions.class.getDeclaredMethod(methodName, args);}

/** * To remember the current element's x- and y-values in the static data * structure here in this class - used in the XXI, XETA, YXI, YETA methods * @param element, the element which values we want to store */public static void storeElementXYValues(Element element) {

// Grab the node list from the elementNodeList nodeList = element.getNodeList();

// Create the arrays, depending on the number of element nodesCompilationFunctions.elementXValues = new double[nodeList.size()];CompilationFunctions.elementYValues = new double[nodeList.size()];

// Fill the new arraysfor(int i = 1; i <= nodeList.size(); i++) {

CompilationFunctions.elementXValues[i-1] = nodeList.getNodeInCorrectOrder(i).getX();CompilationFunctions.elementYValues[i-1] = nodeList.getNodeInCorrectOrder(i).getY();

}}

/** * Helper Method * @param xi * @param eta * @param position * @return */public static double zero(Double xi, Double eta, Integer position) { return 0.0;}

/** * Helper Method * @param xi * @param eta * @param position * @return */public static double one(Double xi, Double eta, Integer position) { return 1.0;}

/* * * TRIANGLE * LINEAR APPROACH * ***************************/

/** * Function for Triangle, linear, normal N * FORMULA 2.101 * * @param xi * @param eta * @param position * @return */ public static double triangleLinearN(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (1.0 - xi.doubleValue() - eta.doubleValue()); case 2:

return (xi.doubleValue()); case 3: return (eta.doubleValue()); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /**

* Function for Triangle, linear, N derived to XI * * @param xi * @param eta * @param position * @return */ public static double triangleLinearNXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (-1.0); case 2:

return (1.0); case 3: return (0.0); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Triangle, linear, N derived to ETA * * @param xi * @param eta * @param position * @return */ public static double triangleLinearNETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (-1.0); case 2:

return (0.0); case 3: return (1.0); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Triangle, linear, X derived to XI * * @param xi * @param eta * @param position * @return */ public static double triangleLinearXXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 3 || CompilationFunctions.elementYValues.length < 3) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 3; i++) {

sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.triangleLinearNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, linear, X derived to ETA * * @param xi * @param eta * @param position * @return */ public static double triangleLinearXETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 3 || CompilationFunctions.elementYValues.length < 3) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 3; i++) {

sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.triangleLinearNETA(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, linear, Y derived to XI * * @param xi * @param eta * @param position * @return */ public static double triangleLinearYXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 3 || CompilationFunctions.elementYValues.length < 3) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the y-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 3; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.triangleLinearNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, linear, Y derived to ETA * * @param xi * @param eta * @param position * @return */ public static double triangleLinearYETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 3 || CompilationFunctions.elementYValues.length < 3) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the y-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 3; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.triangleLinearNETA(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, linear, JACOBI * * @param xi * @param eta * @param position * @return */ public static double triangleLinearJAC(Double xi, Double eta, Integer position) throws FunctionCalculationException { // Calculate detJ double detJ = 0.0; // The position says "-1" all the time because it does not really matter detJ = CompilationFunctions.triangleLinearXXI(xi, eta, position) * CompilationFunctions.triangleLinearYETA(xi, eta, position); detJ = detJ - (CompilationFunctions.triangleLinearXETA(xi, eta, position) * CompilationFunctions.triangleLinearYXI(xi, eta, position)); // Make sure detJ is greater than zero if(detJ <= 0.0) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Value of detJ is not > 0.0: " + detJ); } throw new FunctionCalculationException("Value of detJ is not > 0.0: " + detJ); } return (1.0 / detJ); } /** * Function for Triangle, linear, 1/ JACOBI * * @param xi * @param eta * @param position * @return */ public static double triangleLinearJAConeThrough(Double xi, Double eta, Integer position) throws FunctionCalculationException { return (1.0 / triangleLinearJAC(xi, eta, position)); } /** * Function for Triangle, linear, H1 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double triangleLinearH1(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = CompilationFunctions.triangleLinearNXI(xi, eta, position) * CompilationFunctions.triangleLinearYETA(xi, eta, position); result = result - (CompilationFunctions.triangleLinearNETA(xi, eta, position) * CompilationFunctions.triangleLinearYXI(xi, eta, position));

return result; } /** * Function for Triangle, linear, H2 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double triangleLinearH2(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = (-1.0 * CompilationFunctions.triangleLinearNXI(xi, eta, position)) * CompilationFunctions.triangleLinearXETA(xi, eta, position); result = result + (CompilationFunctions.triangleLinearNETA(xi, eta, position) * CompilationFunctions.triangleLinearXXI(xi, eta, position)); return result; }

/* * * TRIANGLE * QUADRATIC APPROACH * ***************************/

/** * Function for Triangle, quadratic, normal N * FORMULA 2.102 * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticN(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return ((1.0 - xi.doubleValue() - eta.doubleValue()) * (1.0 - 2.0 * xi.doubleValue() - 2.0 * eta.doubleValue())); case 2:

return (xi.doubleValue() * (2.0 * xi.doubleValue() - 1.0)); case 3: return (eta.doubleValue() * (2.0 * eta.doubleValue() - 1.0)); case 4: return (4.0 * xi.doubleValue() * (1.0 - xi.doubleValue() - eta.doubleValue())); case 5: return (4.0 * xi.doubleValue() * eta.doubleValue()); case 6: return (4.0 * eta.doubleValue() * (1.0 - xi.doubleValue() - eta.doubleValue())); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Triangle, quadratic, N derived to XI * FORMULA 2.102 * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticNXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (-3.0 + 4.0 * xi.doubleValue() + 4.0 * eta.doubleValue()); case 2:

return (-1.0 + 4.0 * xi.doubleValue()); case 3: return (0.0); case 4: return (4.0 - 8.0 * xi.doubleValue() - 4.0 * eta.doubleValue()); case 5: return (4.0 * eta.doubleValue()); case 6: return (-4.0 * eta.doubleValue()); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Triangle, quadratic, N derived to ETA

* FORMULA 2.102 * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticNETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (-3.0 + 4.0 * xi.doubleValue() + 4.0 * eta.doubleValue()); case 2:

return (0.0); case 3: return (-1.0 + 4.0 * eta.doubleValue()); case 4: return (-4.0 * xi.doubleValue()); case 5: return (4.0 * xi.doubleValue()); case 6: return (4.0 - 4.0 * xi.doubleValue() - 8.0 * eta.doubleValue()); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Triangle, quadratic, X derived to XI * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticXXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 6 || CompilationFunctions.elementYValues.length < 6) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 6; i++) { sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.triangleQuadraticNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, quadratic, X derived to ETA * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticXETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 6 || CompilationFunctions.elementYValues.length < 6) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 6; i++) { sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.triangleQuadraticNETA(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, quadratic, Y derived to XI * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticYXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 6 || CompilationFunctions.elementYValues.length < 6) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); }

throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the y-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 6; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.triangleQuadraticNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, quadratic, Y derived to ETA * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticYETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 6 || CompilationFunctions.elementYValues.length < 6) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 6; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.triangleQuadraticNETA(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, quadratic, JACOBI * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticJAC(Double xi, Double eta, Integer position) throws FunctionCalculationException { // Calculate detJ double detJ = 0.0; // The position says "-1" all the time because it does not really matter detJ = CompilationFunctions.triangleQuadraticXXI(xi, eta, position) * CompilationFunctions.triangleQuadraticYETA(xi, eta, position); detJ = detJ - (CompilationFunctions.triangleQuadraticXETA(xi, eta, position) * CompilationFunctions.triangleQuadraticYXI(xi, eta, position)); // Make sure detJ is greater than zero if(detJ <= 0.0) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Value of detJ is not > 0.0: " + detJ); } throw new FunctionCalculationException("Value of detJ is not > 0.0: " + detJ); } return (1.0 / detJ); } /** * Function for Triangle, quadratic, 1/ JACOBI * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticJAConeThrough(Double xi, Double eta, Integer position) throws FunctionCalculationException { return (1.0 / triangleQuadraticJAC(xi, eta, position)); } /** * Function for Triangle, quadratic, H1 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticH1(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = CompilationFunctions.triangleQuadraticNXI(xi, eta, position) * CompilationFunctions.triangleQuadraticYETA(xi, eta, position); result = result - (CompilationFunctions.triangleQuadraticNETA(xi, eta, position) * CompilationFunctions.triangleQuadraticYXI(xi, eta, position)); return result; } /** * Function for Triangle, quadratic, H2 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double triangleQuadraticH2(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = (-1.0 * CompilationFunctions.triangleQuadraticNXI(xi, eta, position)) * CompilationFunctions.triangleQuadraticXETA(xi, eta,position); result = result + (CompilationFunctions.triangleQuadraticNETA(xi, eta, position) * CompilationFunctions.triangleQuadraticXXI(xi, eta, position)); return result; }

/*

* * QUADRAT * LINEAR APPROACH * ***************************/

/** * Function for Quadrat, linear, normal N * FORMULA 2.104 * * @param xi * @param eta * @param position * @return */ public static double quadratLinearN(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return ((1.0 - xi.doubleValue()) * (1.0 - eta.doubleValue())); case 2:

return (xi.doubleValue() * (1.0 - eta.doubleValue())); case 3: return (xi.doubleValue() * eta.doubleValue()); case 4: return ((1.0 - xi.doubleValue()) * eta.doubleValue()); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Quadrat, linear, N derived to XI * * @param xi * @param eta * @param position * @return */ public static double quadratLinearNXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (-1.0 + eta.doubleValue()); case 2:

return (1.0 - eta.doubleValue()); case 3: return (eta.doubleValue()); case 4: return (-1.0 * eta.doubleValue()); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Quadrat, linear, N derived to ETA * * @param xi * @param eta * @param position * @return */ public static double quadratLinearNETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (1.0 + xi.doubleValue()); case 2:

return (-1.0 * xi.doubleValue()); case 3: return (xi.doubleValue()); case 4: return (1.0 - xi.doubleValue()); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Quadrat, linear, X derived to XI

* * @param xi * @param eta * @param position * @return */ public static double quadratLinearXXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 4 || CompilationFunctions.elementYValues.length < 4) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 4; i++) { sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.quadratLinearNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Quadrat, linear, X derived to ETA * * @param xi * @param eta * @param position * @return */ public static double quadratLinearXETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 4 || CompilationFunctions.elementYValues.length < 4) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 4; i++) { sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.quadratLinearNETA(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Quadrat, linear, Y derived to XI * * @param xi * @param eta * @param position * @return */ public static double quadratLinearYXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 4 || CompilationFunctions.elementYValues.length < 4) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the y-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 4; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.quadratLinearNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Quadrat, linear, Y derived to ETA * * @param xi * @param eta * @param position * @return */ public static double quadratLinearYETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 4 || CompilationFunctions.elementYValues.length < 4) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the y-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 4; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.quadratLinearNETA(xi, eta, new Integer(i+1))); } return sum; } /**

* Function for Quadrat, linear, JACOBI * * @param xi * @param eta * @param position * @return */ public static double quadratLinearJAC(Double xi, Double eta, Integer position) throws FunctionCalculationException { // Calculate detJ double detJ = 0.0; // The position says "-1" all the time because it does not really matter detJ = CompilationFunctions.quadratLinearXXI(xi, eta, position) * CompilationFunctions.quadratLinearYETA(xi, eta, position); detJ = detJ - (CompilationFunctions.quadratLinearXETA(xi, eta, position) * CompilationFunctions.quadratLinearYXI(xi, eta, position)); // Make sure detJ is greater than zero if(detJ <= 0.0) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Value of detJ is not > 0.0: " + detJ); } throw new FunctionCalculationException("Value of detJ is not > 0.0: " + detJ); } return (1.0 / detJ); } /** * Function for Quadrat, linear, 1/ JACOBI * * @param xi * @param eta * @param position * @return */ public static double quadratLinearJAConeThrough(Double xi, Double eta, Integer position) throws FunctionCalculationException { return (1.0 / quadratLinearJAC(xi, eta, position)); } /** * Function for Quadrat, linear, H1 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double quadratLinearH1(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = CompilationFunctions.quadratLinearNXI(xi, eta, position) * CompilationFunctions.quadratLinearYETA(xi, eta, position); result = result - (CompilationFunctions.quadratLinearNETA(xi, eta, position) * CompilationFunctions.quadratLinearYXI(xi, eta, position)); return result; } /** * Function for Quadrat, linear, H2 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double quadratLinearH2(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = (-1.0 * CompilationFunctions.quadratLinearNXI(xi, eta, position)) * CompilationFunctions.quadratLinearXETA(xi, eta, position); result = result + (CompilationFunctions.quadratLinearNETA(xi, eta, position) * CompilationFunctions.quadratLinearXXI(xi, eta, position)); return result; }

/* * * QUADRAT * QUADRATIC APPROACH * ***************************/

/** * Function for Quadrat, quadratic, normal N * FORMULA 2.105 * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticN(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return ((1.0 - xi.doubleValue()) * (1.0 - eta.doubleValue()) * (1.0 - 2.0 * xi.doubleValue() - 2.0 * eta.doubleValue())); case 2:

return ((-1.0 * xi.doubleValue()) * (1.0 - eta.doubleValue()) * (1.0 - 2.0 * xi.doubleValue() + 2.0 * eta.doubleValue())); case 3: return ((-1.0 * xi.doubleValue() * eta.doubleValue()) * (3.0 - 2.0 * xi.doubleValue() - 2.0 * eta.doubleValue())); case 4:

return ((-1.0 * eta.doubleValue()) * (1.0 - xi.doubleValue()) * (1.0 + 2.0 * xi.doubleValue() - 2.0 * eta.doubleValue())); case 5: return ((4.0 * xi.doubleValue()) * (1.0 - xi.doubleValue()) * (1.0 - eta.doubleValue())); case 6:

return ((4.0 * xi.doubleValue() * eta.doubleValue()) * (1.0 - eta.doubleValue())); case 7: return ((4.0 * xi.doubleValue() * eta.doubleValue()) * (1.0 - xi.doubleValue()));

case 8: return ((4.0 * eta.doubleValue()) * (1.0 - xi.doubleValue()) * (1.0 - eta.doubleValue())); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Quadrat, quadratic, N derived to XI * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticNXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (-3.0 + 5.0 * eta.doubleValue() + 4.0 * xi.doubleValue() - 2.0 * Math.pow(eta.doubleValue(), 2) - 4.0 * eta.doubleValue() *xi.doubleValue()); case 2:

return (-1.0 - eta.doubleValue() + 4.0 * xi.doubleValue() + 2.0 * Math.pow(eta.doubleValue(), 2) - 4.0 * eta.doubleValue() * xi.doubleValue()); case 3: return (-3.0 * eta.doubleValue() + 2.0 * Math.pow(eta.doubleValue(), 2) + 4.0 * eta.doubleValue() * xi.doubleValue()); case 4:

return (eta.doubleValue() * (1.0 + 2.0 * xi.doubleValue() - 2.0 * eta.doubleValue()) - 2.0 * eta.doubleValue() * (1.0 - xi.doubleValue())); case 5: return (4.0 - 4.0 * eta.doubleValue() - 8.0 * xi.doubleValue() + 8.0 * eta.doubleValue() * xi.doubleValue()); case 6:

return (4.0 * eta.doubleValue() - 4.0 * Math.pow(eta.doubleValue(), 2)); case 7: return (4.0 * eta.doubleValue() - 8.0 * eta.doubleValue() * xi.doubleValue()); case 8: return (-4.0 * eta.doubleValue() + 4.0 * Math.pow(eta.doubleValue(), 2)); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for Quadrat, quadratic, N derived to ETA * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticNETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (-3.0 + 5.0 * xi.doubleValue() + 4.0 * eta.doubleValue() - 2.0 * Math.pow(xi.doubleValue(), 2) - 4.0 * eta.doubleValue() * xi.doubleValue()); case 2:

return ((-1.0 * xi.doubleValue()) - 2.0 * Math.pow(xi.doubleValue(), 2) + 4.0 * eta.doubleValue() * xi.doubleValue()); case 3: return (-3.0 * xi.doubleValue() + 2.0 * Math.pow(xi.doubleValue(), 2) + 4.0 * eta.doubleValue() * xi.doubleValue()); case 4:

return (-1.0 - xi.doubleValue() + 4.0 * eta.doubleValue() + 2.0 * Math.pow(xi.doubleValue(), 2) - 4.0 * eta.doubleValue() * xi.doubleValue()); case 5: return (-4.0 * xi.doubleValue() + 4.0 * Math.pow(xi.doubleValue(), 2)); case 6:

return (4.0 * xi.doubleValue() - 8.0 * eta.doubleValue() * xi.doubleValue()); case 7: return (4.0 * xi.doubleValue() - 4.0 * Math.pow(xi.doubleValue(), 2)); case 8: return (4.0 - 4.0 * xi.doubleValue() - 8.0 * eta.doubleValue() + 8.0 * eta.doubleValue() * xi.doubleValue()); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } }

/** * Function for Quadrat, quadratic, X derived to XI * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticXXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 8 || CompilationFunctions.elementYValues.length < 8) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 8; i++) { sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.quadratQuadraticNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Quadrat, quadratic, X derived to ETA * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticXETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 8 || CompilationFunctions.elementYValues.length < 8) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 8; i++) { sum = sum + (CompilationFunctions.elementXValues[i] * CompilationFunctions.quadratQuadraticNETA(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Quadrat, quadratic, Y derived to XI * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticYXI(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 8 || CompilationFunctions.elementYValues.length < 8) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the y-values in the static array multiplied by the "N derived to XI" values for(int i = 0; i < 8; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.quadratQuadraticNXI(xi, eta, new Integer(i+1))); } return sum; } /** * Function for Triangle, quadratic, Y derived to ETA * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticYETA(Double xi, Double eta, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(CompilationFunctions.elementXValues.length < 8 || CompilationFunctions.elementYValues.length < 8) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double sum = 0.0; // Calculate the sum out of the x-values in the static array multiplied by the "N derived to ETA" values for(int i = 0; i < 8; i++) { sum = sum + (CompilationFunctions.elementYValues[i] * CompilationFunctions.quadratQuadraticNETA(xi, eta, new Integer(i+1))); } return sum; }

/** * Function for Quadrat, quadratic, JACOBI * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticJAC(Double xi, Double eta, Integer position) throws FunctionCalculationException { // Calculate detJ double detJ = 0.0; // The position says "-1" all the time because it does not really matter detJ = CompilationFunctions.quadratQuadraticXXI(xi, eta, position) * CompilationFunctions.quadratQuadraticYETA(xi, eta, position); detJ = detJ - (CompilationFunctions.quadratQuadraticXETA(xi, eta, position) * CompilationFunctions.quadratQuadraticYXI(xi, eta, position)); // Make sure detJ is greater than zero if(detJ <= 0.0) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Value of detJ is not > 0.0: " + detJ); } throw new FunctionCalculationException("Value of detJ is not > 0.0: " + detJ); } return (1.0 / detJ); } /** * Function for Quadrat, quadratic, 1/ JACOBI * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticJAConeThrough(Double xi, Double eta, Integer position) throws FunctionCalculationException { return (1.0 / quadratQuadraticJAC(xi, eta, position)); } /** * Function for Quadrat, quadratic, H1 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticH1(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = CompilationFunctions.quadratQuadraticNXI(xi, eta, position) * CompilationFunctions.quadratQuadraticYETA(xi, eta, position); result = result - (CompilationFunctions.quadratQuadraticNETA(xi, eta, position) * CompilationFunctions.quadratQuadraticYXI(xi, eta, position)); return result; } /** * Function for Quadrat, quadratic, H2 part of the Integral * * @param xi * @param eta * @param position * @return */ public static double quadratQuadraticH2(Double xi, Double eta, Integer position) throws FunctionCalculationException { double result = (-1.0 * CompilationFunctions.quadratQuadraticNXI(xi, eta, position)) * CompilationFunctions.quadratQuadraticXETA(xi, eta, position); result = result + (CompilationFunctions.quadratQuadraticNETA(xi, eta, position) * CompilationFunctions.quadratQuadraticXXI(xi, eta, position)); return result; }}

1.2 Drucken Sie die jeweiligen Funktionswerte für die ersten 10 Knotenpunkte derPotentialfunktion für alle 4 Testläufe (Programmversionen (A) und (B) jeweils mitStützstellenpaar (I) und (II) aus). Einander entsprechende Ergebnisse von (A) und (B) müssennicht nur algebraisch, sondern auch numerisch identisch sein.

Potentialfunktion Funktionswerte, 4-4 Stützstellen

Knoten-Nummer quadratische Speicherungsformhüllenorientierte Speicherungsform1 150.0 150.02 150.0 150.03 142.70265242983004 142.702652429830044 150.0 150.05 135.47840826594043 135.478408265940436 150.0 150.07 142.39763614846822 142.397636148468228 142.5713153059559 142.57131530595599 135.4295521553353 135.429552155335310 128.40675340410135 128.40675340410135

Potentialfunktion Funktionswerte, 8-6 Stützstellen

Knoten-Nummer quadratische Speicherungsformhüllenorientierte Speicherungsform1 150.0 150.02 150.0 150.03 142.7026524134017 142.70265241340174 150.0 150.05 135.47840823636872 135.478408236368726 150.0 150.07 142.3976361155748 142.39763611557488 142.57131528238918 142.571315282389189 135.42955212287515 135.4295521228751510 128.4067533684121 128.4067533684121

KommentarDie Grundeinteilung stammt wie gefordert aus dem 1.Leistungsnachweis, welcher auch unterTeilaufgabe 2.1.3 auf der folgenden Seite nochmals abgebildet ist um einen Vergleich zu denursprünglichen Ergebnissen zu ermöglichen. Wie Sie in den beiden Tabellen sehen können,gleichen sich die Werte der quadratischen und der hüllenorientierten Speicherungsform in allenFällen. Dieser Test sollte relativ zuverlässig sicherstellen, dass in der Implementierung derhüllenorientierten Speicherung keinerlei Fehler mehr vorhanden sind.

27

1.3 Zeichnen Sie von einer der beiden Programmversionen (A) oder (B) und demStützstellenpaar (II) Strom- und Potentiallinien (möglichst in einer Zeichnung). Im Vergleich zuden Ergebnissen vom 1.Leistungsnachweis, quadratischer Ansatz, dürften kaum Unterschiedeerkennbar sein.

Wie Sie auf der folgenden Seite sehen werden, unterscheiden sich die Darstellungen der beidenErgebnisse kaum. Das erste Bild stammt aus dem 1.Leistungsnachweis, berechnet mittelsquadratischem Ansatz. Die zweite Darstellung wurde durch krummlinige Elemente berechnet.Hierbei benutzten wir die quadratische Speicherungsform (die hüllenorientierte hat diesselbenErgebnisse erbracht wie in der vorherigen Aufgabe dargestellt) sowie 8 Stützstellen für dasinnere Integral und 6 Stützstellen für das äussere Integral.

AnmerkungIm Bild zum Gauss-Quadratur-Verfahren sieht man in der Nähe der Rundung desFunktionsgebiets eine Lücke, die im oberen Bild nicht vorhanden ist. Zuerst dachten wirhierbei an einen Fehler in unseren Berechnungen, allerdings ist der Strich dort schonvorhanden. Derfem_splitterwählte hierbei ungünstigerweise die Farbe Gelb, welche nicht sehrgut sichtbar ist. Wir hoffen, dass unser Drucker diese gut sichtbar zu Papier bringen kann.

Anhang zu Teil 2.1.3Anhang 2.1.3.A - Vergleichsbild aus dem 1.Leistungsnachweis, quadratischer AnsatzAnhang 2.1.3.B - Gauss-Quadratur-Verfahren, quadratische Speicherungsform, 8-6 Stützstellen

28

Anhang 2.1.3.A- Vergleichsbild aus dem 1.Leistungsnachweis, quadratischer Ansatz

Anhang 2.1.3.B- Gauss-Quadratur-Verfahren, quadratische Speicherungsform, 8-6 Stützstellen

29

2. Feinste Unterteilung von Teil 1: Rechenzeitvergleich bezüglich der numerischen Integration.Rechnen Sie mit Programmversion (A) (Näherungswerte für die) Strom und Potentialfunktion.- mit Stützstellenpaar (I) (4 Stützstellen für jede Integrationsrichtung) und- mit Stützstellenpaar (II) (6 Stützstellen für das innere und 8 Stützstellen für das äussereIntegral)und ermitteln Sie jeweils die Rechenzeit.

Da es uns auch interessiert hat wie sich verschiedene Rechnerkonfigurationen auf denRechenzeitvergleich auswirken, haben wir diese Aufgabe etwas erweitert. Uns ist nämlichaufgefallen, dass z.B. die SoftwareSeti@Homedie ja Fast-Fourier-Transformationen benutzt,auf einemCentrinoLaptop, der weniger MHz bietet als der Desktop Rechner, viel schnellerläuft. Auch wenn die Ergebnisse natürlich aufgrund des Rechneraufbaus nicht direktvergleichbar sind liefern sie doch indirekt einige gute Aussagen. Die verfeinerte Netzeinteilungbesteht aus (wie in Teil 1) 2155 Knoten (inkl. Zwischenknoten) und 1026 Elemente (1016Vierecke und 10 Dreiecke).

Folgende Rechnerkonfigurationen wurden benutzt:

• DesktopAMD Athlon XP 2500 (1833 MHz), 512 KB L2-Cache, 1024 MB Arbeitsspeicher,Windows XP

• LaptopIntel Centrino 1500 (1500 MHz), 2048 KB L2-Cache, 512 MB Arbeitsspeicher, SuSELinux 9.1

Rechenzeitvergleich - Desktop (in Millisekunden)

Programmteil 4-4 Stützstellen 8-6 StützstellenKompilation zur Gesamtsteifigkeitsmatrix 4734 13125

Test: GstMatrix symmetrisch, Hauptdiagonalwerte != 0 219 235Berechnung der Stromlinien 76547 77406

Berechnung der Potentiallinien 76547 75641Gesamtlaufzeit 158062 166407

Rechenzeitvergleich - Laptop (in Millisekunden)

Programmteil 4-4 Stützstellen 8-6 StützstellenKompilation zur Gesamtsteifigkeitsmatrix 4302 11864

Test: GstMatrix symmetrisch, Hauptdiagonalwerte != 0 166 164Berechnung der Stromlinien 71003 70951

Berechnung der Potentiallinien 68896 71930Gesamtlaufzeit 144367 154909

30

KommentarMan kann aus beiden Tabellen sehr deutlich die steigende Rechenzeit zur Kompilation derGesamtsteifigkeitsmatrix ablesen, die sich, durch die höhere Anzahl der Stützstellen, knappverdreifacht. Die Zeitunterschiede in den drei anderen Programmteilen sind vernachlässigbarund sollten im Optimalfall eigentlich auf Null schrumpfen, da sich hier keine Änderungen inder Berechnung ergeben. Die auftretenden Unterschiede hängen unserer Meinung nach mit derProzesszuweisung im Betriebssystem zusammen, welche von uns für beide Tests natürlichnicht exakt reproduzierbar war.

Vergleicht man beide Tabellen schneidet der Laptop trotz weniger MHz besser ab als derDesktop. Dies wird wahrscheinlich vor allem vom höheren L2-Cache in der CPU verursacht.Aufgrund der maximalen Grösse der Gesamtsteifigkeitsmatrix von knapp 37 MB (sieheSpeichervergleich Teil 1) kommt der grössere Hauptspeicher des Desktops nicht zum Tragen.Besonders viel Zeit wird während der Berechnung von Strom- und Potentiallinien gespart undhierbei vor allem bei der Durchführung des Cholesky-Algorithmus.

Das komplette Programm kann sicherlich noch in verschiedenen if-Bedingungen undfor-Schleifen optimiert werden. Was uns allerdings etwas verwundert warenRechenzeitvergleiche mit Komolitonen aus vergangenen Semestern, welche uns zuerst davorgewarnt haben unsere Leistungsnachweise inJavazu schreiben, da diese Programmiersprachefür den Rechenaufwand zu langsam sei. Wenigstens ein C++ Programm kam hier bei einervergleichbaren Berechnung (ähnliche Anzahl Knoten und Elemente) auf Rechenzeiten von biszu einer Stunde, was wir nicht nachvollziehen konnten.

Da wir für unser ProgrammJavabenutzen konnten wir das Programm auch unter Windows XPund SuSE Linux 9.1 testen. Allerdings sind die Unterschiede vernachlässigbar, da die VirtualMachine vonJavabei reinen mathematischen Berechnungen wohl hier die verschiedenenVorteile der Betriebssysteme nicht ausnutzen kann.

31

3 Teil 3: Wärmeleitung

1. Formeln: Leiten Sie zunächst die Formeln zur Berechnung von

∫G

∫(f(x, y) ∗ u(x, y))dxdy (1)

∫C

(α(s) ∗ u(x, y)2)ds (2)

für das geradlinige Element (Dreieck, Parallelogramm) mit linearem Funktionsverlauf von uüber den Elementseiten - analog zur Vorlesung - ausführlich her.

Hinweise:- Im ersten Integral können Sie für die Koordinatentransformationen und für die Funktion u aufdie Formeln aus ’ebene Potentialströmung, geradlinige Elemente’ zurückgreifen (dreigliedrigeAnsätze für die Koordinatentransformationen; für die Funktion u: dreigliedriger Ansatz beimDreieck, viergliedrig beim Parallelogramm).- Im zweiten Integral sind wegen der Geradlinigkeit der Elemente die Ansätze sowohl für dieKoordinatentransformation als auch für die Funktion u lediglich zweigliedrig (=linear). AlsFormfunktionen müssten sichN1(σ) = 1− σ undN2(σ) = σ ergeben.

Herleitung der Berechnung von Formel (1)Zuerst führen wir den Übergang zum lokalen Einheitselement wie in der Vorlesung her:

x = ~xeT ∗ ~N(ξ, η) (3)

y = ~yeT ∗ ~N(ξ, η) (4)

u(x, y) = ~ueT ∗ ~N(ξ, η) = ~NT (ξ, η) ∗ ~ue (5)

Aufgrund der Koordinatentransformation erhalten wir für das Integral ebenso:

dxdy = det(J)dξdη

Nun setzen wir die Formeln (3), (4), (5) und die Koordinatentransformation in die Formel (1)ein und erhalten damit:

1∫0

d(η)∫0

(f( ~xeT ∗ ~N(ξ, η), ~ye

T ∗ ~N(ξ, η)) ∗ ~NT (ξ, η) ∗ ~ue) ∗ det(J)dξdη (6)

Aufgrund der Übersichtstabelle, die wir von Ihnen erhalten haben, haben wir für dieKoordinaten-Transformation beim Dreieck und beim Parallelogramm einen 3-gliedrigen Ansatz

32

(Formel 2.101). Für die Funktionu(ξ, η) haben wir jedoch beim Dreieck einen 3-gliedrigenAnsatz (Formel 2.101) und beim Parallelogramm einen 4-gliedrigen Ansatz (Formel 2.104).Der Ansatz des Parallelogramms kann jedoch, aufgrund seiner Eigenschaften, auf einen3-Gliedrigen reduziert werden, wodurch alle~N(ξ, η) die gleiche Anzahl von Elementen haben.

Da ~ue für die Integration eine Konstante ist, ziehen wir diese aus dem Integral heraus:

1∫0

d(η)∫0

(f( ~xeT ∗ ~N(ξ, η), ~ye

T ∗ ~N(ξ, η)) ∗ ~NT (ξ, η)) ∗ det(J)dξdη ∗ ~ue

Das komplette Integral bildet nun den Vektor~beT

eines Elements:

1∫0

d(η)∫0

(f( ~xeT ∗ ~N(ξ, η), ~ye

T ∗ ~N(ξ, η)) ∗ ~NT (ξ, η)) ∗ det(J)dξdη

︸ ︷︷ ︸~be

T

∗ ~ue

Nun können wir alle Vektoren~beT

der Elemente zum Gesamt-Vektor~bT kompilieren underhalten für alle Elemente:

NE∑e=1

(~beT∗ ~ue) = ~bT ∗ ~u

Die neu erhaltene Formel liefert das Ergebnis der Integration von Formel (1):∫G

∫(f(x, y) ∗ u(x, y))dxdy = ~bT ∗ ~u = ~uT ∗~b

33

Herleitung der Berechnung von Formel (2)Da der TeilrandC vonG in NC TeilränderCR zerfällt, ergibt sich die Summenformel:

∫C

α(s) ∗ u(x, y)2ds =NC∑R=1

∫CR

α(s) ∗ u(x, y)2ds

Die Ansatzfunktion für den zweigliedrigen Ansatz lautet:

~f(σ) = (1, σ)

Berechnung der Formfunktion:

x = γ1 + γ2σ = ~γT ∗ ~f(σ) (7)

y = δ1 + δ2σ = ~δT ∗ ~f(σ) (8)

u = α1 + α2σ = ~αT ∗ ~f(σ) (9)

Berechnung vonγ1, γ2 :

A → A′(σ = 0) xA = γ1 ∗ 1 = γ1 (10)

B → B′(σ = 1) xB = γ1 ∗ 1 + γ2 ∗ 1 = γ1 + γ2 (11)

~xR = B ∗ ~γ

Nun berechnen wir~N(σ), wobei die MatrixB folgende Werte hat :

B =

(1 01 1

)

~γ = A ∗ ~xR

mit

B−1 =: A =

(1 0

−1 1

)

34

Dann ist:

x = ~γT ∗ ~f(σ) = ~xRT ∗AT ∗ ~f(σ)︸ ︷︷ ︸

~N(σ)

Berechnen wir nun~N(σ) ergibt sich als Ergebnis:

~N(σ) = AT ∗ ~f(σ) =

(1− σ

σ

)

Die Berechnungen vonx undy erfolgt analog und wurde hier nicht nochmals ausgeführt. Dieberechneten Ergebnisse von~N(σ) entsprechen den Resultaten die in der Aufgabenstellungangegeben waren.

Folgerung - Erste Ableitung von~N(σ):

~N ′(σ) =

(−11

)

Um nun Formel (2) zu berechnen benötigen wir noch einige Umformungen analog zurVorlesung:

∫CR

...ds =1∫

0

...dσ

Wie in der Vorlesung wird das Bogenstückds so klein gemacht, dass man es als Geradenstückapproximieren kann:

ds =√

(dx)2 + (dy)2

Fürdx unddy ergibt sich wie in der Vorlesung:

dx = ~xRT ∗ ~N ′(σ)dσ dy = ~yR

T ∗ ~N ′(σ)dσ

Nun setzen wir die Formeln fürdx unddy in die Formel fürds ein:

ds =√

( ~xRT ∗ ~N ′(σ))2 + ( ~yR

T ∗ ~N ′(σ))2

35

Fürα(s) := α(x, y) ergibt sich durch einsetzen:

α( ~xRT ∗ ~N ′(σ), ~yR

T ∗ ~N ′(σ))

Nun setzen wir alle benötigten Formeln in∫

CR

α(s) ∗ u(s)2ds ein:

1∫0

α(σ) ∗ ( ~uRT ∗ ~N(σ))2 ∗ √...dσ

Da die beiden Vektoren~uRT und ~uR konstant sind, können diese aus dem Integral

ausgeklammert werden und wir erhalten:

1∫0

α(σ) ∗ ~uRT ∗ ~N(σ) ∗ ~NT (σ) ∗ ~uR ∗

√...dσ =

= ~uRT ∗

1∫0

α(σ) ∗ ~N(σ) ∗ ~NT (σ) ∗ √...dσ

︸ ︷︷ ︸2x2−Matrix−MR

∗ ~uR

Dies ermöglicht uns die Berechnung des Linienintegralbeitrags eines einzelnen Randstückes.Nun müssen wir noch die Ergebnisse aller Linienintegralbeiträge zusammenkompilieren umFormel(2) zu berechnen. Die MatrixMR ist hierbei berechenbar:

∫C

α(s) ∗ u2(s)ds =NC∑R=1

∫CR

α(s) ∗ u2(s)ds =NC∑R=1

~uRT ∗MR ∗ ~uR

36

2. Programm:Schreiben Sie ein Programm zur (näherungsweisen) Berechnung der Temperaturverteilung mitHilfe der Methode der finiten Elemente. Erweitern Sie hierzu Ihre Programmversion (A) vonTeil 2 dieses Leistungsnachweises (Verwendung krummliniger Dreiecke/Vierecke) um dieImplementierung der in der Vorlesung entwickelten Formeln und deren Kompilation.

Um die Linienintegrale zu berücksichtigen, haben wir unsereFEMIN Dateien um dasSchlüsselwortCTABerweitert. Wie in der Vorlesung als Beispiel genannt folgt auf diesesSchlüsselwort die Anzahl von Linienteilen des Funktionsgebiets. Jeder Teil hat hierbei dreiverschiedene Knotennummern, die in den nachfolgenden Zeilen stehen. Diese dreiKnotennummern bilden dann den rechten, mittleren und linken Knoten des Linienteils.

Da es sich ja bei der normalen Berechnung mit krummlinigen Elementen und auch bei derWärmeleitung umFEM3Dateien handelt unterscheiden wir die Vorgehensweisefolgendermaßen in der KlasseFEMStartup: Ist die Datei vom TypFEM3und enthält keinerleiCTABswird die Berechnung mittelsFEMCalcGaussaus dem Teil 2 diesesLeistungsnachweises durchgeführt. Ansonsten wird die neue KlasseFEMCalcTemperatureverwendet, welche sich vonFEMCalcGaussableitet.

Durch die Änderungen am bestehenden Programm wurde folgende Klassen betroffen:

• FEMStartupIm Konstruktor wird nun weiter unterschieden welche Art der Berechnung erfolgen soll.

• FEMINLoaderDas SchlüsselwortCTABwird nun berücksichtigt und mittels der MethodeloadCtabs(...)werden die Linienteile von derFEMIN Datei eingelesen.

• FEMManagerBerücksichtigung vonCTabObjekte in einer eigenen lokalenCTabList

• FEMGaussQuadratureDie neue MethodecalcSingleIntegration(...)ermöglicht die Berechnung einzelnerIntegrale (wird für die Lösung des Linienintegrals benutzt)

Folgende Klassen wurde neu erstellt:

• FEMCalcTemperatureAbgeleitet vonFEMCalcGauss, überschreibt die Methodestart(), benutzt allerdingsweiterhin die Methodecompilation()vonFEMCalcGausszur Kompilierung derGesamtsteifigkeitsmatrix mittels Gauss-Quadratur-Verfahren. Diese neue Klasse enthältauch Methoden zur Erzeugung des Vektors BcreateVectorB()und des LinienintegralscreateLineIntegral(). Ebenso überschreibt es die Methodecalculation()zurDurchführung der eigentlichen Berechnung um den Vektor B zu berücksichtigen.

37

• CTabRepräsentiert ein CTab (Linienteil) welches drei verschiedene Knoten enthält (rechts,mitte, links).

• CTabListDiese Liste kann beliebig vieleCTabObjekte enthalten.

• LineIntegralFunctionsDiese Klasse beinhaltet sämtliche statischen Methoden, die wir während der Berechnungdes Linienintegrals benötigen.

Anhang zu Teil 3.2Source Teil 3.2 - Relevanter Quellcode zu diesem Teil

38

Source Teil 3.2

FEMStartup/** * Construct a new startup object * @param femInputFile, the File object representing the input file * @param femOutputFile, the File object representing the output file * @param showCompleteStiffnessMatrix, true if the complete-stiffness-matrix should be displayed, false otherwise */public FEMStartup(File femInputFile, File femOutputFile, boolean showCompleteStiffnessMatrix) {

// Load the file FEMManager.getInstance().load(femInputFile);

// Create the Calculation object FEMCalc calc = null;

// Check which way of compilation we need to use if(FEMManager.getInstance().getFEMApproach() == 2) {

// Check if we have any CTabs and need to calculate temperature-stuff

if(FEMManager.getInstance().getCTabList().size() > 0) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "CTabs Found ! Temperature !"); localLogger.log(Level.INFO, "Forcing Compilation: B-VECTOR via GAUSS"); } // Temperature calculations calc = new FEMCalcTemperature(); } else { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "No CTabs found !"); localLogger.log(Level.INFO, "Using Compilation: STANDARD"); } // Standard way of compilation using S-Matrices calc = new FEMCalc(); }

} else if(FEMManager.getInstance().getFEMApproach() == 3) {

// Check if we have any CTabs and need to calculate temperature-stuff if(FEMManager.getInstance().getCTabList().size() > 0) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "CTabs Found ! Temperature !"); localLogger.log(Level.INFO, "Forcing Compilation: B-VECTOR via GAUSS"); } // Temperature calculations calc = new FEMCalcTemperature(); } else { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "No CTabs found !"); localLogger.log(Level.INFO, "Using Compilation: GAUSS_QUADRATURE"); } // Compilation via Gauss calc = new FEMCalcGauss(); }

} else {

// Unknown required compilation if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Unknown required way of compilation: "); } FEMStartup.abort(false); }

[...]

FEMINLoader /* The list holding all ctabs */ protected CTabList ctabList = new CTabList();

/** * Load all settings from the given file * @param inFile * @return true if all went well, false otherwise */ public boolean load(File inFile) { try { // Create the file input stream FileInputStream inputStream = new FileInputStream(inFile); // Create a new bytebuffer to hold the contents on the file based on the file size byte buffer[] = new byte[(int)inFile.length()]; // Make sure all lists are empty this.nodeList.clear(); this.elementList.clear(); this.borderList.clear(); this.calculationList.clear(); this.ctabList.clear(); // Read everything from the file and store it in the buffer int readBytes = inputStream.read(buffer); // Convert the byte buffer into one String, easier to work with String contents = new String(buffer, 0, readBytes); StringReader reader = new StringReader(contents); // The keyword string we are reading from the contents String keyword = ""; // The index pointing to the next character to read int charIndex = 0;

// Read from the contents till we reached the end while(charIndex < contents.length()) { // Read the next character and append it to the keyword string keyword = keyword + (char)(reader.read()); // Raise the char index by one charIndex++;

// Take a look if the keyword already matches any of our known keywords if(keyword.contains(InputConstants.KEYWORD_FEM)) {

// We found the keyword for the nodes, call the proper method to read all nodes if(!this.loadFEMInfo(reader)) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Loading file failed while reading the FEM info!"); } return false; } // Clear the found keyword keyword = ""; } else if(keyword.contains(InputConstants.KEYWORD_NODES_START)) {

// We found the keyword for the nodes, call the proper method to read all nodes if(!this.loadNodes(reader)) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Loading file failed while reading nodes!"); } return false; } // Clear the found keyword keyword = ""; } else if(keyword.contains(InputConstants.KEYWORD_ELEMENTS_START)) { // We found the keyword for the elements, call the proper method to read all elements if(!this.loadElements(reader)) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Loading file failed while reading elements!"); } return false; } // Clear the found keyword keyword = ""; } else if(keyword.contains(InputConstants.KEYWORD_BORDERS_START)) { // We found the keyword for the borders, call the proper method to read all borders if(!this.loadBorders(reader)) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Loading file failed while reading borders!"); } return false; } // Clear the found keyword keyword = ""; } else if(keyword.contains(InputConstants.KEYWORD_CTAB_START)) { // We found the keyword for the calculations, call the proper method to read all the ctabs if(!this.loadCtabs(reader)) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Loading file failed while reading a ctab!"); } return false; } // Clear the found keyword keyword = ""; } else if(keyword.contains(InputConstants.KEYWORD_CALCULATION_START)) { // We found the keyword for the calculations, call the proper method to read all calculations if(!this.loadCalculation(reader)) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Loading file failed while reading a calculation!"); } return false; } // Clear the found keyword keyword = ""; } else if(keyword.contains(InputConstants.KEYWORD_END)) { // We found the end of the file, let's stop the load-in return true; } } return true; } catch (Exception e) {

if(localLogger.isEnabledFor(Level.ERROR)) {localLogger.log(Level.ERROR, "Loading file failed: " + inFile.getName(), e);

}

return false; } }

[...]

/** * Loads all ctab information from the given string starting at the given index * @param reader, the stringreader to read from * @return true if the method was successfull, false otherwise */ protected boolean loadCtabs(StringReader reader) { try {

// Now we are at the position to read the number of ctabs in the file int numberOfCtabs = this.readInteger(reader);

// Check if we got the number of ctabs if(numberOfCtabs == -1) { // Error, we did not find at least one number if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Syntax Error while loading the amount of ctabs from the file!"); } return false; } // Show INFO for user if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Loading " + numberOfCtabs + " ctabs from the file" + " ..."); } // Start loading the number of ctabs we discovered for(int ctabIndex = 1; ctabIndex <= numberOfCtabs; ctabIndex++) { // Read the left node int leftNodeIndex = this.readInteger(reader); int midNodeIndex = this.readInteger(reader); int rightNodeIndex = this.readInteger(reader); // Get the node objects and store them in the new ctab Node leftNode = this.nodeList.getNode(leftNodeIndex); Node midNode = this.nodeList.getNode(midNodeIndex); Node rightNode = this.nodeList.getNode(rightNodeIndex); // Create the new ctab object and store it in the main ctab list CTab newCTab = new CTab(ctabIndex, leftNode, midNode, rightNode); this.ctabList.setCTab(newCTab); } return true; } catch (Exception e) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error while loading ctabs from the file !", e); } return false; } }

[...]

/** * Retrieve all ctabs * @return the list of all ctabs */ public CTabList getCTabs() { return this.ctabList; }

FEMManager /** * Load all settings from the given file (normally the FEMIN file) * @param inFile, the FEMIN file to get all settings from * @return true if all went well, false otherwise */ public boolean load(File inFile) { try { // Clear the whole manager this.clear(); // Call the FEMIN loader class FEMINLoader loader = new FEMINLoader(); if(!loader.load(inFile)) { // Failure while loading the file, stop the program FEMStartup.abort(false); } // Grab all data from the loader this.femApproach = loader.getFEMApproach(); this.nodeList = loader.getNodes(); this.elementList = loader.getElements(); this.borderList = loader.getBorders(); this.ctabList = loader.getCTabs(); this.calculationList = loader.getCalculations();

if(localLogger.isEnabledFor(Level.INFO)) {localLogger.log(Level.INFO, "File import complete: ");localLogger.log(Level.INFO, " Approach: " + this.femApproach);localLogger.log(Level.INFO, " Nodes: " + this.nodeList.size());localLogger.log(Level.INFO, " Elements: " + this.elementList.size());localLogger.log(Level.INFO, " Borders: " + this.borderList.size());localLogger.log(Level.INFO, " CTabs: " + this.ctabList.size());localLogger.log(Level.INFO, " Calculations: " + this.calculationList.size());

} } catch (Exception e) {

if(localLogger.isEnabledFor(Level.ERROR)) {localLogger.log(Level.ERROR, "Loading the file failed: " + inFile.getName(), e);

}

return false; } return true; }

[...]

/** * @return Returns the ctab list */ public CTabList getCTabList() { return this.ctabList; }

FEMGaussQuadrature[...]

/** * Calculate one single integral via the gauss quadraturel * @param a, lower-border of the outer-integral * @param b, upper-border of the outer-integral * @param h1, first part of the integral * @param h2, second part of the integral * @param q, third part of the integral * @param z1, size of the vector in h1 (used to determine the position integer) * @param z2, size of the vector in h2 (used to determine the position integer) * @param ay "stuetzstellen" vector of "a" for y * @param hy "gewichtung" vector of "h" for y * @return result matrix or vector or value or whatever it calculates */public static MathObject calcSingleIntegration(double a, double b, Method h1, Method h2, Method q, int z1, int z2, Vector ay, Vector hy) { // Create the resulting MathObject MathObject resultObject = null; try {

if(z1 == z2) { // It's a matrix resultObject = MatrixFactory.createUserDefinedMatrix("GaussQuadrature Result", z1); } else if(z1 == 1 || z2 == 1) { // Take the bigger one if(z1 > z2) {

// It's a vector resultObject = new Vector("GaussQuadrature Result", z1);

} else {

// It's a vector resultObject = new Vector("GaussQuadrature Result", z2);

} } else {

if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Unknown result object requested (z1 / z2) :" + z1 + " / " + z2); } return null;

} /** * Start the calculation stuff * */ // Run through all positions in the result object for(int s = 1; s <= z1; s++) { for(int t = 1; t <= z2; t++) { // Calculate the sum: Hy * f( ((b-a)/2) * ay + ((b+a)/2) ) from j=1 to my double sum = 0; double xi = 0; for(int j = 1; j <= hy.size(); j++) { xi = ((b-a)/2) * ay.getValue(j) + ((b+a)/2);

double h1Value = callMethodCalculation(h1, xi, 0, s); double h2Value = callMethodCalculation(h2, xi, 0, t); double qValue = callMethodCalculation(q, xi, 0, j); sum = sum + hy.getValue(j) * (h1Value * h2Value * qValue);

} // Calc: ((b-a)/2) * sum double result = ((b-a) / 2) * sum; // Place the result into the result object if(resultObject instanceof Matrix) { ((Matrix)resultObject).setValue(s, t, result); } else if(resultObject instanceof Vector) { // Check which value has been greater if(z1 > z2) { // It's a vector with z1 running (which is 's') ((Vector)resultObject).setValue(s, result); } else { // It's a vector with z2 running (which is 't') ((Vector)resultObject).setValue(t, result); } } } }

} catch (FunctionCalculationException e) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "FunctionCalculationException, aborting GaussQuadrature !", e); } // Abort the program FEMStartup.abort(false); } catch (Exception e) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "An error occured during the GaussQuadrature !", e); } // Abort the program FEMStartup.abort(false); } return resultObject;

}[...]

FEMCalcTemperature/** * Munich University of Applied Sciences, FB07 Computer Science * DV-Anwendungen in der Technik - Prof.Dr.Gleich - 7.Semester * * Class Description: * This class extends from the FEMCalcGauss class taking care * of the whole calculation. The difference is that this class * overwrites the method start() as well as the method calculation() * from FEMCalc which is the base-class. It makes use of the method * compilation() from FEMCalcGauss. * * This class is being used when we have a FEM3 File with CTabs * used for temperature calculations. * * @author Thomas Woellert ([email protected]) * @author Stefan Weissbach ([email protected]) * * System: Linux 2.6, Sun Java JDK 5.0 * Semestergroup: 7T */package fhm.edu.fem.calc;

import java.lang.reflect.Method;import java.util.List;

import org.apache.log4j.Level;

import fhm.edu.fem.calc.objects.Border;import fhm.edu.fem.calc.objects.CTab;import fhm.edu.fem.calc.objects.CTabList;import fhm.edu.fem.calc.objects.Calculation;import fhm.edu.fem.calc.objects.CompilationFunctions;import fhm.edu.fem.calc.objects.Condition;import fhm.edu.fem.calc.objects.Element;import fhm.edu.fem.calc.objects.ElementList;import fhm.edu.fem.calc.objects.LineIntegralFunctions;import fhm.edu.fem.calc.objects.MathObject;import fhm.edu.fem.calc.objects.Node;import fhm.edu.fem.calc.objects.NodeList;import fhm.edu.fem.calc.objects.Vector;import fhm.edu.fem.calc.objects.matrix.Matrix;import fhm.edu.fem.constants.ApplicationConstants;import fhm.edu.fem.constants.GaussConstants;import fhm.edu.fem.exception.CholeskyFailedException;

public class FEMCalcTemperature extends FEMCalcGauss { /* Vector B */ protected Vector vectorB = null; /* f(x,y) constant value */ protected double fxyValue = -20; /* Alpha constant value */ protected double alpha = 2;

/* Inner and Outer Points ("Stuetzstellen des inneren und aeusseren Integrals") */protected static int OUTER_POINTS_LINE_INTEGRAL = 6;

/** * Create a new FEM Calculator for Temperature Tasks */ public FEMCalcTemperature() { // Call the super constructor super(); // Initialize the vector B this.vectorB = new Vector("Complete-Vector B", femManager.getNodeList().size()); } /** * Call this method to start the calculation * @return true if all went well, false otherwise */ public boolean start() { // Remember the starting time this.startTime = System.currentTimeMillis(); // Clear the result list of the FEMManager femManager.clearResultList(); if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Doing the compilation of the complete-stiffness-matrix ..."); } // Do the compilation this.tmpTime = System.currentTimeMillis(); if(!this.compilation()) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error during compilation of the complete-stiffness-matrix !"); } return false; } // Calc the time needed for the compilation this.tmpTime = System.currentTimeMillis() - this.tmpTime; if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Compilation of the Complete-Stiffness-Matrix successfully completed: " + this.tmpTime + " ms"); localLogger.log(Level.INFO, "Size of the Complete-Stiffness-Matrix: " + this.completeStiffnessMatrix.size() + "x" +this.completeStiffnessMatrix.size()); localLogger.log(Level.INFO, "Required Memory of the Complete-Stiffness-Matrix: " + this.completeStiffnessMatrix.getRequiredMemory() + " bytes"); } this.tmpTime = System.currentTimeMillis(); if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Testing if the Complete-Stiffness-Matrix is symmetric ..."); }

// Compilation done, test if the complete stiffness matrix is symmetric if(!this.completeStiffnessMatrix.isSymmetric()) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Complete Stiffness Matrix is not symmetric !"); } return false; } if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Testing if all elements on the main diagonal in the Complete-Stiffness-Matrix are not zero ..."); } // Check if the main diagonal of the complete stiffness matrix is not zero if(!this.completeStiffnessMatrix.isMainDiagonalNotZero()) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: At least one element on the main diagonal of the complete stiffness matrix is zero !"); } return false; } // Calc the time needed for the tests this.tmpTime = System.currentTimeMillis() - this.tmpTime; if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Time needed for the tests: " + this.tmpTime + " ms"); } if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Building Vector B ..."); } // Do the compilation this.tmpTime = System.currentTimeMillis(); if(!this.createVectorB()) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error during creation of Vector B !"); } return false; } // Calc the time needed for the compilation this.tmpTime = System.currentTimeMillis() - this.tmpTime; if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Creation of Vector B successfully completed: " + this.tmpTime + " ms"); localLogger.log(Level.INFO, "Size of the Vector B: " + this.vectorB.size()); } // Build the line integral this.tmpTime = System.currentTimeMillis(); if(!this.createLineIntegral()) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error during the creation of the line integral !"); } return false; } // Calc the time needed for the creation of the line integral this.tmpTime = System.currentTimeMillis() - this.tmpTime; if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Creation of the Line Integral successfully completed: " + this.tmpTime + " ms"); localLogger.log(Level.INFO, "Size of the new Complete-Stiffness-Matrix: " + this.completeStiffnessMatrix.size() + "x" +this.completeStiffnessMatrix.size()); localLogger.log(Level.INFO, "Required Memory of the new Complete-Stiffness-Matrix: " + this.completeStiffnessMatrix.getRequiredMemory() + " bytes"); } // Do the calculations if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Doing the calculations ..."); } // Run through all calculations List<Calculation> calculationList = femManager.getCalculationList(); for(int calcIndex = 0; calcIndex < calculationList.size(); calcIndex++) { // Remember the time at the start of this calculation this.tmpTime = System.currentTimeMillis(); if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Starting calculation: " + calcIndex); } // Grab calculation Calculation calc = calculationList.get(calcIndex); // Do the calculation if(!this.calculate(calc)) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error during calculation: " + calcIndex); } return false; } // Calculate the time needed to complete the current calculation this.tmpTime = System.currentTimeMillis() - this.tmpTime; if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Calculation " + calcIndex + " successfully completed: " + this.tmpTime + " ms"); } } // Calculate the total time this.totalTime = System.currentTimeMillis() - this.startTime;

if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "All calculations successfully completed - Total time: " + this.totalTime + " ms"); } return true;

} /** * Do the compilation of the vector B * @return true if all went well, false otherwise */ protected boolean createVectorB() { try { // Grab the approach from the manager int femApproach = femManager.getFEMApproach(); // Grab the list of all elements ElementList elementlist = femManager.getElementList(); // The variables to use in the Gauss Quadrature Method call double a = 0; double b = 1; Method h1 = null; Method h2 = null; Method q = null; int z1 = -1; int z2 = -1; Vector ax = GaussConstants.get(INNER_POINTS, GaussConstants.VALUE_A); Vector hx = GaussConstants.get(INNER_POINTS, GaussConstants.VALUE_H); Vector ay = GaussConstants.get(OUTER_POINTS, GaussConstants.VALUE_A); Vector hy = GaussConstants.get(OUTER_POINTS, GaussConstants.VALUE_H); MathObject integralResultObject = null; // Calculate how many percentage one element makes up double oneElementPercentage = 100.0 / elementlist.size(); // Calculate how many elements make up one percent double onePercentElements = elementlist.size() / 100.0; // Where we store the current actual percentage double currentPercentage = 0.0; // Run through all elements for(int elementIndex = 1; elementIndex <= elementlist.size(); elementIndex++) { // Calculate the current percentage of elements already done in the compilation currentPercentage = (elementIndex-1) * oneElementPercentage;

// Make a percentage output about every 5% of completed elements if(elementIndex%(onePercentElements*5.0) < 1) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Built at " + currentPercentage + " %"); } } // Get the current element Element tmpElement = elementlist.getElement(elementIndex); // Store the x- and y-values of the element nodes in the global data structure for the gauss quadrature CompilationFunctions.storeElementXYValues(tmpElement); // Check which kind of element we have int nodeListSize = tmpElement.getNodeList().size(); int elementType = -1; if(nodeListSize == 3) { // Linear triangle h1 = CompilationFunctions.getMethod(CompilationFunctions.TRIANGLE_LINEAR_N); h2 = CompilationFunctions.getMethod(CompilationFunctions.ONE); q = CompilationFunctions.getMethod(CompilationFunctions.TRIANGLE_LINEAR_ONETHROUGHJAC); z1 = 3; z2 = 1; elementType = GaussConstants.FIGURE_TRIANGLE; } else if(nodeListSize == 4) { // Linear quadrat h1 = CompilationFunctions.getMethod(CompilationFunctions.QUADRAT_LINEAR_N); h2 = CompilationFunctions.getMethod(CompilationFunctions.ONE); q = CompilationFunctions.getMethod(CompilationFunctions.QUADRAT_LINEAR_ONETHROUGHJAC); z1 = 4; z2 = 1; elementType = GaussConstants.FIGURE_PARALLELOGRAM; } else if(nodeListSize == 6) { // "Krummes" triangle h1 = CompilationFunctions.getMethod(CompilationFunctions.TRIANGLE_QUADRATIC_N); h2 = CompilationFunctions.getMethod(CompilationFunctions.ONE); q = CompilationFunctions.getMethod(CompilationFunctions.TRIANGLE_QUADRATIC_ONETHROUGHJAC); z1 = 6; z2 = 1; elementType = GaussConstants.FIGURE_TRIANGLE; } else if(nodeListSize == 8) { // "Krummes" quadrat h1 = CompilationFunctions.getMethod(CompilationFunctions.QUADRAT_QUADRATIC_N); h2 = CompilationFunctions.getMethod(CompilationFunctions.ONE); q = CompilationFunctions.getMethod(CompilationFunctions.QUADRAT_QUADRATIC_ONETHROUGHJAC); z1 = 8; z2 = 1; elementType = GaussConstants.FIGURE_PARALLELOGRAM; } else {

if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Unknown element type. Number of nodes: " + nodeListSize); }

}

// Calculate the integral integralResultObject = FEMGaussQuadrature.calcIntegration(a, b, h1, h2, q, z1, z2, ax, hx, ay, hy, elementType);

// Check if the result object matches our requirements if(!(integralResultObject instanceof Vector)) { // At least one of the result objects is not a Vector => ERROR if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "One of the integral result objects is not a Vector: " + integralResultObject.getClass()); }

return false; } // Calculate Vector B_e * f(x,y) Vector bElementVector = ((Vector)(integralResultObject)).mult(this.fxyValue); // Compile the new element Vector B_e onto the Complete-Vector-B NodeList elementNodeList = tmpElement.getNodeList(); for(int vecIndex = 1; vecIndex <= bElementVector.size(); vecIndex++) { Node tmpNode = elementNodeList.getNodeInCorrectOrder(vecIndex); int id = tmpNode.getId(); // Grab the current value from the element vector b and add it to the value in the gesamt vector b double elementValue = bElementVector.getValue(vecIndex); double newValue = this.vectorB.getValue(id) + elementValue; this.vectorB.setValue(id, newValue); } } } catch (Exception e) {

if(localLogger.isEnabledFor(Level.ERROR)) {localLogger.log(Level.ERROR, "Failure during compilation!", e);

}

return false; } return true; } /** * Build the line integral and compile it onto the complete stiffness matrix * @return true if all went well, false otherwise */ protected boolean createLineIntegral() { try { // Grab the ctab list CTabList ctabs = femManager.getCTabList(); // Run through all CTabs for(int ctabIndex = 1; ctabIndex <= ctabs.size(); ctabIndex++) { // The variables to use in the Gauss Quadrature Method call double a = 0; double b = 1; Method h1 = LineIntegralFunctions.getMethod(LineIntegralFunctions.N_SIGMA); Method q = LineIntegralFunctions.getMethod(LineIntegralFunctions.Q_ROOT); int z1 = 3; Vector ay = GaussConstants.get(OUTER_POINTS_LINE_INTEGRAL, GaussConstants.VALUE_A); Vector hy = GaussConstants.get(OUTER_POINTS_LINE_INTEGRAL, GaussConstants.VALUE_H); MathObject integralResultObject = null; // Grab the current ctab CTab tmpCtab = ctabs.getCTab(ctabIndex);

// Store the x- and y-values of the ctab nodes in the global data structure for the gauss quadrature LineIntegralFunctions.storeCtabXYValues(tmpCtab); // Calculate the single gauss quadrature integralResultObject = FEMGaussQuadrature.calcSingleIntegration(a, b, h1, h1, q, z1, z1, ay, hy); // Check if the result object matches our requirements if(!(integralResultObject instanceof Matrix)) { // At least one of the result objects is not a Matrix => ERROR if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "One of the integral result objects is not a Matrix !"); } return false; } // Bring the alpha constant into play Matrix resultMatrix = ((Matrix)(integralResultObject)).mult(this.alpha);

// Compile the resulting matrix onto the complete stiffness matrix for(int j = 1; j <= 3; j++) { // Grab the first node ID so we know where to place the value int nodeAId = tmpCtab.getNode(j).getId(); // Determine the starting valueof index K for the next lines, depending if we use a MATRIX_STANDARD or MATRIX_HULL int startOfIndexK = -1; if(ApplicationConstants.MATRIX_USE == ApplicationConstants.MATRIX_STANDARD) { // We are using a standard matrix startOfIndexK = 1; } else if(ApplicationConstants.MATRIX_USE == ApplicationConstants.MATRIX_HULL) { // We are using a hull matrix startOfIndexK = j; } for(int k = startOfIndexK; k <= 3; k++) { // Grab the second node ID so we know where to place the value int nodeBId = tmpCtab.getNode(k).getId(); // Grab the current value from the result matrix and add it to the value in the complete stiffness matrix double resultValue = resultMatrix.getValue(j, k); double newValue = this.completeStiffnessMatrix.getValue(nodeAId, nodeBId) + resultValue; this.completeStiffnessMatrix.setValue(nodeAId, nodeBId, newValue); } } } if(localLogger.isEnabledFor(Level.DEBUG)) { localLogger.log(Level.DEBUG, "Compilation complete !"); localLogger.log(Level.DEBUG, "Matrix size: " + this.completeStiffnessMatrix.size()); localLogger.log(Level.DEBUG, "CompleteStiffnessMatrix: " + this.completeStiffnessMatrix); } } catch (Exception e) {

if(localLogger.isEnabledFor(Level.ERROR)) {

localLogger.log(Level.ERROR, "Failure during the creation of the line integral!", e);}

return false; } return true; } /** * Do the calculation, overwritten from FEMCalc because we still need to get the results * of Vector B into the calculation * @param calc, the calculation object * @return true if all went well, false otherwise */ protected boolean calculate(Calculation calc) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Starting to clone the complete-stiffness-Matrix ..."); }

// Clone the complete stiffness matrix for us to change Matrix stiffnessMatrixClone = (Matrix)(this.completeStiffnessMatrix.clone()); /** * IMPLEMENT THE PREVIOUS RESULTS OF VECTOR B * */ if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Starting to implement previous results of Vector B ..."); } // We initialize the resulting vector b with the previously created Vector B Vector b = (Vector)(this.vectorB.clone()); // Normally we would add the results of Vector B to the results of the Line Integral, to do that while solving the calculation // we bring the results of Vector B onto the left side of the equation and therefore have to mulitply it with -1.0 // K*u = -b b = b.mult(-1.0);

/** * IMPLEMENT THE BORDER CONDITIONS * */ if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Starting to implement the border conditions ..."); } // Grab the conditions from the actual calculation List<Condition> conditionList = calc.getConditions(); // Run through all conditions for(int i = 0; i < conditionList.size(); i++) { // Grab the current condition Condition condition = conditionList.get(i); // Retrieve the value of the condition double conditionValue = condition.getValue(); // Get the border affected by this condition and grab all nodes from this border Border conditionBorder = condition.getBorder(); NodeList borderNodeList = conditionBorder.getNodes();

// Run through all nodes in the border for(int j = 1; j <= borderNodeList.size(); j++){ // Grab the current node from the border node list Node tmpNode = borderNodeList.getNodeInCorrectOrder(j);

// Retrieve the ID number of the current node int nodeId = tmpNode.getId(); // Run through the vector b for(int k = 1; k <= this.completeStiffnessMatrix.size(); k++){ // Calculate the new value of b[k] made up of b[k] - ( K[k][nodeID] * conditionValue ) double newValue = b.getValue(k) - (stiffnessMatrixClone.getValue(k, nodeId) * conditionValue);

// Set the new value for b b.setValue(k, newValue); }

// Set the condition value to the proper line in the vector b b.setValue(nodeId, conditionValue); // Fill the column and the line identified by the node ID with zeros stiffnessMatrixClone.setLineAndColumn(nodeId, 0); // Set the value "1" at the main diagonal element identified by K[nodeID][nodeID] stiffnessMatrixClone.setValue(nodeId, nodeId, 1); } } if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Implementing border conditions successfully completed"); localLogger.log(Level.INFO, "New required Memory of the MODIFIED Complete-Stiffness-Matrix: " + stiffnessMatrixClone.getRequiredMemory() + "bytes"); }

/** * Calculate the CHOLESKY * */ if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Starting to calculate the CHOLESKY ..."); } Matrix L = null; try { // Compute the CHOLESKY L = stiffnessMatrixClone.cholesky();

if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Computed CHOLESKY for Matrix: " + stiffnessMatrixClone.getName()); } if(localLogger.isEnabledFor(Level.DEBUG)) { localLogger.log(Level.DEBUG, "CHOLESKY: " + L); } } catch (CholeskyFailedException e) {

if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error while computing the CHOLESKY for Matrix: " + stiffnessMatrixClone.getName()); } return false; }

/** * Calculate the results by solving K*u = b * */ // Calculate Vector y from L*y=b Vector y = new Vector("y", this.completeStiffnessMatrix.size()); // Run through all element positions in the vector y for(int i = 1; i <= this.completeStiffnessMatrix.size(); i++) { double sum = 0; // Calculate the sum l[i][k]*y[k] from k=1 to [i-1] for(int k = 1; k <= (i-1); k++) { sum = sum + (L.getValue(i, k) * y.getValue(k)); } double newValue = (b.getValue(i) - sum) / L.getValue(i, i); y.setValue(i, newValue); } // Solve "L(transponated) * u = y" by calculating Vector u Vector u = new Vector("u", this.completeStiffnessMatrix.size()); // Run through all element positions in the vector u for(int i = this.completeStiffnessMatrix.size(); i >= 1; i--) { double sum = 0; // Calculate the sum l[k][i] * u[k] from k=i+1 to size of the matrix for(int k = (i+1); k <= this.completeStiffnessMatrix.size(); k++) { sum = sum + (L.getValue(k, i) * u.getValue(k)); } double newValue = (y.getValue(i) - sum) / L.getValue(i, i); u.setValue(i, newValue); } // Calculation for Vector u has been completed, save the results in the FEMManager femManager.addToResultList(u); if(localLogger.isEnabledFor(Level.DEBUG)) { localLogger.log(Level.DEBUG, "Vector u calculation successfull: " + u); } // Display the results for debug purposes FEMCalcTemperature.displaySpecificResults(u);

return true; } /** * This method displays the specific results for certain nodes * we need to compare the results with the ones from the "Schwartz" book * @param u, the result vector */ protected static void displaySpecificResults(Vector u) { if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Specific Results: NORMAL VERSION"); localLogger.log(Level.INFO, " A = " + u.getValue(1)); localLogger.log(Level.INFO, " B = " + u.getValue(11)); localLogger.log(Level.INFO, " C = " + u.getValue(56)); localLogger.log(Level.INFO, " D = " + u.getValue(154)); localLogger.log(Level.INFO, " E = " + u.getValue(205)); localLogger.log(Level.INFO, " F = " + u.getValue(193)); localLogger.log(Level.INFO, " H = " + u.getValue(150)); localLogger.log(Level.INFO, " I = " + u.getValue(111)); localLogger.log(Level.INFO, " K = " + u.getValue(86)); localLogger.log(Level.INFO, " L = " + u.getValue(110)); localLogger.log(Level.INFO, " M = " + u.getValue(57)); } if(localLogger.isEnabledFor(Level.INFO)) { localLogger.log(Level.INFO, "Specific Results: FINE VERSION"); localLogger.log(Level.INFO, " A = " + u.getValue(1)); localLogger.log(Level.INFO, " B = " + u.getValue(35)); localLogger.log(Level.INFO, " C = " + u.getValue(203)); localLogger.log(Level.INFO, " D = " + u.getValue(559)); localLogger.log(Level.INFO, " E = " + u.getValue(745)); localLogger.log(Level.INFO, " F = " + u.getValue(704)); localLogger.log(Level.INFO, " H = " + u.getValue(555)); localLogger.log(Level.INFO, " I = " + u.getValue(409)); localLogger.log(Level.INFO, " K = " + u.getValue(322)); localLogger.log(Level.INFO, " L = " + u.getValue(410)); localLogger.log(Level.INFO, " M = " + u.getValue(201)); } }}

CTab/** * Munich University of Applied Sciences, FB07 Computer Science * DV-Anwendungen in der Technik - Prof.Dr.Gleich - 7.Semester * * Class Description: * This class represents a "ctab" * * @author Thomas Woellert ([email protected]) * @author Stefan Weissbach ([email protected]) * * System: Linux 2.6, Sun Java JDK 5.0 * Semestergroup: 7T */package fhm.edu.fem.calc.objects;

import org.apache.log4j.Level;import org.apache.log4j.Logger;

import fhm.edu.fem.util.logging.LoggingManager;

public class CTab {

/* Our local logger object */protected static Logger localLogger = LoggingManager.getLogger(CTab.class.getName());

/* The nodes forming the CTab */ protected Node midNode = null; protected Node leftNode = null; protected Node rightNode = null; /* The ID of the CTab */ protected int id = -1; /** * Construct a new CTab * @param id, the ID number * @param leftNode, the left node * @param midNode, the middle node * @param rightNode, the right node */ public CTab(int id, Node leftNode, Node midNode, Node rightNode) { this.id = id; this.midNode = midNode; this.leftNode = leftNode; this.rightNode = rightNode; } /** * @return Returns the id. */ public int getId() { return this.id; } /** * @return Returns the left node. */ public Node getLeftNode() { return this.leftNode; } /** * @return Returns the right node. */ public Node getRightNode() { return this.rightNode; } /** * @return Returns the mid node. */ public Node getMidNode() { return this.midNode; } /** * Returns the node depending on i * usage: i = 1 (left node), 2 (mid node), 3 (right node) * @param i, may be 1 (left node), 2 (mid node), 3 (right node) * @return the requested node */ public Node getNode(int i) { switch(i) { case 1: return this.leftNode; case 2: return this.midNode; case 3: return this.rightNode; default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown number to get a node, usage: 1 = left, 2 = mid, 3 = right !"); } } return null; } /** * Implementation of the toString() method * @return a string visualization of the element */ public String toString() { return "[CTab id=" + this.id + " left_node_id = " + leftNode.getId() + " mid_node_id = " + midNode.getId() + " right_node_id = " + rightNode.getId() +"]"; }}

CTabList/** * Munich University of Applied Sciences, FB07 Computer Science * DV-Anwendungen in der Technik - Prof.Dr.Gleich - 7.Semester * * Class Description: * This class acts as ctab list. It takes the ctab index from the ctab itself * * @author Thomas Woellert ([email protected]) * @author Stefan Weissbach ([email protected]) * * System: Linux 2.6, Sun Java JDK 5.0 * Semestergroup: 7T */package fhm.edu.fem.calc.objects;

import java.util.ArrayList;import java.util.Iterator;

import org.apache.log4j.Logger;

import fhm.edu.fem.util.logging.LoggingManager;

public class CTabList {

/* Our local logger object */protected static Logger localLogger = LoggingManager.getLogger(CTabList.class.getName());

/* The List object where we store our elements */protected ArrayList<CTab> ctabs = new ArrayList<CTab>();

/** * Create a new ctab list */public CTabList() {}

/** * Set a new ctab in the list. It will be set at the index specified in the ctab * @param ctab, the ctab to set */public void setCTab(CTab ctab) { ctabs.add(ctab);}

/** * Retrieve a ctab with the given index from the list * @param ctabIndex * @return the found ctab */public CTab getCTab(int ctabIndex) {

// Run through the list and find the element with the given indexIterator it = ctabs.iterator();CTab tmpCTab = null;

while(it.hasNext()) {// Grab the next ctab from the listtmpCTab = (CTab)(it.next());

// Check if it is the ctab we are searching forif(tmpCTab != null) {

if(ctabIndex == tmpCTab.getId()) {

// We found the correct ctab, return itreturn tmpCTab;

}}

}

// We found no proper ctabreturn null;

}

/** * Convert this list to an array of ctab * @return the ctab array */public Object[] toArray() {

return this.ctabs.toArray();}

/** * Clear the list */public void clear() {

this.ctabs.clear();}

/** * Retrieve the number of ctabs in the list * @return the number of ctabs */public int size() {

return this.ctabs.size();}

/** * Clone Implementation * @return a clone of this list */public Object clone() {

// Create the new listCTabList cloneList = new CTabList();

// Fill the new list with the same ctabs as the current listObject[] ctabArray = this.toArray();

for(int i = 0; i < ctabArray.length; i++) {cloneList.setCTab((CTab)(ctabArray[i]));

}

return cloneList;}

}

LineIntegralFunctions/** * Munich University of Applied Sciences, FB07 Computer Science * DV-Anwendungen in der Technik - Prof.Dr.Gleich - 7.Semester * * Class Description: * Holds all the static function methods needed for the * calculation of the line integral when we deal with * temperature problems via FEMCalcTemperature * * @author Thomas Woellert ([email protected]) * @author Stefan Weissbach ([email protected]) * * System: Linux 2.6, Sun Java JDK 5.0 * Semestergroup: 7T */package fhm.edu.fem.calc.objects;

import java.lang.reflect.Method;

import org.apache.log4j.Level;import org.apache.log4j.Logger;

import fhm.edu.fem.exception.FunctionCalculationException;import fhm.edu.fem.util.logging.LoggingManager;

public class LineIntegralFunctions {

/* Our local logger object */protected static Logger localLogger = LoggingManager.getLogger(LineIntegralFunctions.class.getName());

/* The method names */public static final String N_SIGMA = "nSigma";public static final String Q_ROOT = "qRoot";

/* Global data structure to remember the current x- and y-values of the element, used in the Q_ROOT method */protected static double[] ctabXValues;protected static double[] ctabYValues;

/** * Get the proper method * @param methodName, the method name taken from the constants in this class * @return the method */public static Method getMethod(String methodName) throws SecurityException, NoSuchMethodException { // Build the args array Class args[] = new Class[3]; args[0] = Double.class; args[1] = Double.class; args[2] = Integer.class; return LineIntegralFunctions.class.getDeclaredMethod(methodName, args);}

/** * To remember the current ctabs x- and y-values in the static data * structure here in this class - used in the XXI, XETA, YXI, YETA methods * @param element, the element which values we want to store */public static void storeCtabXYValues(CTab ctab) {

// Create the arrays, depending on the number of element nodes LineIntegralFunctions.ctabXValues = new double[3]; LineIntegralFunctions.ctabYValues = new double[3];

// Grab the nodes from the ctab and store them in the double arrays Node tmpNode = ctab.getLeftNode(); LineIntegralFunctions.ctabXValues[0] = tmpNode.getX(); LineIntegralFunctions.ctabYValues[0] = tmpNode.getY();

tmpNode = ctab.getMidNode(); LineIntegralFunctions.ctabXValues[1] = tmpNode.getX(); LineIntegralFunctions.ctabYValues[1] = tmpNode.getY();

tmpNode = ctab.getRightNode(); LineIntegralFunctions.ctabXValues[2] = tmpNode.getX(); LineIntegralFunctions.ctabYValues[2] = tmpNode.getY();}

/** * Function for N derived to Sigma * * @param sigma * @param empty * @param position * @return */ public static double nSigma(Double sigma, Double empty, Integer position) throws FunctionCalculationException {

// Determine which position in the vector the user wants to calculate switch(position.intValue()) { case 1: return (1.0 - 3.0*sigma.doubleValue() + 2.0*Math.pow(sigma.doubleValue(), 2)); case 2:

return (4.0*sigma.doubleValue() - 4.0*Math.pow(sigma.doubleValue(), 2)); case 3: return (-1.0 * sigma.doubleValue() + 2.0*Math.pow(sigma.doubleValue(), 2)); default: if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Unknown position in function vector given: " + position); } throw new FunctionCalculationException("Illegal position value: " + position); } } /** * Function for q Root * * @param sigma * @param empty * @param position * @return */ public static double qRoot(Double sigma, Double empty, Integer position) throws FunctionCalculationException {

// Check if the number if coordinates in the static arrays match our requirements if(LineIntegralFunctions.ctabXValues.length < 3 || LineIntegralFunctions.ctabYValues.length < 3) { if(localLogger.isEnabledFor(Level.ERROR)) { localLogger.log(Level.ERROR, "Error: Insufficient number of x- and y-coordinates stored in the static arrays !"); } throw new FunctionCalculationException("Insufficient number of coordinates in static arrays !"); } double valueX = 0.0; double valueY = 0.0; // Calculate (x * N')^2 + (y * N')^2 valueX = LineIntegralFunctions.ctabXValues[0] * (-3.0 + 4.0*sigma.doubleValue()) + LineIntegralFunctions.ctabXValues[1] * (4.0 -8.0*sigma.doubleValue()) + LineIntegralFunctions.ctabXValues[2] * (-1.0 + 4.0*sigma.doubleValue()); valueY = LineIntegralFunctions.ctabYValues[0] * (-3.0 + 4.0*sigma.doubleValue()) + LineIntegralFunctions.ctabYValues[1] * (4.0 -8.0*sigma.doubleValue()) + LineIntegralFunctions.ctabYValues[2] * (-1.0 + 4.0*sigma.doubleValue()); return Math.sqrt(valueX*valueX + valueY*valueY); }}

3. Testmaterial:3.1 Grundeinteilung: etwa entsprechend der Figur 6.2 in dem Lehrbuch von H.R. Schwarz.3.2 eine Verfeinerung - Falls dies nicht mit zu viel Aufwand verbunden ist:Achten Sie darauf, dass dann die neuen Knoten des Kreisbogens nicht auf Sehnen, sondern aufdem Kreis liegen (z.B. nachträgliche Korrektur mit Polarkoordinaten) - Die Punkte A bis M derFigur 6.1 sollten Knotenpunkte sein.

Zahlenergebnisse:Eine kleine Tabelle, die für jede der beiden Einteilungen die Funktionswerte in den Punkten Abis M enthält. Vergleichen Sie Ihre Ergebnisse mit denjenigen in dem Lehrbuch von H.R.Schwarz, Tab. 6.2 und Tab. 6.3 (exakte Übereinstimmung ist (vielleicht?) in Tab. 6.3/II’ zuerwarten).

Funktionswerte - Einteilung Fig.6.2 - Ergebnisse Tab.6.2 (H.R.Schwarz) - 6-8 Stützstellen

Knotenbezeichnung Unsere Knotennr. Fall I Fall II Fall III Unsere ErgebnisseA 1 0.0 0.0 0.0 0.0B 11 0.0 0.0 0.0 0.0C 56 85.18 84.17 84.05 84.18005839954856D 154 158.29 156.66 156.10 156.73970493025243E 205 105.90 104.28 103.71 104.28284218830943F 193 38.79 37.22 36.65 37.18103972808866H 150 41.16 39.57 39.11 39.725367976200396I 111 31.67 30.44 30.09 30.441530798492245K 86 25.08 24.10 23.95 24.020995398670333L 110 27.87 26.85 26.53 26.85242589245469M 57 74.99 74.15 74.02 74.18800278215643

Funktionswerte - Verfeinerung - Ergebnisse Tab.6.3 (H.R.Schwarz) - 6-8 Stützstellen

Knotenbezeichnung Unsere Knotennr. Fall I’ Fall II’ Fall III’ Unsere ErgebnisseA 1 0.0 0.0 0.0 0.0B 35 0.0 0.0 0.0 0.0C 203 82.69 83.05 83.42 84.56055050145876D 559 155.10 155.23 155.29 156.79983988834877E 745 102.56 102.78 102.86 104.37411450490212F 704 36.00 35.90 35.88 37.133629414156395H 555 38.50 38.28 38.36 39.76137928665349I 409 29.48 29.40 29.48 30.521341484869676K 322 23.36 23.28 23.47 24.193705417813295L 410 26.05 25.98 26.02 26.89437558638322M 201 73.03 73.27 73.52 74.44584944665975

52

KommentarBerechnet wurden unsere Ergebnisse mit 8 Stützstellen für das innere und 6 Stützstellen für dasäussere Integral bei der Kompilierung der Gesamtsteifigkeitsmatrix. Bei der Berechnung desLinienintegrals haben wir 6 Stützstellen eingesetzt.

Wie Sie aus der Tabelle entnehmen können, bilden unsere Ergebnisse eine gute Näherung andie Werte aus dem Buch von H.R.Schwarz. Sie stimmen zwar nicht genau überein, allerdingsliegen diese Differenzen in einem vertretbaren Rahmen, wie man auch an den Linien gleicherTemperaturen auf den folgenden Seiten für beide Einteilungen sehen kann. Diese stimmen sehrgut mit dem Bild der Temperaturverteilung (Fig. 6.45) von H.R.Schwarz zusammen. Im erstenBild kann man noch gewisse Ungenauigkeiten bemerken allerdings treten diese aufgrund der,doch eher groben, Einteilung des Funktionsgebiets auf. Im zweiten Bild sieht man die feinereEinteilung des Gebietes, welche zu Resultaten führt die um einiges besser sind.

53

Grafische Darstellungen:Jeweils Linien gleicher Temperatur für die beiden Beispiele - Fig. 6.45 zeigt eineVergleichszeichnung.

Einteilung nach Fig. 6.2 (205 Knoten, 48 Dreiecke, 24 Vierecke) - Linien gleicherTemperaturen

54

Verfeinerung (745 Knoten, 192 Dreiecke, 96 Vierecke) - Linien gleicher Temperaturen

55