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!
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
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