Note

You can download this example as a Jupyter notebook or start it in interactive mode.

Solve on a Server#

In this example, we explain how linopy can handle model optimization on remote machines. What you need in order to run the example: * a running installation of paramiko on your local machine (use pip install paramiko for example) * a remote server with an working installation of linopy, e.g. in a conda environment. * a working ssh access to that machine

The basic idea that the workflow follows consists of the following steps most of which linopy takes over for you:

  1. define a model on the local machine

  2. save the model on the remote machine

  3. load, solve and write out the model, all on the remote machine

  4. copy the solved model to the local machine

  5. load the solved model on the local machine

Therefore the initialization process happens locally and the solving remotely.

Create a model#

First we are going to build the optimization model we want to solve in our local process.

[6]:
from linopy import Model
from numpy import arange
from xarray import DataArray

N = 10
m = Model()
coords = [arange(N), arange(N)]
x = m.add_variables(coords=coords, name='x')
y = m.add_variables(coords=coords, name='y')
m.add_constraints(x - y >= DataArray(arange(N)))
m.add_constraints(x + y >= 0)
m.add_objective((2 * x + y).sum())
m
[6]:
Linopy LP model
===============

Variables:
----------
 * x (dim_0, dim_1)
 * y (dim_0, dim_1)

Constraints:
------------
 * con0 (dim_0, dim_1)
 * con1 (dim_0, dim_1)

Status:
-------
initialized

Initialize SSH connection#

Now we have to set up the SSH connection. The SSH connection is handled by the RemoteHandler class in of the linopy.remote module. This is strongly relying on the paramiko package. When initializing, you have two options:

  1. Pass the standard arguments host, username. If the SSH keys are stored in a default location, the keys are autodetected and the RemoteHandler does not require the password argument. Otherwise you also have to pass the password.

  2. Pass a working paramiko.SSHClient as client. This enables you to set up the SSH connection by others means supported by paramiko.

In the following we use the first option.

[2]:
from linopy import RemoteHandler

host = "your.host.de"
username = "username"

handler = RemoteHandler(host, username=username)

Optionally: Activate a conda environment on the remote#

The RemoteHandler keeps an interactive shell in the background. You can execute any code in order to prepare the solving process (install linopy, activate an environment).

Assuming you have a conda environment linopy-env that contains the linopy package with dependencies, you can run

[3]:
handler.execute("conda activate linopy-env")

Solve the model on remote#

Now the only thing you have to do is to pass the RemoteHandler as an argument to the solve function. Other keyword arguments like solver_name and solver options are propagated to the remote machine.

[4]:
m.solve(remote=handler)
Set parameter Username
Academic license - for non-commercial use only - expires 2023-02-06
Read LP format model from file /tmp/linopy-problem-uh4gvjyp.lp
Reading time = 0.00 seconds
obj: 200 rows, 200 columns, 400 nonzeros
Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)
Thread count: 12 physical cores, 24 logical processors, using up to 24 threads
Optimize a model with 200 rows, 200 columns and 400 nonzeros
Model fingerprint: 0xf2bcac49
Coefficient statistics:
Matrix range     [1e+00, 1e+00]
Objective range  [1e+00, 2e+00]
Bounds range     [0e+00, 0e+00]
RHS range        [1e+00, 9e+00]
Presolve removed 200 rows and 200 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Iteration    Objective       Primal Inf.    Dual Inf.      Time
0    2.2500000e+02   0.000000e+00   0.000000e+00      0s

Solved in 0 iterations and 0.00 seconds (0.00 work units)
Optimal objective  2.250000000e+02
[4]:
('ok', '')
[5]:
m.solution
[5]:
<xarray.Dataset>
Dimensions:  (dim_0: 10, dim_1: 10)
Coordinates:
  * dim_0    (dim_0) int64 0 1 2 3 4 5 6 7 8 9
  * dim_1    (dim_1) int64 0 1 2 3 4 5 6 7 8 9
Data variables:
    x        (dim_0, dim_1) float64 0.0 0.0 0.0 0.0 0.0 ... 4.5 4.5 4.5 4.5 4.5
    y        (dim_0, dim_1) float64 0.0 0.0 0.0 0.0 0.0 ... -4.5 -4.5 -4.5 -4.5