//******************************************************************************
//
// File:    HotSpotClu.java
// Package: edu.rit.clu.heat
// Unit:    Class edu.rit.clu.heat.HotSpotClu
//
// This Java source file is copyright (C) 2008 by Alan Kaminsky. All rights
// reserved. For further information, contact the author, Alan Kaminsky, at
// ark@cs.rit.edu.
//
// This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
// software; you can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// PJ is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// A copy of the GNU General Public License is provided in the file gpl.txt. You
// may also obtain a copy of the GNU General Public License on the World Wide
// Web at http://www.gnu.org/licenses/gpl.html.
//
//******************************************************************************

package edu.rit.clu.heat;

import edu.rit.color.HSB;

import edu.rit.image.ColorImageRow;
import edu.rit.image.PJGHueImage;
import edu.rit.image.PJGImage;

import edu.rit.io.Files;

import edu.rit.mp.DoubleBuf;

import edu.rit.mp.buf.DoubleItemBuf;

import edu.rit.pj.Comm;

import edu.rit.pj.reduction.DoubleOp;

import edu.rit.util.Arrays;
import edu.rit.util.Range;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;

/**
 * Class HotSpotClu is a cluster parallel program that calculates the
 * temperature distribution over a metal plate with hot spots.
 * 

* Usage: java -Dpj.np=K edu.rit.clu.heat.HotSpotClu imagefile * H W rl1 cl1 ru1 cu1 temp1 [ * rl2 cl2 ru2 cu2 temp2 . . . ] *
K = Number of parallel processes *
imagefile = Output image file name *
H = Mesh height in pixels (H >= 1) *
W = Mesh width in pixels (W >= 1) *
rl1 = First hot spot lower row (1 <= rl1 <= * W) *
cl1 = First hot spot lower column (1 <= cl1 <= * W) *
ru1 = First hot spot upper row (1 <= ru1 <= * W) *
cu1 = First hot spot upper column (1 <= cu1 <= * W) *
temp1 = First hot spot temperature (0.0 <= temp1 <= * 100.0) *

* The program sets up a mesh of equally-spaced points with H+2 rows and * W+2 columns. The temperature of each boundary point [r,c], * where r = 0, r = H+1, c = 0, or c = * W+1, is fixed at 0.0. The temperatures at certain interior points, * known as "hot spots," are fixed at certain values greater than 0.0. * Specifically, the temperature of each point in the rectangle from * [rl1,cl1] to [ru1,cu1] inclusive is fixed at temp1, the * temperature of each point in the rectangle from [rl2,cl2] to * [ru2,cu2] inclusive is fixed at temp2, and so on. The program * calculates the temperature at every interior point (other than the hot spots) * using successive overrelaxation with Chebyshev acceleration and red-black * updating. The program outputs a PJG color image H+2 pixels high and * W+2 pixels wide. Each pixel's hue depends on the corresponding mesh * point's temperature. A temperature of 0.0 is blue; a temperature of 100.0 is * red; intermediate temperatures are intermediate hues. Each process writes its * own PJG image file with a slice of the image. If imagefile is * specified as "out.pjg", for example, then process 0 writes file * "out_0.pjg", process 1 writes file "out_1.pjg", and so on. *

* The computation is performed in parallel in multiple processors. The program * measures the computation's running time. * * @author Alan Kaminsky * @version 11-Apr-2008 */ public class HotSpotClu { // Prevent construction. private HotSpotClu() { } // Hidden constants. private static final double MIN_TEMP = 0.0; private static final double MAX_TEMP = 100.0; private static final double DELTA_TEMP = MAX_TEMP - MIN_TEMP; private static final double MIN_HUE = 4.0/6.0; private static final double MAX_HUE = 0.0; private static final double DELTA_HUE = MAX_HUE - MIN_HUE; private static final double EPS = 1.0e-3; private static final int FIRST = 0; private static final int MIDDLE = 1; private static final int LAST = 2; private static final int SINGLE = 3; // Hidden variables. // World communicator. static Comm world; static int size; static int rank; static int position; static int predRank; static int succRank; // Command line arguments. static File imagefile; static int H; static int W; // Row slice index ranges. static Range[] slices; static Range mySlice; static int myLb; static int myUb; static int myLen; // Temperature grid. static double[][] h; // Mesh of hot spot locations. static boolean[][] hotspot; // Variables for total absolute residual. static double EPS_initialTotalAbsXi; static double totalAbsXi; // Other variables used in the successive overrrelaxation algorithm. static int MAXITER; static double rho_s_sqr; static double omega_over_4; static int iterations; // Communication buffers. static DoubleItemBuf xibuf; static DoubleBuf hbuf_pred_red; static DoubleBuf hbuf_pred_black; static DoubleBuf hbuf_top_red; static DoubleBuf hbuf_top_black; static DoubleBuf hbuf_bottom_red; static DoubleBuf hbuf_bottom_black; static DoubleBuf hbuf_succ_red; static DoubleBuf hbuf_succ_black; // Main program. /** * Main program. */ public static void main (String[] args) throws Exception { // Start timing. long t1 = System.currentTimeMillis(); // Initialize world communicator. Comm.init (args); world = Comm.world(); size = world.size(); rank = world.rank(); if (size == 1) position = SINGLE; else if (rank == 0) position = FIRST; else if (rank < size-1) position = MIDDLE; else position = LAST; predRank = rank - 1; succRank = rank + 1; // Parse command line arguments. if (args.length < 8 || (args.length % 5) != 3) usage(); imagefile = new File (args[0]); H = Integer.parseInt (args[1]); W = Integer.parseInt (args[2]); if (H < 1) usage(); if (W < 1) usage(); // Determine row slice index ranges. slices = new Range (1, H) .subranges (size); mySlice = slices[rank]; myLb = mySlice.lb(); myUb = mySlice.ub(); myLen = mySlice.length(); // Initialize temperature and hot spot meshes. h = new double [H+2] []; Arrays.allocate (h, new Range (myLb-1, myUb+1), W+2); hotspot = new boolean [H+2] []; Arrays.allocate (hotspot, new Range (myLb-1, myUb+1), W+2); // Record hot spot coordinates and temperatures. int n = (args.length - 3) / 5; for (int i = 0; i < n; ++ i) { int rl = Integer.parseInt (args[3+5*i]); int cl = Integer.parseInt (args[4+5*i]); int ru = Integer.parseInt (args[5+5*i]); int cu = Integer.parseInt (args[6+5*i]); double temp = Double.parseDouble (args[7+5*i]); if (1 > rl || rl > W) usage(); if (1 > cl || cl > H) usage(); if (1 > ru || ru > W) usage(); if (1 > cu || cu > H) usage(); if (MIN_TEMP > temp || temp > MAX_TEMP) usage(); for (int r = rl; r <= ru; ++ r) { double[] h_r = h[r]; boolean[] hotspot_r = hotspot[r]; if (h_r != null) { for (int c = cl; c <= cu; ++ c) { h_r[c] = temp; hotspot_r[c] = true; } } } } // Initialize communication buffers. xibuf = DoubleBuf.buffer(); hbuf_pred_red = redBuffer (myLb-1); hbuf_pred_black = blackBuffer (myLb-1); hbuf_top_red = redBuffer (myLb); hbuf_top_black = blackBuffer (myLb); hbuf_bottom_red = redBuffer (myUb); hbuf_bottom_black = blackBuffer (myUb); hbuf_succ_red = redBuffer (myUb+1); hbuf_succ_black = blackBuffer (myUb+1); // Compute initial total absolute residual, then multiply by EPS. totalAbsXi = 0.0; double xi; for (int r = myLb; r <= myUb; ++ r) { double[] h_rm1 = h[r-1]; double[] h_r = h[r]; double[] h_rp1 = h[r+1]; boolean[] hotspot_r = hotspot[r]; for (int c = 1; c <= W; ++ c) { xi = hotspot_r[c] ? 0.0 : h_rm1[c]+h_rp1[c]+h_r[c-1]+h_r[c+1]-4.0*h_r[c]; totalAbsXi += Math.abs (xi); } } xibuf.item = totalAbsXi; world.allReduce (xibuf, DoubleOp.SUM); totalAbsXi = xibuf.item; EPS_initialTotalAbsXi = EPS * totalAbsXi; // Initialize other variables. MAXITER = 2 * (W + H); rho_s_sqr = 0.5 * (Math.cos (Math.PI/W) + Math.cos (Math.PI/H)); rho_s_sqr = rho_s_sqr * rho_s_sqr; omega_over_4 = 0.25; iterations = 0; long t2 = System.currentTimeMillis(); // Perform successive overrelaxation. do { totalAbsXi = 0.0; // Red half-sweep. for (int r = myLb; r <= myUb; ++ r) { double[] h_rm1 = h[r-1]; double[] h_r = h[r]; double[] h_rp1 = h[r+1]; boolean[] hotspot_r = hotspot[r]; for (int c = 1 + (r&1); c <= W; c += 2) { xi = hotspot_r[c] ? 0.0 : h_rm1[c]+h_rp1[c]+h_r[c-1]+h_r[c+1]-4.0*h_r[c]; totalAbsXi += Math.abs (xi); h_r[c] += omega_over_4 * xi; } } omega_over_4 = 0.25 / (1.0 - rho_s_sqr * (iterations == 0 ? 0.5 : omega_over_4)); // Exchange boundary row red cells with neighboring processes. switch (position) { case FIRST: world.send (succRank, hbuf_bottom_red); world.receive (succRank, hbuf_succ_red); break; case MIDDLE: world.sendReceive (succRank, hbuf_bottom_red, predRank, hbuf_pred_red); world.sendReceive (predRank, hbuf_top_red, succRank, hbuf_succ_red); break; case LAST: world.receive (predRank, hbuf_pred_red); world.send (predRank, hbuf_top_red); break; } // Black half-sweep. for (int r = myLb; r <= myUb; ++ r) { double[] h_rm1 = h[r-1]; double[] h_r = h[r]; double[] h_rp1 = h[r+1]; boolean[] hotspot_r = hotspot[r]; for (int c = 2 - (r&1); c <= W; c += 2) { xi = hotspot_r[c] ? 0.0 : h_rm1[c]+h_rp1[c]+h_r[c-1]+h_r[c+1]-4.0*h_r[c]; totalAbsXi += Math.abs (xi); h_r[c] += omega_over_4 * xi; } } omega_over_4 = 0.25 / (1.0 - rho_s_sqr * omega_over_4); // Exchange boundary row black cells with neighboring processes. switch (position) { case FIRST: world.send (succRank, hbuf_bottom_black); world.receive (succRank, hbuf_succ_black); break; case MIDDLE: world.sendReceive (succRank, hbuf_bottom_black, predRank, hbuf_pred_black); world.sendReceive (predRank, hbuf_top_black, succRank, hbuf_succ_black); break; case LAST: world.receive (predRank, hbuf_pred_black); world.send (predRank, hbuf_top_black); break; } // Determine total absolute residual from all processes. xibuf.item = totalAbsXi; world.allReduce (xibuf, DoubleOp.SUM); totalAbsXi = xibuf.item; ++ iterations; } while (iterations < MAXITER && totalAbsXi >= EPS_initialTotalAbsXi); // Check for convergence. if (iterations == MAXITER) { System.err.println ("HotSpotClu: Did not converge"); System.exit (1); } long t3 = System.currentTimeMillis(); // Generate image. int[][] matrix = new int [H+2] []; int rlb = rank == 0 ? myLb-1 : myLb; int rub = rank == size-1 ? myUb+1 : myUb; Arrays.allocate (matrix, new Range (rlb, rub), W+2); ColorImageRow matrix_r = new ColorImageRow (matrix[rlb]); for (int r = rlb; r <= rub; ++ r) { double[] h_r = h[r]; matrix_r.setArray (matrix[r]); for (int c = 0; c <= W+1; ++ c) { matrix_r.setPixelHSB (/*c */ c, /*hue*/ (float) ((h_r[c]-MIN_TEMP)/DELTA_TEMP*DELTA_HUE+MIN_HUE), /*sat*/ 1.0f, /*bri*/ 1.0f); } } PJGHueImage image = new PJGHueImage (H+2, W+2, matrix); PJGImage.Writer writer = image.prepareToWrite (new BufferedOutputStream (new FileOutputStream (Files.fileForRank (imagefile, rank)))); writer.writeRowSlice (new Range (rlb, rub)); writer.close(); // Stop timing. long t4 = System.currentTimeMillis(); System.out.println (iterations + " iterations " + rank); System.out.println ((t2-t1) + " msec pre " + rank); System.out.println ((t3-t2) + " msec calc " + rank); System.out.println ((t4-t3) + " msec post " + rank); System.out.println ((t4-t1) + " msec total " + rank); } // Hidden operations. /** * Returns a communication buffer for the red columns of the given row of * the h matrix. * * @param r Row index. * * @return Communication buffer. */ private static DoubleBuf redBuffer (int r) { return DoubleBuf.sliceBuffer (h[r], new Range (1 + (r&1), W, 2)); } /** * Returns a communication buffer for the black columns of the given row of * the h matrix. * * @param r Row index. * * @return Communication buffer. */ private static DoubleBuf blackBuffer (int r) { return DoubleBuf.sliceBuffer (h[r], new Range (2 - (r&1), W, 2)); } /** * Print a usage message and exit. */ private static void usage() { System.err.println ("Usage: java -Dpj.np= edu.rit.clu.heat.HotSpotClu [ . . . ]"); System.err.println (" = Number of parallel processes"); System.err.println (" = Output image file name"); System.err.println (" = Mesh height in pixels ( >= 1)"); System.err.println (" = Mesh width in pixels ( >= 1)"); System.err.println (" = First hot spot lower row (1 <= <= )"); System.err.println (" = First hot spot lower column (1 <= <= )"); System.err.println (" = First hot spot upper row (1 <= <= )"); System.err.println (" = First hot spot upper column (1 <= <= )"); System.err.println (" = First hot spot temperature (0.0 <= <= 100.0)"); System.exit (1); } }

Ads help maintain this website.