brocksam / pycollo

General-purpose optimal control, trajectory optimisation and parameter optimisation using direct collocation
https://brocksam.github.io/pycollo/
MIT License
8 stars 3 forks source link

Example of multiphase optimization #50

Closed jtheinen closed 2 years ago

jtheinen commented 2 years ago

Is there an example that shows a successful multiphase optimization? Delta III is not yet solvable.

From an issue I saw it was possible to leave the start/end time as a variable, but that a problem can become unsolvable. Would just stating start and end time be an issue when considering multiple phases?

brocksam commented 2 years ago

Thanks for pointing this out. This will be a good type of problem to discuss in greater detail in the documentation.

I've added a new example to illustrate this: https://github.com/brocksam/pycollo/blob/main/examples/multiphase_point_move/multiphase_point_move.py

In this example there are two phases, A and B, and an endpoint constraint is used to enforce that the final time of A is equal to the initial time of B, i.e. they are consecutive. Other endpoint constraints are also used to enforce continuity in the dynamics (positions and velocities) at the adjacent boundary of these two phases too.

The final time of A, initial time of B, and final time of B are all left as variable, by setting non-equal lower and upper bounds for each of them. If you wish to fix the problem final time (i.e. the final time of B) then you can replace the lower-upper bound pair list with a constant (or set both the lower and upper bounds in the pair equal). If you wish to fix the time of the phase boundary (i.e. the final time of A and the initial time of B) then you can do the same to the bounds of both the final time of A and the initial time of B while also removing the endpoint constraint (and its bound of 0) that enforces them to be equal.

I hope that helps. If anything is unclear, or you have follow up questions, please let me know.

jtheinen commented 2 years ago

Thanks! That helps a lot, reading the code makes it clear as well. Though, the code of the example gives an error, do you get the same error?

===============================
Initialising mesh iteration #2.
===============================

Guess interpolated to iteration mesh in 6.89ms.
Scaling initialised in 349.62us.
Initial guess scaled in 36.44us.
Traceback (most recent call last):

  File ~/Master Thesis/Python/Pycollo/multiphase.py:179 in <module>
    problem.solve()

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/optimal_control_problem.py:415 in solve
    tolerances_met = self._solve_iteration()

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/optimal_control_problem.py:438 in _solve_iteration
    _ = self._backend.new_mesh_iteration(self._next_iteration_mesh,

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/backend.py:845 in new_mesh_iteration
    new_iteration = Iteration(

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/iteration.py:66 in __init__
    self.initialise()

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/iteration.py:84 in initialise
    self.generate_nlp()

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/iteration.py:386 in generate_nlp
    self.backend.generate_nlp_function_callables(self)

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/backend.py:1412 in generate_nlp_function_callables
    self.generate_constraint_function_callable()

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/backend.py:1656 in generate_constraint_function_callable
    all_phase_mapping = make_all_phase_mapping(self.current_iteration.mesh)

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/backend.py:1534 in make_all_phase_mapping
    mapping = {k: v[i]

  File ~/opt/anaconda3/lib/python3.9/site-packages/pycollo/backend.py:1534 in <dictcomp>
    mapping = {k: v[i]

  File ~/opt/anaconda3/lib/python3.9/site-packages/casadi/casadi.py:9118 in __getitem__
    return self.get(False, s)

  File ~/opt/anaconda3/lib/python3.9/site-packages/casadi/casadi.py:8037 in get
    return _casadi.SX_get(self, *args)

RuntimeError: .../casadi/core/slice.cpp:83: Assertion "stop<=len" failed:
Slice (start=38, stop=39, step=1) out of bounds with supplied length of 38
brocksam commented 2 years ago

I do not, which is very weird. Have you edited anything in the file at all or are you running exactly as is from the GitHub repo? How did you install Pycollo? It may be that a new release is needed if you've installed from conda-forge.

In the meantime, you can hopefully get this to work by turning off the adaptive mesh refinement as it's not strictly needed, especially for a problem still simple. If you add

problem.settings.max_mesh_iterations = 1

before calling

problem.initialise()
problem.solve()

that should terminate the solve without mesh refinement before this bug is encountered.

brocksam commented 2 years ago

Version 0.1.6 should fix this bug. It has been released and is on PyPI already. I'm just waiting for the conda-forge bot to create the PR on the feedstock for the new version before it'll be available via conda. This will probably take another couple of hours.

brocksam commented 2 years ago

Pycollo 0.1.6, which should resolve this issue, is now available from both PyPI and conda-forge. Please let me know when you've had a chance to test to confirm that it is indeed resolved. Thanks.

jtheinen commented 2 years ago

The update to pycollo 0.1.6 solved the error.

The piece of code suggested also worked in 0.1.5

problem.settings.max_mesh_iterations = 1

brocksam commented 2 years ago

@jtheinen I'm closing this because it appears to now be resolved. Please feel free to reopen if that's not the case.