Abort: Unable to create linear formulation for the `float_times(X_INTRODUCED_44_, X_INTRODUCED_45_, X_INTRODUCED_46_)` constraint - solver

I'm coding a MIP problem using Minzinc with Coin-bc solver. But, It's raise a error like the title. It's due to eta_cpu & cpu_used both are variables, When I remove one of them from the Objective Function income, it become work. System point out set QuadrFloat=ture, but after I did it, Another question comes like this: Backend: [int/float]_times not supported.
MiniZinc version is 2.5.5
Code in here:
include "Untitled1.dzn";
% include "redefinitions.mzn";
QuadrFloat = true;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ENVIRONMENT
int: numHosts;
set of int: hosts = 1..numHosts;
array[hosts] of int: cpu_resource;
array[hosts] of int: memory_resource;
array[hosts] of int: storage_resource;
array[hosts] of int: bandwidth_resource;
int: numVnfs;
set of int: vnf = 1..numVnfs;
array[vnf] of int: vnf_properties_bw;
array[vnf] of int: vnf_properties_cpu;
array[vnf] of int: vnf_properties_mem;
array[vnf] of int: vnf_properties_sto;
int: sliceLen;
set of int: sSlice = 1..sliceLen;
array[sSlice] of int: slice;
float: C;
float: G_c;
float: G_m;
float: G_s;
float: W_min;
float: W_max;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DECISION VARIABLES AND CONSTRAINTS
var float: income;
array[sSlice] of var hosts: placement;
array[hosts] of var int: cpu_used;
array[hosts] of var int: memory_used;
array[hosts] of var int: storage_used;
array[hosts] of var int: bandwidth_used;
array[hosts] of var 0..1: u;
array[hosts] of var float: eta_cpu;
array[hosts] of var float: eta_mem;
array[hosts] of var float: eta_sto;
array[hosts] of var float: eta_bw;
% RESOUECES UTILIZATION
constraint forall(host in hosts)
(
cpu_used[host] = sum(s in sSlice where placement[s] = host) (vnf_properties_cpu[slice[s]])
);
constraint forall(host in hosts)
(
memory_used[host] = sum(s in sSlice where placement[s] = host) (vnf_properties_mem[slice[s]])
);
constraint forall(host in hosts)
(
storage_used[host] = sum(s in sSlice where placement[s] = host) (vnf_properties_sto[slice[s]])
);
constraint forall(host in hosts)
(
bandwidth_used[host] = sum(s in sSlice where placement[s] = host) (vnf_properties_bw[slice[s]])
);
% RESOURCE CONSTRAINTS
constraint forall(host in hosts)
(
cpu_used[host] <= cpu_resource[host]
);
constraint forall(host in hosts)
(
memory_used[host] <= memory_resource[host]
);
constraint forall(host in hosts)
(
storage_used[host] <= storage_resource[host]
);
constraint forall(host in hosts)
(
bandwidth_used[host] <= bandwidth_resource[host]
);
% RESOUECES UTILIZATION RATE
constraint forall(host in hosts)
(
(
eta_cpu[host] =
if cpu_used[host] > 0
then cpu_used[host] / cpu_resource[host]
else
0
endif
)
);
constraint forall(host in hosts)
(
(
eta_mem[host] =
if memory_used[host] > 0
then memory_used[host] / memory_resource[host]
else
0
endif
)
);
constraint forall(host in hosts)
(
(
eta_sto[host] =
if storage_used[host] > 0
then storage_used[host] / storage_resource[host]
else
0
endif
)
);
constraint forall(host in hosts)
(
(
eta_bw[host] =
if bandwidth_used[host] > 0
then bandwidth_used[host] / bandwidth_resource[host]
else
0
endif
)
);
% HOST STATE
constraint forall(host in hosts)
(
(
u[host] =
if cpu_used[host] > 0
then 1
else 0
endif
)
);
% OBJECTIVE FUNCTION
income = sum(host in hosts) ((G_c * (1.0 - eta_cpu[host]) * cpu_used[host] + G_m * memory_used[host] + G_s * storage_used[host]) - (W_max - W_min) * eta_cpu[host] + u[host] * W_min) * C;
% income = sum(host in hosts) ((G_c * cpu_used[host] + G_m * memory_used[host] + G_s * storage_used[host]) - (W_max - W_min) * eta_cpu[host] + u[host] * W_min) * C;
% income = sum(host in hosts) ((G_c * (1 - eta_cpu[host]) + G_m * memory_used[host] + G_s * storage_used[host]) - (W_max - W_min) * eta_cpu[host] + u[host] * W_min) * C;
% income = sum(host in hosts) ((G_c * (1 - eta_cpu[host]) * 10.0 + G_m * 10.0 + G_s * 10.0) - (W_max - W_min) * eta_cpu[host] + u[host] * W_min) * C;
% solve satisfy;
solve maximize income;
output ["\nplacement: ", show(placement),
"\ncpu_used: ", show(cpu_used),
"\nmemory_used: ", show(memory_used),
"\nstorage_used: ", show(storage_used),
"\nbandwidth_used: ", show(bandwidth_used),
"\neta_cpu: ", show(eta_cpu),
"\neta_mem: ", show(eta_mem),
"\neta_sto: ", show(eta_sto),
"\neta_bw: ", show(eta_bw),
"\nu: ", show(u),
"\nincome: ", show_float(0, 5, income),
% "\n111: ", show_float(0, 5, int2float(2, cpu_used[1]))
];
What should I do to solve this problem. Help me. Please. ORZ.

The issue here is with the type of solver. Coin-or Branch-and-Cut (CBC) is a Mixed Integer Programming solvers. One of the limitations of these types of solvers is that its problems can only contain linear (in-)equalities. So you can multiply decision variables by constants, and you can add these terms together, but you cannot multiply two variables. This is out of scope for the solving mechanism.
For integer multiplication, there is a solution. You can use a decomposition where you split the integers into many 0..1 integer variable each representing whether the original integer takes a certain value. These variables can then be used to reason about the value of the multiplication in multiple seperate constraints. This is especially efficient, but allows us to use integer multiplication (at least some of the time).
Floating point multiplication is a different beast. It requires explicit support from a solver. Problems that use these constraints are called quadratic and you will often see that MIP solver will specify whether they can solve quadratic problems. Among the MiniZinc solvers, CBC does not support quadratic constraints, but I believe the other MIP solvers (SCIP, Gurobi, and CPLEX) do.

Related

Why does the code terminate with a "Solution Not Found" error and "EXIT: Converged to a point of local infeasibility. Problem may be infeasible"?

I cannot seem to figure out why IPOPT cannot find a solution to this. Initially, I thought the problem was totally infeasible but when I reduce the value of col_total to any number below 161000 or comment out the last constraint equation that contains col_total, it solves and EXITs with an Optimal Solution Found and a final objective value function of -161775.256826753. I have solved the same Maximization problem using Artificial Bee Colony and Particle Swamp Optimization techniques, and they solve and return optimal objective value function at least 225000 and 226000 respectively. Could it be that another solver is required? I have also tried APOPT, BPOPT, and IPOPT and have tinkered around with the tolerance values, but no combination none seems to work just yet. The code is posted below. Any guidance will be hugely appreciated.
from gekko import GEKKO
import numpy as np
distances = np.array([[[0, 0],[0,0],[0,0],[0,0]],\
[[155,0],[0,0],[0,0],[0,0]],\
[[310,0],[155,0],[0,0],[0,0]],\
[[465,0],[310,0],[155,0],[0,0]],\
[[620,0],[465,0],[310,0],[155,0]]])
alpha = 0.5 / np.log(30/0.075)
diam = 31
free = 7
rho = 1.2253
area = np.pi * (diam / 2)**2
min_v = 5.5
axi_max = 0.32485226746
col_total = 176542.96546512868
rat = 14
nn = 5
u_hub_lowerbound = 5.777777777777778
c_pow = 0.59230249
p_max = 0.5 * rho * area * c_pow * free**3
# Initialize Model
m = GEKKO(remote=True)
#initialize variables, Set lower and upper bounds
x = [m.Var(value = 0.03902278, lb = 0, ub = axi_max) \
for i in range(nn)]
# i = 0
b = 1
c = 0
v_s = list()
for i in range(nn-1): # Loop runs for nn-1 times
# print(i)
# print(i,b,c)
squared_defs = list()
while i < b:
d = distances[b][c][0]
r = distances[b][c][1]
ss = (2 * (alpha * d) / diam)
tt = r / ((diam/2) + (alpha * d))
squared_defs.append((2 * x[i] / (1 + ss**2)) * np.exp(-(tt**2)) ** 2)
i+=1
c+=1
#Equations
m.Equation((free * (1 - (sum(squared_defs))**0.5)) - rat <= 0)
m.Equation((free * (1 - (sum(squared_defs))**0.5)) - u_hub_lowerbound >= 0)
v_s.append(free * (1 - (sum(squared_defs))**0.5))
squared_defs.clear()
b+=1
c=0
# Inserts free as the first item on the v_s list to
# increase len(v_s) to nn, so that 'v_s' and 'x'
# are of same length
v_s.insert(0, free)
gamma = list()
for i in range(len(x)):
bet = (4*x[i]*((1-x[i])**2) * rho * area) / 2
gam = bet * v_s[i]**3
gamma.append(gam)
#Equations
m.Equation(x[i] - axi_max <= 0)
m.Equation((((4*x[i]*((1-x[i])**2) * rho * area) / 2) \
* v_s[i]**3) - p_max <= 0)
m.Equation((((4*x[i]*((1-x[i])**2) * rho * area) / 2) * \
v_s[i]**3) > 0)
#Equation
m.Equation(col_total - sum(gamma) <= 0)
#Objective
y = sum(gamma)
m.Maximize(y) # Maximize
#Set global options
m.options.IMODE = 3 #steady state optimization
#Solve simulation
m.options.SOLVER = 3
m.solver_options = ['linear_solver ma27','mu_strategy adaptive','max_iter 2500', 'tol 1.0e-5' ]
m.solve()
Built the equations without .value in the expressions. The x[i].value is only needed at the end to view the solution after the solution is complete or to initialize the value of x[i]. The expression m.Maximize(y) is more readable than m.Obj(-y) although they are equivalent.
from gekko import GEKKO
import numpy as np
distances = np.array([[[0, 0],[0,0],[0,0],[0,0]],\
[[155,0],[0,0],[0,0],[0,0]],\
[[310,0],[155,0],[0,0],[0,0]],\
[[465,0],[310,0],[155,0],[0,0]],\
[[620,0],[465,0],[310,0],[155,0]]])
alpha = 0.5 / np.log(30/0.075)
diam = 31
free = 7
rho = 1.2253
area = np.pi * (diam / 2)**2
min_v = 5.5
axi_max = 0.069262150781
col_total = 20000
p_max = 4000
rat = 14
nn = 5
# Initialize Model
m = GEKKO(remote=True)
#initialize variables, Set lower and upper bounds
x = [m.Var(value = 0.03902278, lb = 0, ub = axi_max) \
for i in range(nn)]
i = 0
b = 1
c = 0
v_s = list()
for turbs in range(nn-1): # Loop runs for nn-1 times
squared_defs = list()
while i < b:
d = distances[b][c][0]
r = distances[b][c][1]
ss = (2 * (alpha * d) / diam)
tt = r / ((diam/2) + (alpha * d))
squared_defs.append((2 * x[i] / (1 + ss**2)) \
* m.exp(-(tt**2)) ** 2)
i+=1
c+=1
#Equations
m.Equation((free * (1 - (sum(squared_defs))**0.5)) - rat <= 0)
m.Equation(min_v - (free * (1 - (sum(squared_defs))**0.5)) <= 0 )
v_s.append(free * (1 - (sum(squared_defs))**0.5))
squared_defs.clear()
b+=1
a=0
c=0
# Inserts free as the first item on the v_s list to
# increase len(v_s) to nn, so that 'v_s' and 'x'
# are of same length
v_s.insert(0, free)
beta = list()
gamma = list()
for i in range(len(x)):
bet = (4*x[i]*((1-x[i])**2) * rho * area) / 2
gam = bet * v_s[i]**3
#Equations
m.Equation((((4*x[i]*((1-x[i])**2) * rho * area) / 2) \
* v_s[i]**3) - p_max <= 0)
m.Equation((((4*x[i]*((1-x[i])**2) * rho * area) / 2) \
* v_s[i]**3) > 0)
gamma.append(gam)
#Equation
m.Equation(col_total - sum(gamma) <= 0)
#Objective
y = sum(gamma)
m.Maximize(y) # Maximize
#Set global options
m.options.IMODE = 3 #steady state optimization
#Solve simulation
m.options.SOLVER = 3
m.solve()
This gives a successful solution with maximized objective 20,000:
Number of Iterations....: 12
(scaled) (unscaled)
Objective...............: -4.7394814741924645e+00 -1.9999999999929641e+04
Dual infeasibility......: 4.4698510326511536e-07 1.8862194343304290e-03
Constraint violation....: 3.8275766582203308e-11 1.2941979026166479e-07
Complementarity.........: 2.1543608536533588e-09 9.0911246952931704e-06
Overall NLP error.......: 4.6245685940749926e-10 1.8862194343304290e-03
Number of objective function evaluations = 80
Number of objective gradient evaluations = 13
Number of equality constraint evaluations = 80
Number of inequality constraint evaluations = 0
Number of equality constraint Jacobian evaluations = 13
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations = 12
Total CPU secs in IPOPT (w/o function evaluations) = 0.010
Total CPU secs in NLP function evaluations = 0.011
EXIT: Optimal Solution Found.
The solution was found.
The final value of the objective function is -19999.9999999296
---------------------------------------------------
Solver : IPOPT (v3.12)
Solution time : 3.210000000399305E-002 sec
Objective : -19999.9999999296
Successful solution
---------------------------------------------------

How to find the n-th term in a sequence with following recurrence relation for a given n?

How to find the n-th term in a sequence with following recurrence relation for a given n?
F(n) = 2 * b * F(n – 1) – F(n – 2), F(0) = a, F(1) = b
where a and b are constants.
The value of N is quite large (1 ≤ n ≤ 1012) and so matrix exponentiation is required.
Here is my code for it; ll is a typedef for long long int, and value is to be taken modulo r.
void multiply(ll F[2][2], ll M[2][2])
{
ll x = ((F[0][0] * M[0][0]) % r + (F[0][1] * M[1][0]) % r) % r;
ll y = ((F[0][0] * M[0][1]) % r + (F[0][1] * M[1][1]) % r) % r;
ll z = ((F[1][0] * M[0][0]) % r + (F[1][1] * M[1][0]) % r) % r;
ll w = ((F[1][0] * M[0][1]) % r + (F[1][1] * M[1][1]) % r) % r;
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
void power(ll F[2][2], ll n, ll b)
{
if (n == 0 || n == 1)
return;
ll M[2][2] = {{2 * b, -1}, {1, 0}};
power(F, n / 2,b);
multiply(F, F);
if (n % 2 != 0)
multiply(F, M);
}
ll rec(ll n, ll b, ll a)
{
ll F[2][2] = {{2 * b, -1}, {1, 0}};
if (n == 0)
return a;
if (n == 1)
return b;
power(F, n - 1,b);
return F[0][0] % r;
}
However I am facing problems getting required value in all cases, that is I am getting Wrong Answer (WA) verdict for some cases.
Could anyone help me with this question and point out the mistake in this code so I can tackle these kind of problems myself afterward?
P.S. First timer here. Apologies if I did something incorrectly and missed out on anything.
Technical:
Perhaps you are asked to find the value res modulo r so that 0 <= res < r.
However, by using -1 in the matrix, you can actually get negative intermediate and final values. The reason is that, in most programming languages, the modulo operation actually uses division rounded towards zero, and so produces a result in the range -r < res < r (example link).
Try either of the following:
Change that -1 to r - 1, so that all intermediate values remain non-negative.
Fix the final result by returning (F[0][0] + r) % r instead of just F[0][0] % r.
Formula:
Your formula looks wrong. Logically, your rec function says that nothing except F(0) depends on a, which is obviously wrong.
Recall why and how we use the matrix in the first place:
( F(n) ) = ( 2b -1 ) * ( F(n-1) )
( F(n-1) ) ( 1 0 ) ( F(n-2) )
Here, we get a 2x1 vector by multiplying a 2x2 matrix and a 2x1 vector. We then look at its top element and have, by multiplication rules,
F(n) = 2b * F(n-1) + (-1) * F(n-2)
The point is, we can take the power of the matrix to get the following:
( F(n) ) = ( 2b -1 ) ^{n-1} * ( F(1) )
( F(n-1) ) ( 1 0 ) ( F(0) )
By the same argument, we have
F(n) = X * F(1) + Y * F(0)
where X and Y are the top row of the matrix:
( 2b -1 ) ^{n-1} = ( X Y )
( 1 0 ) ( Z T )
So F[0][0] % r is not the answer, really.
The real answer looks like
(F[0][0] * b + F[0][1] * a) % r
If we can have negative intermediate values (see point 1 above), the result is still from -r to r instead of from 0 to r. To fix it, we can add one more r and take the modulo once again:
((F[0][0] * b + F[0][1] * a) % r + r) % r
Possible reason for WA is, you return a or b without doing any mod.
Try it.
if (n == 0)
return a%r;
if (n == 1)
return b%r;
If you are still getting WA, please give some test cases or problem link.

Mutual recursion analysis

I'm trying to analyze these functions but i am getting a bit lost. So for function f when t(n) = c if n < 1^-5
so if n >= 1^5 i get t(n) = c2 + t( n / 2 ) + t2( n / 2) where t2 is the time analysis of function h, but i'm confused on expanding it should it be something like
t(n) = ( t(n / 2) + t2( n / 2) ) * c2 + c
or should i be expanding t2 in side of that?
here is the code i am trying to analyze.
float f( float x) {
if ( abs( x ) < 1e-5 ) {
return x + ( ( x * x * x ) / 2 );
}
float y = f( x / 2 );
float z = g( x / 2 );
return 2 * y * z;
}
float g( float x ) {
if ( abs( x ) < 1e-5 ) {
return 1 + ( ( x * x ) / 2 );
}
float y = f( x / 2 );
float z = g( x / 2 );
return ( z * z ) + ( y * y );
}
T1(n) = T1(n / 2) + T2(n / 2) + c1
T2(n) = T1(n / 2)+T2(n / 2) + c2
so we have
T1(n) = O(T2(n))
T1(n) = 2T1(n / 2) + c1
since c1 = O(nlog22) master theorem implies that
T(n) = O(n)
Even though we are calling two different functions in this code, there is a thing about them that makes finding the complexity of this recursion easy.
What's happening is that at the top level, if you are entering f(), you are evaluating x and then calling two different functions - itself and g(). Even if you enter the function g() first, same thing happens, i.e. g() calls itself and f().
Since, every level down the tree the value of x halves, the number of levels on this tree would be Log2(n). Also, every node has 2 children viz. f(x/2) and g(x/2).
This is a complete binary tree of length Log2(n).
Work done on each node is constant - If the node represents the call to f(), you do 2 * y * z, which is constant. If the node represents the call to g(), you do y*y + z*z, which is also constant.
Hence, all we need to do is, find the total number of nodes in a compete binary tree of length Log2(n) and we have our complexity.
A perfect binary tree of height h has total 2h + 1 - 1 nodes.
In this case it would be 2Log2(n) + 1 - 1 nodes.
Also, aLogab = b (By property of logarithms)1
Hence, the complexity is O(2Log2(n)) = O(n).
1 See first property in "Cancelling Exponentials" section.

SuperCollider -- Synthdef with mix of variable amount of SinOsc's

This code returns an error, but it works if I remove "arg" from line 4. What can I do to make n an argument and not get an error?
(
SynthDef("test",
{
arg n=8;
f=Mix.fill(n, {
arg index;
var freq, amp;
freq=440*((7/6)**index);
//freq.postln;
amp=(1-(index / n)) / (n*(n+1) / (2*n));
SinOsc.ar(freq,0,0.2*amp)
});
//f=SinOsc.ar(440,0,0.2);
Out.ar(0,f)
}).add;
)
SynthDefs always have fixed "wiring", so you cannot vary the number of SinOscs. That is a hard constraint which you cannot avoid.
What you can do is procedurally generate synthdefs for each cardinality:
(
(2..10).do{|num|
SynthDef("wiggler%".format(num), {|freq=440, amp=0.1|
var oscs;
oscs = Mix.fill(num, {|index|
SinOsc.ar(freq * index)
});
Out.ar(0, oscs * amp);
}).add;
}
)
x = Synth("wiggler2")
x.free
x = Synth("wiggler10")
x.free
In case you have a an upper bound for n (let's say n<=16), then you can create a continuous cutoff array with which you multiply the harmonics.
(
SynthDef("test",
{
arg n=8;
var cutoff = tanh( (1..16)-n-0.5 *100 ) * -1 / 2 + 0.5; // this
f=Mix.fill(16, { // run it through the upper bound
arg index;
var freq, amp;
freq=440*((7/6)**index);
//freq.postln;
amp=(1-(index / n)) / (n*(n+1) / (2*n));
cutoff[index] * SinOsc.ar(freq,0,0.2*amp) // multiply with cutoff
});
//f=SinOsc.ar(440,0,0.2);
Out.ar(0,f)
}).add;
)
The cutoff array has values 1 if index<n, and zeros after that. Lets say n=3, then cutoff==[1,1,1,0,0,0,...].

Jacobi method converging then diverging

I am working to solve Poisson's equation (in 2d axisymmetric cylindrical coordinates) using the Jacobi method. The L2 norm decreases from ~1E3 on the first iteration (I have a really bad guess) to ~0.2 very slowly. Then, the L2 norm begins to increase over many iterations.
My geometry is parallel plates with sharp points at r = 0 on both plates. (If that matters).
Is there some error in my code? Do I need to go to a different algorithm? (I have a not yet working DADI algorithm.)
Here is my Jacobi method algorithm. Then this just in wrapped in a while loop.
subroutine Jacobi(PoissonRHS, V, resid)
implicit none
real, dimension(0:,0:) :: PoissonRHS, V
REAL resid
integer :: i,j, lb, ub
real, dimension(0:size(V,1)-1, 0:size(V,2)-1) :: oldV
real :: dr = delta(1)
real :: dz = delta(2)
real :: dr2 = (delta(1))**(-2)
real :: dz2 = (delta(2))**(-2)
integer :: M = cells(1)
integer :: N = cells(2)
oldV = V
!Note: All of the equations are second order accurate
!If at r = 0 and in the computational domain
! This is the smoothness condition, dV(r=0)/dr = 0
V(0,:) = (4.0*oldV(1,:)-oldV(2,:))/3.0
!If at r = rMax and in the computational domain
! This is an approximation and should be fixed to improve accuracy, it should be
! lim r->inf V' = 0, while this is V'(r = R) = 0
V(M, 1:N-1) = 0.5 / (dr2 + dz2) * ( &
(2.0*dr2)*oldV(M-1,1:N-1) + &
dz2 * (oldV(M,2:N) + oldV(M,0:N-2)) &
- PoissonRHS(M,1:N-1))
do i = 1, M-1
lb = max(0, nint(lowerBoundary(i * dr) / dz)) + 1
ub = min(N, nint(upperBoundary(i * dr) / dz)) - 1
V(i,lb:ub) = 0.5 / (dr2 + dz2) * ( &
((1.0 - 0.5/dble(i))*dr2)*oldV(i-1,lb:ub) + &
((1.0 + 0.5/dble(i))*dr2)*oldV(i+1,lb:ub) + &
dz2 * (oldV(i,lb+1:ub+1) + oldV(i,lb-1:ub-1)) &
- PoissonRHS(i,lb:ub))
V(i, 0:lb-1) = V0
V(i, ub+1:N) = VL
enddo
!compare to old V values to check for convergence
resid = sqrt(sum((oldV-V)**2))
return
end subroutine Jacobi
Based on additional readings it seems like it was a precision problem. Because (for example), I had the expression
V(i,lb:ub) = 0.5 / (dr2 + dz2) * ( &
((1.0 - 0.5/dble(i))*dr2)*oldV(i-1,lb:ub) + &
((1.0 + 0.5/dble(i))*dr2)*oldV(i+1,lb:ub) + &
dz2 * (oldV(i,lb+1:ub+1) + oldV(i,lb-1:ub-1)) &
- PoissonRHS(i,lb:ub))
where dr2 and dz2 are very large. So by distributing these I got terms that were ~1 and the code converges (slowly, but that's a function of the mathematics).
So my new code is
subroutine Preconditioned_Jacobi(PoissonRHS, V, resid)
implicit none
real, dimension(0:,0:) :: PoissonRHS, V
REAL resid
integer :: i,j, lb, ub
real, dimension(0:size(V,1)-1, 0:size(V,2)-1) :: oldV
real :: dr = delta(1)
real :: dz = delta(2)
real :: dr2 = (delta(1))**(-2)
real :: dz2 = (delta(2))**(-2)
real :: b,c,d
integer :: M = cells(1)
integer :: N = cells(2)
b = 0.5*(dr**2)/((dr**2) + (dz**2))
c = 0.5*(dz**2)/((dr**2) + (dz**2))
d = -0.5 / (dr2 + dz2)
oldV = V
!Note: All of the equations are second order accurate
!If at r = 0 and in the computational domain
! This is the smoothness condition, dV(r=0)/dr = 0
V(0,:) = (4.0*oldV(1,:)-oldV(2,:))/3.0 !same as: oldV(0,:) - 2.0/3.0 * (1.5 * oldV(0,:) - 2.0 * oldV(1,:) + 0.5 * oldV(2,:) - 0)
!If at r = rMax and in the computational domain
! This is an approximation and should be fixed to improve accuracy, it should be
! lim r->inf V' = 0, while this is V'(r = R) = 0
V(M,1:N-1) = d*PoissonRHS(M,1:N-1) &
+ 2.0*c * oldV(M-1,1:N-1) &
+ b * ( oldV(M,0:N) + oldV(M,2:N) )
do i = 1, M-1
lb = max(0, nint(lowerBoundary(i * dr) / dz)) + 1
ub = min(N, nint(upperBoundary(i * dr) / dz)) - 1
V(i,lb:ub) = d*PoissonRHS(i,lb:ub) &
+ (c * (1.0-0.5/dble(i)) * oldV(i-1,lb:ub)) &
+ (c * (1.0+0.5/dble(i)) * oldV(i+1,lb:ub)) &
+ b * (oldV(i,lb-1:ub-1) + oldV(i,lb+1:ub+1))
V(i, 0:lb-1) = V0
V(i, ub+1:N) = VL
enddo
!compare to old V values to check for convergence
resid = sum(abs(oldV-V))
return
end subroutine Preconditioned_Jacobi

Resources