[petsc-users] Conditional Constraints
Shri
abhyshr at mcs.anl.gov
Thu Sep 8 21:34:55 CDT 2011
Jon,
> I do not want Ve to be constant, however; I would like it to either decrease in response to Imag > Imag_max or increase in response to Imag < Imag_max, providing > the condition Vmag <= Vmag_max remains true.
> Should I then have something like f(Ve_ijk) = Imag - Imag_max?
Note here that (a) f(Ve_ijk) is a complex function while Imag and Imag_max are real. So the above equation does not hold.
(b) In your previous email, you had bounds on Imag, 0 < Imag < Imag_max. Now you want Ve_ijk to increase if Imag > Imag_max and decrease if Imag < Imag_max. Are you trying to find the value of Ve at which the current is maximum, i.e. Imag = Imag_max, by doing this?
----- Original Message -----
Shri,
Thanks very much for your response. In fact, -snes_converged_reason revealed that the solution was not converging, as you suggested: "Nonlinear solve did not converge due to DIVERGED_LINE_SEARCH." I had not realized this earlier since the voltage distribution in the solution appeared to be correct, even though the SNES_VI constraints were not satisfied.
Given that and your explanation, I am sure something is wrong with my choices of f. I do not want Ve to be constant, however; I would like it to either decrease in response to Imag > Imag_max or increase in response to Imag < Imag_max, providing the condition Vmag <= Vmag_max remains true. Should I then have something like f(Ve_ijk) = Imag - Imag_max?
Note that you have
One more thing from your response:
>If a block (with coordinates i, j, k) is not occupied by an electrode , C_e is set to zero in the expression for Vb_ijk and all function and Jacobian entries for Ve, >Vmag, and Imag are either not set or set to zero.
Does this mean f(Ve_ijk) = f(Vmag_ijk) = f(Imag_ijk) = 0? If so, then Ve_ijk, Vmag_ijk, and Imag_ijk would retain their initial values for all time steps.
In my present scheme, f(Ve_ijk) = f(Vmag_ijk) = 0 and f(Imag_ijk) is non-zero for electrode blocks; all three are zero for non-electrode blocks. Depending on the choice of initial conditions, I can make f(Vmag_ijk) non-zero as well (until Ve changes to match Ve_max).
Thanks again,
Jon
On 2011-09-08, at 3:42 PM, Shri wrote:
Jon,
> for Ve_ijk, f = 0.0 + 0.0*i, and all corresponding Jacobian entries are zero as well. Ve_ijk is set to the maximum voltage for each electrode when the initial solution >is - set. Since the magnitude of Ve is constrained rather than Ve itself, I believe this is correct, but could this be why Ve does not change as it should when the >problem is - being solved?
This f(Ve_ijk) seems very odd to me since normally you would always have f(some/all variables) = 0 as the function. If f=0.0+0.0*i for all steps, then you don't need a seperate variable Ve_ijk, you can treat it as a constant since Ve_ijk will not change its value during the solutions.
Moroever, the Jacobian rows for df(Ve_ijk)/d(all variables) would be all zeros which implies a singular matrix. I am not sure how the solution converged for this case. Were you using -pc_type lu with some shift or some external direct solver such as superlu? What do you get for -snes_monitor -snes_converged_reason?
> Ve_ijk is set to the maximum voltage for each electrode when the initial solution is set. Since the magnitude of Ve is constrained rather than Ve itself.
> for Vmag_ijk, f = abs(Ve_ijk) - abs(Ve_ijk_max)
Since Ve_ijk = Ve_ijk_max, f for Vmag_ijk = 0.0 and hence Vmag_ijk also will also retain its initial value throughout.
>If a block (with coordinates i, j, k) is not occupied by an electrode , C_e is set to zero in the expression for Vb_ijk and all function and Jacobian entries for Ve, >Vmag, and Imag are either not set or set to zero.
Does this mean f(Ve_ijk) = f(Vmag_ijk) = f(Imag_ijk) = 0? If so, then Ve_ijk, Vmag_ijk, and Imag_ijk would retain their initial values for all time steps.
> When I run my program with -snes_vi_type rs, the solution converges quickly but Vmag voltages remain the same as Ve_max for every electrode. As a result, Imag > currents are far larger than abs(iE_max).
Seems to me like the problem is not converging, or giving the incorrect solution, since the solution of a variational inequality problem has to satisfy Imag < iE_max, which in your case is not happening.
Thanks for the detailed explanation. Would you mind if I (or you) forward this to petsc-users list so that others could share their thoughts too.
Shri
----- Original Message -----
Hi Shri,
Thanks again for your patience with my being away this past month. I have spent some more time with this problem and I have added Jacobian entries for 'cross terms' such as d(f(Vb)) / d(Ve). However, this did not appear to change the solution arrived at by PETSc.
I will give you some examples of the f functions and corresponding Jacobian entries as you suggested, with the hope you will be able to see where I may be going wrong. I will use Vb = V_block, Ve = V_electrode, Vmag = magnitude(V_electrode), Imag = magnitude(I_electrode) to name the four degrees of freedom.
In my 3D finite differencing grid, there are two types of blocks: blocks occupied by electrodes, and blocks occupied by a resistive medium. The block type of the current block and its neighbouring blocks determines the form of f. This is complicated by the fact that individual electrodes generally occupy three vertically-contiguous blocks, and I want to limit the electric current flowing from the whole electrode rather than the current through each block. Note that Ve, Vmag, and Imag are thus computed or recorded only for the top block of each electrode.
If a block (with coordinates i, j, k in the x, y, and z directions, respectively) is occupied by an electrode ,
- for Vb_ijk, f = C_posX * Vb_posX + C_posY * Vb_posY + C_posZ * Vb_posZ
- (C_posX + C_posY + C_posZ + C_negX + C_negY + C_negZ - C_e) * Vb_ijk
+ C_negX * Vb_negX + C_negY * Vb_negY + C_negZ * Vb_negZ
- C_e * Ve,
where all C's are calculated constants that do not depend on the other degrees of freedom, but do depend on the type of the neighbouring block in their assigned directions. Then,
the Jacobian entries for Vb_ijk are
df/dVb_negZ = C_negZ (col.i = i, col.j = j, col.k = k - 1)
df/dVb_negY = C_negY (col.i = i, col.j = j - 1, col.k = k)
df/dVb_negX = C_negX (col.i = i - 1, col.j = j, col.k = k)
df/dVb_ijk = - (C_posX + C_posY + C_posZ + C_negX + C_negY + C_negZ - C_e) (col.i = i, col.j = j, col.k = k)
df/dVb_posX = C_posX (col.i = i + 1, col.j = j, col.k = k)
df/dVb_posY = C_posY (col.i = i, col.j = j + 1, col.k = k)
df/dVb_posZ = C_posZ (col.i = i, col.j = j, col.k = k + 1)
For each of these, row.i = i, row.j = j, row.k = k, and row.c = DOF_VB (the DOF index for Vb). Also, col.c = DOF_VB.
The only cross term for the Vb_ijk function is
df/dVe_ijk = -C_e (row.i = i, row.j = j, row.k = k, row.c = DOF_VB, col.i = i, col.j = j, col.k = k col.c = DOF_VE)
- for Ve_ijk, f = 0.0 + 0.0*i, and all corresponding Jacobian entries are zero as well. Ve_ijk is set to the maximum voltage for each electrode when the initial solution is set. Since the magnitude of Ve is constrained rather than Ve itself, I believe this is correct, but could this be why Ve does not change as it should when the problem is being solved?
- for Vmag_ijk, f = abs(Ve_ijk) - abs(Ve_ijk_max). The idea was to provide some 'pressure' towards Ve = Ve_max. The corresponding Jacobian entries are
df/dVmag_ijk = 1.0 + 0.0*i (row.i = i, row.j = j, row.k = k, row.c = DOF_VMAG, col.i = i, col.j = j, col.k = k, col.c = DOF_VMAG)
df/dVe_ijk = 0.5 * conj(Ve_ijk) / abs(Ve_ijk) (row.i = i, row.j = j, row.k = k, row.c = DOF_VMAG, col.i = i, col.j = j, col.k = k, col.c = DOF_VE)
(However, since d(abs(Ve_ijk))/dVe_ijk does not have satisfied Cauchy-Reimann equations for the entire complex plane, this derivative does not technically exist.)
- for Imag_ijk, f = abs(iE) - iE_max. Again, the idea was to provide some 'pressure' towards iE = iE_max. iE is calculated by adding iE_block currents for each block occupied by an electrode. iE_block for block i,j,k is found from
iE_block_ijk = aE_ijk * (Ve - Vb_ijk)
where aE_ijk is a constant that does not depend on any degrees of freedom. There is one Ve value per electrode. The Jacobian entries are then
df/dImag_ijk = 1.0 + 0.0*i (row.i = i, row.j = j, row.k = k, row.c = DOF_IMAG, col.i = i, col.j = j, col.k = k, col.c = DOF_IMAG)
df/dVe = 0.5 * aE_sum * conj(iE) / abs(iE) (row.i = i, row.j = j, row.k = k, row.c = DOF_IMAG, col.i = i, col.j = j, col.k = k, col.c = DOF_VE)
df/dVb_ijk = - 0.5 * aE_ijk * conj(iE) / abs(iE) (row.i = i, row.j = j, row.k = k, row.c = DOF_IMAG, col.i = i, col.j = j, col.k = k, col.c = DOF_VB)
df/dVb_ij(k-1) = - 0.5 * aE_ij(k-1) * conj(iE) / abs(iE) (row.i = i, row.j = j, row.k = k, row.c = DOF_IMAG, col.i = i, col.j = j, col.k = k-1, col.c = DOF_VB)
df/dVb_ij(k-2) = - 0.5 * aE_ij(k-2) * conj(iE) / abs(iE) (row.i = i, row.j = j, row.k = k, row.c = DOF_IMAG, col.i = i, col.j = j, col.k = k-2, col.c = DOF_VB)
If a block (with coordinates i, j, k) is not occupied by an electrode , C_e is set to zero in the expression for Vb_ijk and all function and Jacobian entries for Ve, Vmag, and Imag are either not set or set to zero.
My SNES_VI constraints are set as follows for every block:
xl_ijk_DOF_V = -SNES_VI_INF
xu_ijk_DOF_V = SNES_VI_INF
xl_ijk_DOF_VE = -SNES_VI_INF
xu_ijk_DOF_VE = SNES_VI_INF
xl_ijk_DOF_VMAG = 0.0
xu_ijk_DOF_VMAG = abs(Ve_max)
xl_ijk_DOF_IMAG = 0.0
xu_ijk_DOF_IMAG = abs(iE_max)
When I run my program with -snes_vi_type rs, the solution converges quickly but Vmag voltages remain the same as Ve_max for every electrode. As a result, Imag currents are far larger than abs(iE_max). Are you able to see from here what the problem might be? Again, my hunches are that the complex derivatives do not work in my Jacobian because they do not exist, or that my choices of f for Ve, Vmag, and Imag are not correct.
Please let me know if you would like clarification on any portion of my description., and thank you again for all your help with this.
Jon
On 2011-07-29, at 12:13 PM, Shri wrote:
Jon,
I am trying to compile petsc with complex data type right now and will try to test the VI solver with complex variables within the next few hours.
My understanding is that comparison operators (such as < and >) are
not defined for complex numbers, so would it be correct to say that
anyone using complex scalars within PETSc will encounter this problem
with SNESVI? In other words, SNESVI inequality constraints can only be
applied to real variables or real-valued functions of complex
variables?
For complex scalars, we only compare the real part of the complex variable and bound,i.e.,
real(xl) <= real(x) <= real(x_u). For your application, this real part comparison is sufficient
since the magnitude is saved in the real part.
The residuals are set as follows, and the Jacobian entries are set
correspondingly:
f[V_block] = {function of adjacent V_blocks, V_electrode}
f[V_electrode] = 0.0 + 0.0i
f[magnitude(V_electrode)] = 0.0 + 0.0i
f[magnitude(I_electrode)] = 0.0 + 0.0i
Can you give an example of f for all dofs maybe just for one grid point with the following dof names
Vb - V_block
Ve - V_electrode
Vmag - magnitude(V_electrode)
Imag - magnitude(I_electrode)
Since I set all the residuals for both magnitude variables to zero,
and each entry in the Jacobian matrix is a partial derivative of a
residual, I believe the Jacobian entries for both magnitudes would all
be zero as well. However, your point made me realize I have no
Jacobian entry for the partial derivative of f[V_block] w.r.t.
V_electrode. Is that needed?
Since f[V_block] is a function of V_electrode, you would need to set the partial derivatives of f[V_block] w.r.t V_electrode
for correct jacobian evaluation and for having a good newton convergence.
How would one enter it with
MatSetValuesStencil?
ex28.c,
http://www.mcs.anl.gov/petsc/petsc-as/snapshots/petsc-dev/src/ksp/ksp/examples/tutorials/ex28.c.html ,
is a petsc example which shows how to use MatSetValuesStencil with multiple degrees of freedom.
See the routine ComputeMatrix in the example.
My working understanding was that each degree of
freedom conceptually has its own residual and Jacobian, even though
all residuals are contained in one Vec and all Jacobians contained in
one Mat.
Please bare with us as we are trying to figure out whether the issue is with our VI implementation or something in
your code is amiss. I appreciate your patience on this matter.
Btw, one quick question, are all the problem formulations in your field done using complex variables or by decomposing the complex term into real/imaginary or magnitude/angle? My background is in electrical power grid and we mostly use either real/imaginary part or magnitude/angle as the variables.
Shri
----- Original Message -----
Thanks for your reply, Shri. Responses below:
On 2011-07-28, at 1:03 PM, Shri wrote:
----- Original Message -----
Hi Barry, Shri,
I reworked my implementation to include only the time-independent
electrical problem, and to make use of SNESVISetVariableBounds().
However, it does not work quite as I expected: Constraints on
variables that are functions of other variables have no effect on
the
variables by which the functions are defined.
My constraints are set on the four degrees of freedom as follows:
-SNES_VI_INF <= V_block <= SNES_VI_INF
-SNES_VI_INF <= V_electrode <= SNES_VI_INF
0.0 + 0.0i <= magnitude(V_electrode) <= magnitude(V_electrode_max)
0.0 + 0.0i <= magnitude(I_electrode) <= magnitude(I_electrode_max)
Note that while V_block and V_electrode and complex quantities,the
magnitude terms are actually real numbers. What function did you use
to compute the magnitude? abs()? sqrt of product of complex number
with its conjugate?
I used the "0.0 + 0.0i" there to emphasize that I built PETSc with
complex scalars, so all the scalars are stored as complex even if the
imaginary components are always zero. I have been using std::abs()
from the C++ standard library complex template class
(std::complex<double>). I believe the values of type 'double' returned
by std::abs() are implicitly cast to the real part of
std::complex<double> or PetscScalar, though I usually try to cast
explicitly.
This seems like an application where the variables are of type
complex but the constraints need to be set for functions of the
variables which are actually real numbers. I am not sure whether
this can be supported. Maybe Barry or others can shed more
light on this.
My understanding is that comparison operators (such as < and >) are
not defined for complex numbers, so would it be correct to say that
anyone using complex scalars within PETSc will encounter this problem
with SNESVI? In other words, SNESVI inequality constraints can only be
applied to real variables or real-valued functions of complex
variables?
The residuals are set as follows, and the Jacobian entries are set
correspondingly:
f[V_block] = {function of adjacent V_blocks, V_electrode}
f[V_electrode] = 0.0 + 0.0i
f[magnitude(V_electrode)] = 0.0 + 0.0i
f[magnitude(I_electrode)] = 0.0 + 0.0i
What equations do you use for the partial derivatives of the
magnitude functions w.r.t. the actual complex variables (V_block and
V_electrode) in the jacobian evaluation?
Since I set all the residuals for both magnitude variables to zero,
and each entry in the Jacobian matrix is a partial derivative of a
residual, I believe the Jacobian entries for both magnitudes would all
be zero as well. However, your point made me realize I have no
Jacobian entry for the partial derivative of f[V_block] w.r.t.
V_electrode. Is that needed? How would one enter it with
MatSetValuesStencil? My working understanding was that each degree of
freedom conceptually has its own residual and Jacobian, even though
all residuals are contained in one Vec and all Jacobians contained in
one Mat.
The first two potentials, V_block and V_electrode, are independent,
while magnitude(V_electrode) is a function of V_electrode only and
the
electrode current magnitude(I_electrode) is a function of V_block
and
V_electrode. Note that V_electrode acts as a source term in the
finite
difference formulation for V_block. While all of these variables
are
complex, the latter two always have zero imaginary parts. I suppose
I
am assuming that PETSc knows to compare only the real parts if the
imaginary parts are zero. (Is this a bad assumption?)
When solving with PETSc (using -snes_vi_type rs)
Did you also use -snes_type vi?
I have been using SNESSetType(snes, SNESVI) in my code, and the use of
-snes_type vi in the command line does not seem to change any
behaviour.
V_electrode stays at
its maximum, as set in the initial guess, and the V_block
distribution
falls properly from that. However, measurements of
magnitude(I_electrode) are way above maximum and do not move
downwards
with successive SNES iterations. I can also set the constraint on
magnitude(V_electrode) to less than maximum and it does not affect
the
value of V_electrode. How can I tell PETSc to change V_electrode
when
the magnitude(V_electrode) or magnitude(I_electrode) constraints
are
not met?
Send the code for your application with instructions on how to run
it and we'll try to figure out what needs to be
done.
I really appreciate this generous offer of your time, and I will
certainly take you up on it if we cannot resolve this otherwise.
Unfortunately, I will be travelling for the next few weeks and it may
take me some time to isolate the PETSc-dependent parts of my
application. Please bear with me as I will try to keep in touch while
I am away.
As I mentioned above, I think the issue may lie in the conceptual
incompatibility of complex variables and inequality constraints, but I
would appreciate your thoughts on that.
Thanks again,
Jon
Shri
Thanks again for your help.
Jon
On 2011-07-25, at 8:58 PM, Barry Smith wrote:
On Jul 25, 2011, at 5:50 PM, Jonathan Backs wrote:
Hi Shri,
Thanks for your message and all the helpful tips. If the
TSVISetVariableBounds() functions are available now, I would like
to try them as well. Is the interface essentially the same as
with
SNESVISetVariableBounds()? I will get back to you and Barry when
I
have had a chance to modify my application.
For my problem, I believe it makes sense to have bounds on one of
the variables as well as one function of the variables. The two
relevant degrees of freedom are the block voltage (one for each
finite difference block) and the electrode voltage (one for each
electrode, which may be present in multiple blocks). The
electrode
voltage should keep a constant phase while the magnitude is
constrained between zero and some maximum. The block voltages
near
the electrodes depend on the electrode voltages as well as the
neighbouring block voltages. The electrode current for a given
electrode is a function of its electrode voltage and several
nearby
block voltages, and should be constrained in magnitude between
zero
and some maximum (and the phase unconstrained). Would I need to
use
SNESVISetComputeVariableBounds since the electrode current is a
function of the other variables? Would any other provisions need
to
be made for the block voltages, since they depend on the
electrode
voltages?
You cannot directly make a bound on some function of other
variables. Instead you need to introduce another variable that is
defined to be equal to that function and put the bound on that
new
variable.
Barry
Thank you again,
Jon
On 2011-07-25, at 11:58 AM, Shri wrote:
----- Original Message -----
On Jul 22, 2011, at 4:16 PM, Jonathan Backs wrote:
Barry,
Thank you so much for your response. Lucky, indeed! I look
forward
to trying out these new features.
I neglected to mention in my original post that my electrical
problem is part of a DAE, which includes a time-dependent
heating
problem. Can SNESVI constraints be used in conjunction with
TSSetIFunction() and TSSetIJacobian() as well? (Of course, I
only
need the constraints for the time-independent electrical
portion.)
We have not yet put that in but Shri is starting to look at
that
just
now. Basically we would have a TSVISetVariableBounds() and
handle
everything from there. I suggest you start with a simple time
electrical portion with constraints to explore and we'll go
from
there. Shri is actually a electrical networks guy and so can
speak
your language.
I've added TSVISetVariableBounds() for setting the bounds on the
variables using the TS object directly.
A few things that i want to mention here about using the
variational inequality nonlinear solver (SNESVI).
i) Use the runtime option -snes_type vi or explicitly set
SNESSetType(snes,SNESVI).
ii) There are two tested algorithms currently available, (a)
semismooth (-snes_vi_type ss) and (b) active set or reduced
space
(-snes_vi_type rs).
iii) Take a look at example,ex61.c, in
src/snes/examples/tutorials
which is a time-stepping nonlinear problem with constraints on
the
variables. This example does not use the TS object directly but
rather a time-loop is explicitly written. Another example,ex8.c,
in src/snes/examples/tests/ is a minimum surface area problem
which uses SNESVI.
By the way, does your problem have bounds on the variables or
bounds on some function of the variables?
Shri
Barry
Thank you again,
Jon
On 2011-07-22, at 2:46 PM, Barry Smith wrote:
Jon,
You may be in luck. In PETSc-dev
http://www.mcs.anl.gov/petsc/petsc-as/developers/index.html
we
have now implemented variational inequality non-linear
solvers
with box constraints.
That is one has a set of variables u and algebraic equations
F(u) = 0 (say of size n each) but in addition one has
constraints lu <= u <= uu where some or all of lu may be
negative infinity (no constraints) and some or all of uu may
be
infinity (no constraints). There is also a constraint on the
sign of F() for those equations associated with active
constraints. If your constraints are not in this form
sometimes
you can introduce new additional variables to get it in this
form. Read up a little on variational inequalities on the
web.
To use this you provide the usual SNES function and Jacobian
but
you also provide SNESVISetVariableBounds() there is a manual
page for this function and for for SNESVI at
http://www.mcs.anl.gov/petsc/petsc-as/snapshots/petsc-dev/docs/index.html
(the link is broken right now but Satish is fixing it). Plus
several examples in src/snes/examples/tutorials (in
petsc-dev).
This is all new code so we would be interested in your
feedback.
Barry
On Jul 22, 2011, at 3:33 PM, Jonathan Backs wrote:
Hi,
I am trying to add a constraint feature to my first PETSc
application, which uses the finite difference method to
calculate
the potential distribution produced by a collection of
electrodes
in a resistive medium. I would like to make this simulation
more
realistic by imposing a maximum electric current and a
maximum
potential difference that can be supplied to each electrode
by
the
power supply. If the medium between the electrodes is very
conductive, the current maximum would be exceeded by the
maximum
potential difference, so the potential difference should be
decreased from maximum until it produces the maximum
current.
On
the other hand, the potential difference between the
electrodes
should remain at maximum as long as the current remains
below
maximum (say, for a less conductive medium).
I added an extra degree of freedom (the electrode voltages)
to
my
DMDA, and I developed a set of conditional expressions that
describe the above constraints, but one problem is that the
logic
relies on if-then-else decisions that are made when forming
the
function/residual and the Jacobian. Once these decisions are
made,
of course, the conditions are not checked again until the
next
function or Jacobian evaluation. The non-linear solver then
tends
to oscillate between extreme solutions to the opposing
conditions
with each iteration, and never converges towards a
reasonable
solution.
Is there a better strategy for solving such problems? Does
PETSc
offer mechanisms to aid in their solution? I would very much
appreciate any hints.
Thank you for your time,
Jon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mcs.anl.gov/pipermail/petsc-users/attachments/20110908/0af5c3db/attachment-0001.htm>
More information about the petsc-users
mailing list