Your program calculates the final temperature for each region on the
piece of alloy. The new temperature for a given region of the alloy
is calculated using the formula

where represents each of the three base metals, is the thermal constant for metal , is the set representing the neighbouring regions, is the temperature of the neighbouring region, is the percentage of metal in neighbour , and is the number of neighbouring regions. This computation is repeated until the temperatures converge to a final value or a reasonable maximum number of iterations is reached.

The values for , , , , , the dimensions of the mesh, and the threshold should be parameters to the program. Note however, that combinations of these parameters do not do not converge well. Try values of (0.75, 1.0, 1.25) C1, C2, C3 for your test/demo.

Assume that the edges are maximally insulated from their surroundings.

Your program should graphically display the results by drawing a grid of points with intensities or colors indicating temperature. (Alternatively, you can just output them to a file and use something like gnuplot to display them.)

Acknowledgment: This assignment was adapted from a study by Steve MacDonald.

abstract class JTree extends RecursiveAction { volatile double maxDiff; // for convergence check } class Interior extends JTree { private final JTree[] quads; Interior(JTree q1, JTree q2, JTree q3, JTree q4) { quads = new JTree[] { q1, q2, q3, q4 }; } public void compute() { invoke(quads); double md = 0.0; for (int i = 0; i < quads.length; ++i) { md = Math.max(md,quads[i].maxDiff); quads[i].reset(); } maxDiff = md; } } class Leaf extends JTree { private final double[][] A; private final double[][] B; private final int loRow; private final int hiRow; private final int loCol; private final int hiCol; private int steps = 0; Leaf(double[][] A, double[][] B, int loRow, int hiRow, int loCol, int hiCol) { this.A = A; this.B = B; this.loRow = loRow; this.hiRow = hiRow; this.loCol = loCol; this.hiCol = hiCol; } public void compute() { boolean AtoB = (steps++ % 2) == 0; double[][] a = (AtoB)? A : B; double[][] b = (AtoB)? B : A; double md = 0.0; for (int i = loRow; i <= hiRow; ++i) { for (int j = loCol; j <= hiCol; ++j) { b[i][j] = 0.25 * (a[i-1][j] + a[i][j-1] + a[i+1][j] + a[i][j+1]); md = Math.max(md, Math.abs(b[i][j] - a[i][j])); } } maxDiff = md; } } class Jacobi extends RecursiveAction { static final double EPSILON = 0.001; // convergence criterion final JTree root; final int maxSteps; Jacobi(double[][] A, double[][] B, int firstRow, int lastRow, int firstCol, int lastCol, int maxSteps, int leafCells) { this.maxSteps = maxSteps; root = build(A, B, firstRow, lastRow, firstCol, lastCol, leafCells); } public void compute() { for (int i = 0; i < maxSteps; ++i) { invoke(root); if (root.maxDiff < EPSILON) { System.out.println("Converged"); return; } else root.reinitialize(); } } static JTree build(double[][] a, double[][] b, int lr, int hr, int lc, int hc, int size) { if ((hr - lr + 1) * (hc - lc + 1) <= size) return new Leaf(a, b, lr, hr, lc, hc); int mr = (lr + hr) / 2; // midpoints int mc = (lc + hc) / 2; return new Interior(build(a, b, lr, mr, lc, mc, size), build(a, b, lr, mr, mc+1, hc, size), build(a, b, mr+1, hr, lc, mc, size), build(a, b, mr+1, hr, mc+1, hc, size)); } }