Search code examples
openmdao

Final boundary constraint with states from two tandem phases in Dymos


Is it possible to create a boundary constraint in Dymos with states from two separate tandem phases? In my problem the first phase is governed by a system of ODEs with a control, and the second tandem phase is governed by the same system but without a control. The two phases have different initial conditions, but I want to create a boundary constraint that sets their final states equal to each other. The final time is a free variable.

My current solution is to simply "stack" the second system with the first system in a single phase and impose a constraint like phase.add_boundary_constraint('diff = xp1 - xp2', loc='final', equals=0), but this isn't the most efficient, especially when performing grid refinement, since a much coarser transcription can sufficiently describe the dynamics of the non-controlled phase.

Are there any other ways I could approach setting something like this up? Thanks!


Solution

  • This sounds like the purpose of linkage constraints in dymos. This is a convenience feature that lets the user impose constraints on the relationship between two values at different phase endpoints.

    https://openmdao.github.io/dymos/features/trajectories/trajectories.html#add-linkage-constraint

    For example, in the case where we find the shortest possible "balanced field" length for an aircraft, we want to impose the condition that

    • if the takeoff is rejected, the end of the braking roll occurs at some range (the length of the runway)
    • if the takeoff continues with a single engine, the aircraft clears 25 feet of altitude at the end of the runway

    https://openmdao.github.io/dymos/examples/balanced_field/balanced_field.html

    In particular, the following call says that range (r) at the end (final) of rejected-takeoff (rto) has to equal range at the end of climb.

    traj.add_linkage_constraint(phase_a='rto', var_a='r', loc_a='final',
                                phase_b='climb', var_b='r', loc_b='final',
                                ref=1000)
    

    These phases also enforce that the aircraft has zero velocity at the end of rto, and that the aircraft has an altitude of 35 ft at the end of climb.

    rto.add_boundary_constraint('v', loc='final', equals=0., ref=100, linear=True)
    
    climb.add_boundary_constraint('h', loc='final', equals=35, ref=35, units='ft', linear=True) # end climb with 35 ft of altitude.
    climb.add_boundary_constraint('gam', loc='final', equals=5, ref=5, units='deg', linear=True) # end climb with a 5 degree flight path angle.
    climb.add_path_constraint('gam', lower=0, upper=5, ref=5, units='deg') # never descend
    climb.add_boundary_constraint('v_over_v_stall', loc='final', lower=1.25, ref=1.25) # avoid stall