Мой вопрос
- Есть ли лучший способ сделать это ?
ДА: Что бы это было? - НЕТ: Какой из моих методов — C?
Контекст
Я использую это для моделирования жидкости.< /p>
Матрица двумерная, и вы можете получить x и y, используя эту формулу:
int x = pos % xLength;
int y = pos / xLength;
Размеры матрицы составляют около 720x1280 ячеек.
Однопоточный базовый метод
< pre class="lang-java Prettyprint-override"> int size = x.length;
if (b.length != size)
throw new IllegalArgumentException("both matrix must be the same size");
// Values of x_{i-1,j}, x_{i+1,j}, x_{i,j-1}, x_{i,j+1}
double xL, xR, xB, xT, valX, valXNew;
int xLPos, xRPos, xBPos, xTPos; // Positions of x_{i-1,j}, x_{i+1,j}, x_{i,j-1}, x_{i,j+1}
double cellDiff; // The % of difference between two iterations of this cell
double curentDiff = 1d; // The current % minimal between two iterations
double[] x_new = this.matrixArrayPool.borrowObject();
for (int iter = 0; iter < SimulationConstants.MAX_JACOBI_ITERATIONS; iter++) {
curentDiff = 1;
for (int pos = 0; pos < size; pos++) {
// Get the pos of x_{i-1,j}, x_{i+1,j}, x_{i,j-1}, x_{i,j+1}
xLPos = getPosAtOffset(pos, xLength, yLength, -1, 0); // x_{i-1,j}
xRPos = getPosAtOffset(pos, xLength, yLength, 1, 0); // x_{i+1,j}
xBPos = getPosAtOffset(pos, xLength, yLength, 0, -1); // x_{i,j-1}
xTPos = getPosAtOffset(pos, xLength, yLength, 0, 1); // x_{i,j+1}
xL = x[xLPos]; // x_{i-1,j}
xR = x[xRPos]; // x_{i+1,j}
xB = x[xBPos]; // x_{i,j-1}
xT = x[xTPos]; // x_{i,j+1}
// Find the new value of x_{i,j}
valXNew = x_new[pos] = (xL + xR + xB + xT + alpha * b[pos]) * rBeta;
// Find the new % of difference
valX = x[pos];
if (valX == valXNew) continue;
cellDiff = (valXNew - valX) / valX;
if (cellDiff < 0) {
cellDiff = -cellDiff;
}
curentDiff = Math.min(cellDiff, curentDiff);
}
// Switch both matrix
System.arraycopy(x_new, 0, x, 0, size);
// Check if the current diff is lower than the threshold
if (curentDiff < SimulationConstants.MAX_JACOBI_DIFF) break;
}
Попытки многопоточности
Пул исполнителей фиксированной длины
Я пробовал многопоточность с использованием пула исполнителей с вызываемая
основная функция
double[] x_new = this.matrixArrayPool.borrowObject();
JacobiPartSolver.setGlobalVariables(x, xLength, yLength, alpha, rBeta, b, x_new);
double curentDiff = 1;
for (int iter = 0; iter < SimulationConstants.MAX_JACOBI_ITERATIONS; iter++) {
applyBoundaryConditions();
// Start the threads
try {
executor.invokeAll(this.jacobiSolverTasks);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Get the global differents
curentDiff = JacobiPartSolver.getCurrentDiff();
// Switch matrix
System.arraycopy(x_new, 0, x, 0, size);
if (curentDiff < SimulationConstants.MAX_JACOBI_DIFF) break;
}
jacobiSolverTasks — это список Callable, созданный с начальной и конечной позицией.
вызов функции
public Void call() {
if (!isSetuped)
throw new IllegalStateException("Global variables haven't been setuped");
double xL,
xR,
xB,
xT,
valXNew,
valX; // value of x_{i-1,j}, x_{i+1,j}, x_{i,j-1}, x_{i,j+1}
int xLPos, xRPos, xBPos, xTPos; // pos of x_{i-1,j}, x_{i+1,j}, x_{i,j-1}, x_{i,j+1}
double cellDiff;
for (int pos = start; pos < end; pos++) {,j+1}
xLPos = getPosAtOffset(pos, xLength, yLength, -1, 0); // x_{i-1,j}
xRPos = getPosAtOffset(pos, xLength, yLength, 1, 0); // x_{i+1,j}
xBPos = getPosAtOffset(pos, xLength, yLength, 0, -1); // x_{i,j-1}
xTPos = getPosAtOffset(pos, xLength, yLength, 0, 1); // x_{i,j+1}
xL = x[xLPos]; // x_{i-1,j}
xR = x[xRPos]; // x_{i+1,j}
xB = x[xBPos]; // x_{i,j-1}
xT = x[xTPos]; // x_{i,j+1}
valXNew = x_new[pos] = (xL + xR + xB + xT + alpha * b[pos]) * rBeta;
valX = x[pos];
if (valX == valXNew) continue;
cellDiff = (valXNew - valX) / valX;
if (cellDiff < 0) {
cellDiff = -cellDiff;
}
long cellDiffBits = Double.doubleToLongBits(cellDiff);
if (cellDiffBits < curentDiff.get()) {
curentDiff.set(cellDiffBits);
}
}
curentDiff — это AtomicLong для обеспечения безопасности потоков, поскольку это единственное значение, которое записывается несколькими потоками одновременно.
RecursiveTask с ForkJoin
Моя вторая попытка — с RecursiveTask
main function
int size = x.length;
double[] x_new = this.matrixArrayPool.borrowObject();
JacobiPartSolver.setGlobalVariables(x, xLength, yLength, alpha, rBeta, b, x_new);
double curentDiff = 1;
for (int iter = 0; iter < SimulationConstants.MAX_JACOBI_ITERATIONS; iter++) {
applyBoundaryConditions();
JacobiPartSolver jacobiSolverTask = new JacobiPartSolver(0, size);
curentDiff = forkJoinPool.invoke(jacobiSolverTask);
System.arraycopy(x_new, 0, x, 0, size);
if (curentDiff < SimulationConstants.MAX_JACOBI_DIFF) break;
}
функция вычисления и решения
@Override
public Double compute() {
if (!isSetuped)
throw new IllegalStateException("Global values not defined");
if (this.end - this.start < SUBTASK_THRESHOLD) {
return solve();
}
int mid = (this.start + this.end) / 2;
JacobiPartSolver left = new JacobiPartSolver(this.start, mid);
JacobiPartSolver right = new JacobiPartSolver(mid, this.end);
left.fork();
return Math.min(right.compute(), left.join());
}
private double solve() {
double xL,
xR,
xB,
xT,
valXNew,
valX; // Values of x_{i-1,j}, x_{i+1,j}, x_{i,j-1}, x_{i,j+1}
int xLPos, xRPos, xBPos, xTPos; // Position of x_{i-1,j}, x_{i+1,j}, x_{i,j-1}, x_{i,j+1}
double cellDiff = 1;
double minDiff = cellDiff;
for (int pos = this.start; pos < this.end; pos++) {
xLPos = getPosAtOffset(pos, xLength, yLength, -1, 0); // x_{i-1,j}
xRPos = getPosAtOffset(pos, xLength, yLength, 1, 0); // x_{i+1,j}
xBPos = getPosAtOffset(pos, xLength, yLength, 0, -1); // x_{i,j-1}
xTPos = getPosAtOffset(pos, xLength, yLength, 0, 1); // x_{i,j+1}
xL = x[xLPos]; // x_{i-1,j}
xR = x[xRPos]; // x_{i+1,j}
xB = x[xBPos]; // x_{i,j-1}
xT = x[xTPos]; // x_{i,j+1}
valXNew = x_new[pos] = (xL + xR + xB + xT + alpha * b[pos]) * rBeta;
valX = x[pos];
if (valX == valXNew) continue;
cellDiff = (valXNew - valX) / valX;
if (cellDiff < 0) {
cellDiff = -cellDiff;
}
minDiff = Math.min(minDiff, cellDiff);
}
return minDiff;
}
}
Подробнее здесь: https://stackoverflow.com/questions/782 ... rations-on