In: Computer Science
Code in Java Successive Over-Relaxation (SOR) method.
`Hey,
Note: Brother if you have any queries related the answer please do comment. I would be very happy to resolve all your queries.
package ie.ucd.mscba.algorithm;
import ie.ucd.mscba.io.OutputFile;
import java.lang.Math;
import java.util.Formatter;
// Class to analyse the CRS Arrays and perform the SOR
algorithm
public class SOR
{
// Class Fields
private Formatter f = new Formatter();
// For formatted writing to
output file
private OutputFile
outFile;
private double [] val;
// Array of values of the nonzero elements of
the matrix
private int []
col;
// Array of column locations of the elements in
the val vector
private int []
rowStart;
// Array
of locations in the val vector that start a row
private double []
b;
// Solution vector
private double []
x;
// This is the initial guess that is calculated
below
private double []
xOld;
private double omega =
1.0;
// Omega
is determined to be between 1.0 and 1.4 - We choose 1.2
private final int maxits =
50;
// Total
number of iterations before halting algorithm
private int
matrixSize;
private double
machEpsilon;
//
Calculate using method below
private int sorCounter;
// Number of iterations
performed
private double xTol = 1;
// Need to set to 1 for first
iteration
private double residVal = 1;
private boolean diagonalDom;
// Need to implement column
diagonal dominance, do so from input file and change
row/col_pointer
/**
* Constructor that sets the size of field variables to
their appropriate values
**/
public SOR( int t, int matrixSize, OutputFile
outFile)
{
this.outFile =
outFile;
this.matrixSize =
matrixSize;
val =
new double[t];
col =
new int[t];
rowStart = new int[matrixSize +
1];
b =
new double[matrixSize];
}
/**
* This method populates the fields above where the
initial guess is calculated. This method will benefit the
* greatest when the matrix is a band matrix
*
*/
public void calculateInitialGuess()
{
x = divide();
xOld = divide();
//for(int i=0; i<matrixSize;
i++)
//
System.out.println("initial guess element["+ i + "] = " +
x[i]);
}
/**
* Determines if the matrix A(or CRS arrays in this
case) is both column and
* row diagonally dominant
*/
public void testDiagonal() {
double diagVal = 0;
// Variable to store the diagonal element
double sumrow;
int count = 0;
// Loop to check for row diagonal
dominance
for (int i = 0; i <= (matrixSize
- 1); i++)
// Each row
{
sumrow = 0;
for (int j =
rowStart[i]; j <= (rowStart[i + 1] - 1); j++)
{
if (col[j] == i) {
//
Diagonal elements of the matrix
diagVal = Math.abs(val[j]);
// Store
in variable d in 'abs' form
}
else
{
sumrow +=
(Math.abs(val[j]));
// If not diagonal, store in sumrow
}
}
if (diagVal >
sumrow) {
// Test against each other
count++;
}
}
if (count == matrixSize) {
// If all rows diag dom, count will match
matrixSize
diagonalDom =
true;
// The algorithm will
converge
}
else {
diagonalDom =
false;
// The algorithm may or may not converge
}
}
/**
* calculate machine epsilon to a finite degree of
precision
*/
private double calculateMachineEpsilon() {
double machEps = 1.0;
do {
machEps /=
2.0;
} while ((double) (1.0 + (machEps /
2.0)) != 1.0);
return machEps;
}
/**
* Method that calculates the SOR solution vector.
Determine best way to
* choose appropriate Omega value. Gauss-Seidel omega =
1.0
*/
public void performSOR()
{
double
sum;
double
diagonal = 0;
sorCounter
= 0;
// The number of iterations
//caluclate the initial guess based
on A matrix and b vector
calculateInitialGuess();
// Calculate the machine epsilon to
be used as tolerance
machEpsilon =
calculateMachineEpsilon();
// Keep on iteration if the
redidTol or xTol are greater than machine Epsilon and no. of
iterations is less than max iterations
while (((residVal >=
machEpsilon) && (xTol >= machEpsilon)) &&
(sorCounter <= maxits) )
{
for (int i = 0;
i <= (matrixSize-1); i++)
// Each row
{
sum = 0;
// Reset
the variable sum after each row
for (int j = rowStart[i]; j <= (rowStart[i +
1]-1); j++)
{
sum = sum + val[j] *
x[col[j]];
if (col[j] == i){
// Diagonal elements of the matrix
diagonal =
val[j];
// Store in variable d to be used in
equation
}
}
x[i] = x[i] + omega * (b[i] - sum)
/diagonal;
// Successive Over Relaxation
equation
System.out.println("Iteration " + (sorCounter+1)
+ ", element "
+ i + " :
\t\t" + x[i] );
}
sorCounter++;
// Increment the number of
iterations performed
if(sorCounter
>= maxits)
// When max iterations are
performed, write to file as reason
{
writeSummary("Max Iterations");
outFile.closeWriter();
// Clean up and exit
System.exit(0);
}
// Call method
to check for divergence or convergence
checkConvergence_Divergence();
}
// Needs to determine if it was
residual/xSequence convergence
if(residVal<xTol)
{
writeSummary("
Residual Converge");
}
else
writeSummary("
xSeq. Converge");
}
/**
* This method will check for convergence or
divergence
*/
private void checkConvergence_Divergence() {
// Calculate both the Residual and
Successive Approximation
residVal =
calculateResidual(x);
xTol =
successiveApprox(x);
}
/**
* @param x
* @return
*
* Method that calculates the successive approximation
of the algorithm. It will indicate if the solution is being
converged to or not
* There is also an alternative method of calculating
successive approximation. Therefore, there are three methods
overall
*/
private double successiveApprox(double[] x)
{
double
successiveNorm;
double subtraction [] = new
double[matrixSize];
double error[] =
new double[matrixSize];
// This array is for alternate approach
// Calculate the error
for(int i = 0; i<matrixSize;
i++)
{
subtraction[i] =
((x[i] - xOld[i]));
error[i] =
Math.abs((x[i] - xOld[i])/x[i])*100;
//
Alternative method of calculating the absolute error
xOld[i] =
x[i];
//re-assign the current array as the old
one
}
successiveNorm =
calculateNorm(subtraction);
// Call method to calculate the norm of the
array
//System.out.println("The
successive approximation is: \t" + successiveNorm);
//System.out.println("The
alternative approximation is: \t" + calculateMax(error) +
"%\n");
return successiveNorm;
}
/**
* This method calculates the Residual(b-Ax) and
returns the norm of r(Residual).
* The Residual value(r) will approach zero as the
answer converges
*/
private double calculateResidual(double[] x)
{
double residual[] = new
double[matrixSize];
double[] mult = new
double[matrixSize];
double normResidual;
// Returned after norm calculated
// Call product method that will
traverse through CRS and multiply A*x. Will return mult of size
matrixSize
mult = product(x);
// To calculate the Residual,
subtract the result of product from b
for(int i=0; i<matrixSize;
i++){
residual[i] =
b[i] - mult[i];
}
normResidual =
calculateNorm(residual);
// Finally, calculate the
norm of the result b-Ax and return
//System.out.println("The residual
is: \t\t\t" + normResidual);
double bNorm =
calculateNorm(b);
// This needs to be performed
somewhere more centralized and once!!!
return normResidual/bNorm;
} //end calculateResidual method
/**
* Given a vector(array), this method will return the
norm of the vector
*/
private double calculateNorm(double[] x)
{
double sum = 0;
for(int i=0; i< matrixSize;
i++){
sum = sum +
x[i]*x[i];
// Stores
the square of each element combined
}
return Math.sqrt(sum);
//returns
the square root of the whole array(each element squared)
}
/**
* Takes a vector x and returns the product of the
matrix stored in the CRS object with x for residual
convergence.
**/
private double[] product(double[] x){
double[] product = new
double[matrixSize];
//create
vector to save product
for (int i = 0; i <
matrixSize; i++){
for( int j =
rowStart[i]; j < rowStart[i+1]; j++){
product[i] += val[j] * x[col[j]];
}
}
return product;
}//end of product
/**
* Takes a vector x and returns the division of the
matrix stored in the CRS object with b for the initial guess
estimation
**/
private double[] divide(){
double[] divided = new
double[matrixSize];
// Create
vector to save division
for (int i = 0; i <
matrixSize; i++){
for( int j =
rowStart[i]; j < rowStart[i+1]; j++){
divided[i] = b[i]/val[j];
// Perform
division of diagonal and vector b
}
}
return divided;
} //end of divide
/**
* This method returns the max of the array. Used for
successive approximation where the max of the norm array is
calculate
* @param error[]
* @return the max of the array
*/
public static double calculateMax(double[] error)
{
double maximum = error[0];
// Start max with the first value
for (int i=1; i<error.length; i++) {
if (error[i] > maximum) {
// If element is greater than current max,
replace
maximum = error[i];
// New
maximum
}
}
return maximum;
} //end method calculateMax
/**The following three methods are used to populate
the CRS arrays defined in the fieilds of this class
and initialised in the
constructor. They are called in class ParseInput- method
getInputData */
public void populateCRS(double element, int index, int
j) {
val[index] = element;
col[index] = j;
}
public void populateRowStart(int i, int index) {
rowStart[i+1] = index;
}
public void populateVectorB(double element, int
row){
b[row] = element;
}
/**
* Write the details of the algorithm and stopping reason
details
*/
public void writeSummary(String stopReason)
{
outFile.write( "\n\n Stopping Reason Max Iterations
Num of Iteration " +
"Machine Epsilon
X seq. tolerance Res seq. tolerance Diag. Dominance(R)\n"
+ " -------------------- ------------------ ------------------
------------------ " +
" ------------------
----------------------- ---------------------\n" );
f = new Formatter();
f.format( "%18s %14d %20d %22.7e %18.7e %20.7e %20s\n", stopReason,
maxits, sorCounter, machEpsilon, xTol, residVal,
diagonalDom);
outFile.write( f.toString() );
outFile.write("\n\n The Solution Vector x is: \n" +
"----------------------------\n");
f = new Formatter();
for(int i=0; i<matrixSize; i++){
f.format("\n\tx[" + i + "] = %2.20e",
x[i]);
}
outFile.write( f.toString() );
}
/**
* This method is specifically for printing unrecoverable errors to
the output file
*
*/
public void writeError(String stopReason)
{
outFile.write("\n\n Stopping Reason: \n" +
"----------------------------\n");
f = new Formatter();
f.format( "%21s\n\n\n", stopReason);
outFile.write( f.toString() );
}
}
Kindly revert for any queries
Thanks.