Difference between revisions of "Source Inversion (FEniCS/Casadi)"

From mintOC
Jump to: navigation, search
(Created page with "This page contains a discretized version of the mixed integer PDE constrained optimization problem Source Inversion in [http://www.casadi.org CasADi 2.4.3] format. The wea...")
 
Line 231: Line 231:
  
 
Node solutions are calculated using IPOPT (3.12, default settings, using linear solver MUMPS on Ubuntu 15.10 for x86-64 with Linux 4.2.0-19-generic, Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz, 16 GB RAM). The objective function value is <math>0.858837</math>. The integer solution is found after processing 25 nodes.
 
Node solutions are calculated using IPOPT (3.12, default settings, using linear solver MUMPS on Ubuntu 15.10 for x86-64 with Linux 4.2.0-19-generic, Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz, 16 GB RAM). The objective function value is <math>0.858837</math>. The integer solution is found after processing 25 nodes.
 +
 +
== Solution ==
 +
 +
The following is a Gnuplot compatible tabular version of the control data determined by the solver:
 +
 +
<pre>
 +
# x      w        w0
 +
  0.0625        0 2.91549e-08
 +
  0.1875        0 2.75108e-08
 +
  0.3125        0 6.746e-08
 +
  0.4375        1  0.46917
 +
  0.5625        0  0.543817
 +
  0.6875        0 1.33205e-07
 +
  0.8125        0 1.51069e-07
 +
  0.9375        1  0.897707
 +
</pre>
 +
 +
The following is a Gnuplot compatible tabular version of the solution found using FEM approximations:
 +
 +
<pre>
 +
# x        u        u0
 +
        0    19.845  18.7521
 +
0.0078125  20.0001  18.8986
 +
0.015625  20.1551  19.0451
 +
0.0234375  20.3101  19.1916
 +
  0.03125  20.4652  19.3381
 +
0.0390625  20.6202  19.4846
 +
0.046875  20.7752  19.6311
 +
0.0546875  20.9303  19.7776
 +
  0.0625  21.0853  19.9241
 +
0.0703125  21.2403  20.0706
 +
0.078125  21.3953  20.2171
 +
0.0859375  21.5503  20.3635
 +
  0.09375  21.7053    20.51
 +
0.101562  21.8603  20.6565
 +
0.109375  22.0153  20.8029
 +
0.117188  22.1702  20.9494
 +
    0.125  22.3251  21.0958
 +
0.132812  22.4799  21.2422
 +
0.140625  22.6347  21.3886
 +
0.148438  22.7894  21.5349
 +
  0.15625    22.944  21.6812
 +
0.164062  23.0985  21.8275
 +
0.171875  23.2528  21.9737
 +
0.179688    23.407  22.1197
 +
  0.1875    23.561  22.2657
 +
0.195312  23.7146  22.4116
 +
0.203125    23.868  22.5573
 +
0.210938  24.0209  22.7028
 +
  0.21875  24.1734    22.848
 +
0.226562  24.3254    22.993
 +
0.234375  24.4766  23.1377
 +
0.242188  24.6271    23.282
 +
    0.25  24.7767  23.4259
 +
0.257812  24.9252  23.5692
 +
0.265625  25.0725  23.7119
 +
0.273438  25.2184    23.854
 +
  0.28125  25.3627  23.9952
 +
0.289062  25.5052  24.1355
 +
0.296875  25.6457  24.2748
 +
0.304688  25.7839    24.413
 +
  0.3125  25.9196  24.5498
 +
0.320312  26.0525  24.6852
 +
0.328125  26.1823  24.8189
 +
0.335938  26.3088  24.9509
 +
  0.34375  26.4316  25.0809
 +
0.351562  26.5505  25.2087
 +
0.359375  26.6651  25.3342
 +
0.367188  26.7753  25.4572
 +
    0.375  26.8807  25.5774
 +
0.382812  26.9811  25.6947
 +
0.390625  27.0762  25.8089
 +
0.398438  27.1659  25.9198
 +
  0.40625  27.2499  26.0271
 +
0.414062  27.3281  26.1308
 +
0.421875  27.4004  26.2305
 +
0.429688  27.4666  26.3262
 +
  0.4375  27.5268  26.4177
 +
0.445312  27.5809  26.5047
 +
0.453125  27.6289  26.5873
 +
0.460938  27.6708  26.6652
 +
  0.46875  27.7069  26.7384
 +
0.476562  27.7371  26.8066
 +
0.484375  27.7617    26.87
 +
0.492188  27.7808  26.9283
 +
      0.5  27.7947  26.9816
 +
0.507812  27.8035  27.0298
 +
0.515625  27.8076  27.0729
 +
0.523438  27.8072  27.1109
 +
  0.53125  27.8026  27.1438
 +
0.539062    27.794  27.1718
 +
0.546875  27.7818  27.1948
 +
0.554688  27.7662    27.213
 +
  0.5625  27.7476  27.2264
 +
0.570312  27.7261  27.2352
 +
0.578125  27.7021  27.2395
 +
0.585938  27.6759  27.2394
 +
  0.59375  27.6476  27.2351
 +
0.601562  27.6174  27.2269
 +
0.609375  27.5857  27.2147
 +
0.617188  27.5525    27.199
 +
    0.625  27.5181  27.1797
 +
0.632812  27.4826  27.1573
 +
0.640625  27.4461  27.1317
 +
0.648438  27.4087  27.1032
 +
  0.65625  27.3706  27.0721
 +
0.664062  27.3318  27.0385
 +
0.671875  27.2924  27.0025
 +
0.679688  27.2525  26.9644
 +
  0.6875  27.2119  26.9242
 +
0.695312  27.1709  26.8821
 +
0.703125  27.1293  26.8383
 +
0.710938  27.0871  26.7928
 +
  0.71875  27.0443  26.7457
 +
0.726562  27.0008  26.6971
 +
0.734375  26.9566  26.6469
 +
0.742188  26.9115  26.5953
 +
    0.75  26.8654  26.5422
 +
0.757812  26.8183  26.4875
 +
0.765625  26.7699  26.4312
 +
0.773438    26.72  26.3732
 +
  0.78125  26.6686  26.3135
 +
0.789062  26.6153  26.2517
 +
0.796875    26.56    26.188
 +
0.804688  26.5024  26.1219
 +
  0.8125  26.4423  26.0534
 +
0.820312  26.3794  25.9822
 +
0.828125  26.3134  25.9082
 +
0.835938    26.244  25.8311
 +
  0.84375    26.171  25.7506
 +
0.851562    26.094  25.6665
 +
0.859375  26.0129  25.5785
 +
0.867188  25.9272  25.4865
 +
    0.875  25.8368  25.3902
 +
0.882812  25.7413  25.2893
 +
0.890625  25.6406  25.1837
 +
0.898438  25.5345  25.0732
 +
  0.90625  25.4227  24.9576
 +
0.914062    25.305  24.8368
 +
0.921875  25.1815  24.7107
 +
0.929688  25.0519  24.5791
 +
  0.9375  24.9162  24.4421
 +
0.945312  24.7745  24.2996
 +
0.953125  24.6267  24.1516
 +
0.960938  24.4728  23.9982
 +
  0.96875    24.313  23.8395
 +
0.976562  24.1474  23.6756
 +
0.984375  23.9762  23.5067
 +
0.992188  23.7995  23.3328
 +
        1  23.6175  23.1542
 +
</pre>
 
   
 
   
 
[[Category:Casadi]]
 
[[Category:Casadi]]

Revision as of 23:37, 12 January 2016

This page contains a discretized version of the mixed integer PDE constrained optimization problem Source Inversion in CasADi 2.4.3 format. The weak version of the problem was discretized using finite element methods (via FEniCS) using first-degree Lagrangian elements on an equidistant mesh with 128 cells.

CasADi

from dolfin import *
 
import math
import numpy
import scipy, scipy.sparse
import casadi
 
 
# Simple Branch and Bound solver
def solve_bnb(solver, root, integers):
    # Initialize the node queue
    Q = [(numpy.inf, root)]
 
    # Global solution data
    x_opt = None
    f_opt = numpy.inf
 
    # Continuous solution data
    x0 = None
    f0 = numpy.inf
 
    # Main loop
    seqnum = 0
    while Q:
        seqnum += 1
 
        # Extract node with lowest lower bound and check if fathoming is necessary
        # (should not happen)
        node = Q.pop()
        if f_opt < numpy.inf and node[0] >= f_opt:
            print "Node %4d (%4d left): %9g >= %9g - PRE-FATHOM" % (seqnum, len(Q), node[0], f_opt)
            continue
        node = node[1]
 
        # Solve the node
        result = solver(node)
 
        # Local solution data
        x = result['x']
        f = result['f'].get()[0]
 
        # Store continuous solution data if none has been stored yet
        if x0 is None:
            x0 = casadi.DMatrix(x)
            f0 = f
 
        # Check if branch can be fathomed
        if f >= f_opt:
            print "Node %4d (%4d left): %9g >= %9g - POST-FATHOM" % (seqnum, len(Q), f, f_opt)
            continue
 
        # Check for violations of integrality (fixed tolerance 1e-5)
        viol = [abs(casadi.floor(x[i] + 0.5) - x[i]) for i in integers]
        idx  = [(integers[i], viol[i]) for i in range(len(integers)) if viol[i] > 1e-5]
        if not idx:
            # Register new global solution
            x_opt = x
            f_opt = f
 
            # Cull the branch and bound tree
            pre  = len(Q)
            Q    = [n for n in Q if n[0] < f_opt]
            post = len(Q)
 
            print "Node %4d (%4d left): f_opt = %9g - *** SOLUTION *** (%d culled)" % (seqnum, len(Q), f, pre - post)
        else:
            # Branch on first violation
            idx = idx[0][0]
 
            # Generate two new nodes (could reuse node structure)
            ln = {
                'x0':     casadi.DMatrix(x),
                'lbx':    node['lbx'],
                'ubx':    casadi.DMatrix(node['ubx']),
                'lbg':    node['lbg'],
                'ubg':    node['ubg'],
                'lam_x0': casadi.DMatrix(result['lam_x']),
                'lam_g0': casadi.DMatrix(result['lam_g'])
            }
            un = {
                'x0':     casadi.DMatrix(x),
                'lbx':    casadi.DMatrix(node['lbx']),
                'ubx':    node['ubx'],
                'lbg':    node['lbg'],
                'ubg':    node['ubg'],
                'lam_x0': casadi.DMatrix(result['lam_x']),
                'lam_g0': casadi.DMatrix(result['lam_g'])
            }
 
            ln['ubx'][idx] = casadi.floor(x[idx])
            un['lbx'][idx] = casadi.ceil(x[idx])
 
            lower_node = (f, ln)
            upper_node = (f, un)
 
            # Insert new nodes in queue (inefficient for large queues)
            Q.extend([lower_node, upper_node])
            Q.sort(cmp=lambda x,y: cmp(y[0], x[0]))
            print "Node %4d (%4d left): %9g - BRANCH ON %d" % (seqnum, len(Q), f, idx)
 
    return {
        'x0': x0,
        'f0': f0,
        'x': x_opt,
        'f': f_opt
    }
 
 
# Converts FEniCS matrix to scipy.sparse.coo_matrix
def matrix_to_coo(A, shape=None):
    nnz = A.nnz()
    col = numpy.empty(nnz, dtype='uint64')
    row = numpy.empty(nnz, dtype='uint64')
    val = numpy.empty(nnz)
 
    if shape is None:
        shape = (A.size(0), A.size(1))
 
    it = 0
    for i in range(A.size(0)):
        col_local, val_local = A.getrow(i)
        nnz_local = col_local.shape[0]
 
        col[it:it+nnz_local] = col_local[:]
        row[it:it+nnz_local] = i
        val[it:it+nnz_local] = val_local[:]
        it                  += nnz_local
 
    return scipy.sparse.coo_matrix((val, (row, col)), shape=shape)
 
 
# Returns FEniCS expression for elementary source term
def source_term(x0):
    return Expression("100.0 * exp(-pow(x[0] - x0, 2) / 0.02)", x0=x0)
 
# Grid resolutions
nx = 128
nu = 8
 
# Generate mesh and function space
mesh = UnitIntervalMesh(nx)
V    = FunctionSpace(mesh, 'CG', 1)
 
# Define the bilinear form and assemble it
u = TrialFunction(V)
v = TestFunction(V)
a = inner(grad(u), grad(v)) * dx + u * v * ds
A = assemble(a)
 
# Create the linear form for the exact source term and perform assembly
f = source_term(3.0 / math.pi) + source_term(0.5)
L = f * v * dx
b = assemble(L)
 
# Solve for the reference solution
u_ref = Function(V)
solve(A, u_ref.vector(), b)
 
# Define the control grid and the elementary source terms
ctrl_grid = numpy.linspace(0.0, 1.0, num=nu+1)[:-1]
ctrl_grid += 0.5 * ctrl_grid[1]
src_expr  = [source_term(x0) for x0 in ctrl_grid]
 
# Assemble the linear forms corresponding to the elementary source terms and
# construct the second half of the coefficient matrix
b = [assemble(-f * v * dx) for f in src_expr]
B = scipy.column_stack([v.array() for v in b])
 
# Construct the full coefficient matrix
C = scipy.sparse.vstack([
    scipy.sparse.hstack([matrix_to_coo(A), B]),
    scipy.sparse.coo_matrix(([1.0]*nu, ([0]*nu, [V.dim() + i for i in range(nu)])), shape=(1, V.dim() + nu))
])
 
# Transfer the optimization constraints to CasADi
C  = casadi.DMatrix(C)
lb = casadi.DMatrix.zeros(C.shape[0], 1)
ub = casadi.DMatrix.zeros(C.shape[0], 1)
 
lb[-1] = 0.0
ub[-1] = 5.0
 
lbx = numpy.array([-numpy.inf]*V.dim() + [0.0]*nu)
ubx = numpy.array([ numpy.inf]*V.dim() + [1.0]*nu)
 
# Define the objective functional and assemble it
u     = Function(V)
J     = (u_ref - u)**2 * dx
dJdu  = derivative(J, u)
dJdu2 = derivative(dJdu, u)
 
H = casadi.DMatrix(matrix_to_coo(assemble(dJdu2), shape=(V.dim() + nu, V.dim() + nu)))
g = casadi.DMatrix(numpy.concatenate((assemble(dJdu).array(), [0.0]*nu)))
c = assemble(J)
 
# Build the CasADi NLP
x   = casadi.MX.sym('X', V.dim() + nu)
nlp = casadi.MXFunction('nlp',
    casadi.nlpIn(x=x),
    casadi.nlpOut(
        f=0.5*casadi.quad_form(x, H) + casadi.inner_prod(g, x) + c,
        g=casadi.mul(C, x)
    ))
 
# Build NLP solver
solver = casadi.NlpSolver('solver', 'ipopt', nlp, {
    'print_level': 0,
    'print_time':  False
})
result = solve_bnb(solver, {
    'lbx': lbx,
    'ubx': ubx,
    'lbg': lb,
    'ubg': ub
}, range(V.dim(), V.dim() + nu))
 
# Evaluate result
print ""
print "----------------------------"
print " f = %g" % result['f']
 
u.vector()[:] = result['x'][:V.dim()].toArray()[:,0]

Results

Node solutions are calculated using IPOPT (3.12, default settings, using linear solver MUMPS on Ubuntu 15.10 for x86-64 with Linux 4.2.0-19-generic, Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz, 16 GB RAM). The objective function value is 0.858837. The integer solution is found after processing 25 nodes.

Solution

The following is a Gnuplot compatible tabular version of the control data determined by the solver:

# x       w         w0
   0.0625         0 2.91549e-08
   0.1875         0 2.75108e-08
   0.3125         0 6.746e-08
   0.4375         1   0.46917
   0.5625         0  0.543817
   0.6875         0 1.33205e-07
   0.8125         0 1.51069e-07
   0.9375         1  0.897707

The following is a Gnuplot compatible tabular version of the solution found using FEM approximations:

# x         u         u0
        0    19.845   18.7521
0.0078125   20.0001   18.8986
 0.015625   20.1551   19.0451
0.0234375   20.3101   19.1916
  0.03125   20.4652   19.3381
0.0390625   20.6202   19.4846
 0.046875   20.7752   19.6311
0.0546875   20.9303   19.7776
   0.0625   21.0853   19.9241
0.0703125   21.2403   20.0706
 0.078125   21.3953   20.2171
0.0859375   21.5503   20.3635
  0.09375   21.7053     20.51
 0.101562   21.8603   20.6565
 0.109375   22.0153   20.8029
 0.117188   22.1702   20.9494
    0.125   22.3251   21.0958
 0.132812   22.4799   21.2422
 0.140625   22.6347   21.3886
 0.148438   22.7894   21.5349
  0.15625    22.944   21.6812
 0.164062   23.0985   21.8275
 0.171875   23.2528   21.9737
 0.179688    23.407   22.1197
   0.1875    23.561   22.2657
 0.195312   23.7146   22.4116
 0.203125    23.868   22.5573
 0.210938   24.0209   22.7028
  0.21875   24.1734    22.848
 0.226562   24.3254    22.993
 0.234375   24.4766   23.1377
 0.242188   24.6271    23.282
     0.25   24.7767   23.4259
 0.257812   24.9252   23.5692
 0.265625   25.0725   23.7119
 0.273438   25.2184    23.854
  0.28125   25.3627   23.9952
 0.289062   25.5052   24.1355
 0.296875   25.6457   24.2748
 0.304688   25.7839    24.413
   0.3125   25.9196   24.5498
 0.320312   26.0525   24.6852
 0.328125   26.1823   24.8189
 0.335938   26.3088   24.9509
  0.34375   26.4316   25.0809
 0.351562   26.5505   25.2087
 0.359375   26.6651   25.3342
 0.367188   26.7753   25.4572
    0.375   26.8807   25.5774
 0.382812   26.9811   25.6947
 0.390625   27.0762   25.8089
 0.398438   27.1659   25.9198
  0.40625   27.2499   26.0271
 0.414062   27.3281   26.1308
 0.421875   27.4004   26.2305
 0.429688   27.4666   26.3262
   0.4375   27.5268   26.4177
 0.445312   27.5809   26.5047
 0.453125   27.6289   26.5873
 0.460938   27.6708   26.6652
  0.46875   27.7069   26.7384
 0.476562   27.7371   26.8066
 0.484375   27.7617     26.87
 0.492188   27.7808   26.9283
      0.5   27.7947   26.9816
 0.507812   27.8035   27.0298
 0.515625   27.8076   27.0729
 0.523438   27.8072   27.1109
  0.53125   27.8026   27.1438
 0.539062    27.794   27.1718
 0.546875   27.7818   27.1948
 0.554688   27.7662    27.213
   0.5625   27.7476   27.2264
 0.570312   27.7261   27.2352
 0.578125   27.7021   27.2395
 0.585938   27.6759   27.2394
  0.59375   27.6476   27.2351
 0.601562   27.6174   27.2269
 0.609375   27.5857   27.2147
 0.617188   27.5525    27.199
    0.625   27.5181   27.1797
 0.632812   27.4826   27.1573
 0.640625   27.4461   27.1317
 0.648438   27.4087   27.1032
  0.65625   27.3706   27.0721
 0.664062   27.3318   27.0385
 0.671875   27.2924   27.0025
 0.679688   27.2525   26.9644
   0.6875   27.2119   26.9242
 0.695312   27.1709   26.8821
 0.703125   27.1293   26.8383
 0.710938   27.0871   26.7928
  0.71875   27.0443   26.7457
 0.726562   27.0008   26.6971
 0.734375   26.9566   26.6469
 0.742188   26.9115   26.5953
     0.75   26.8654   26.5422
 0.757812   26.8183   26.4875
 0.765625   26.7699   26.4312
 0.773438     26.72   26.3732
  0.78125   26.6686   26.3135
 0.789062   26.6153   26.2517
 0.796875     26.56    26.188
 0.804688   26.5024   26.1219
   0.8125   26.4423   26.0534
 0.820312   26.3794   25.9822
 0.828125   26.3134   25.9082
 0.835938    26.244   25.8311
  0.84375    26.171   25.7506
 0.851562    26.094   25.6665
 0.859375   26.0129   25.5785
 0.867188   25.9272   25.4865
    0.875   25.8368   25.3902
 0.882812   25.7413   25.2893
 0.890625   25.6406   25.1837
 0.898438   25.5345   25.0732
  0.90625   25.4227   24.9576
 0.914062    25.305   24.8368
 0.921875   25.1815   24.7107
 0.929688   25.0519   24.5791
   0.9375   24.9162   24.4421
 0.945312   24.7745   24.2996
 0.953125   24.6267   24.1516
 0.960938   24.4728   23.9982
  0.96875    24.313   23.8395
 0.976562   24.1474   23.6756
 0.984375   23.9762   23.5067
 0.992188   23.7995   23.3328
        1   23.6175   23.1542