Пример #1
0
def test_Collocation_2():
    # Full 2PBVP test problem
    # This is calculating the 4th eigenvalue of Mathieu's Equation
    # This problem contains an adjustable parameter.

    def odefun(t, X, p, const):
        return (X[1], -(p[0] - 2 * 5 * np.cos(2 * t)) * X[0])

    def bcfun(t0, X0, q0, tf, Xf, qf, p, ndp, aux):
        return (X0[1], Xf[1], X0[0] - 1)

    algo = Collocation(odefun, None, bcfun)
    solinit = Solution()
    solinit.t = np.linspace(0, np.pi, 30)
    solinit.y = np.vstack(
        (np.cos(4 * solinit.t), -4 * np.sin(4 * solinit.t))).T
    solinit.dynamical_parameters = np.array([15])

    out = algo.solve(solinit)
    assert abs(out.t[-1] - np.pi) < tol
    assert abs(out.y[0][0] - 1) < tol
    assert abs(out.y[0][1]) < tol
    assert abs(out.y[-1][0] - 1) < tol
    assert abs(out.y[-1][1]) < tol
    assert abs(out.dynamical_parameters[0] - 17.09646175) < tol
Пример #2
0
 def guess_mapper(sol):
     n_c = len(constants_of_motion)
     if n_c == 0:
         return sol
     sol_out = Solution()
     sol_out.t = copy.copy(sol.t)
     sol_out.y = np.array([[fn(*sol.y[0]) for fn in states_2_states_fn]])
     sol_out.q = sol.q
     if len(quads) > 0:
         sol_out.q = -0.0 * np.array([np.ones((len(quads)))])
     sol_out.dynamical_parameters = sol.dynamical_parameters
     sol_out.dynamical_parameters[-n_c:] = np.array(
         [fn(*sol.y[0]) for fn in states_2_constants_fn])
     sol_out.nondynamical_parameters = sol.nondynamical_parameters
     sol_out.aux = sol.aux
     return sol_out
Пример #3
0
def test_Shooting_3():
    # This problem contains a parameter, but it is not explicit in the BCs.
    # Since time is buried in the ODEs, this tests if the BVP solver calculates
    # sensitivities with respect to parameters.
    def odefun(t, X, p, const):
        return 1 * p[0]

    def bcfun(t0, X0, q0, tf, Xf, qf, p, ndp, aux):
        return (X0[0] - 0, Xf[0] - 2)

    algo = Shooting(odefun, None, bcfun)
    solinit = Solution()
    solinit.t = np.linspace(0, 1, 2)
    solinit.y = np.array([[0], [0]])
    solinit.dynamical_parameters = np.array([1])
    out = algo.solve(solinit)
    assert abs(out.dynamical_parameters - 2) < tol
Пример #4
0
def test_Shooting_1():
    # Full 2PBVP test problem
    # This is the simplest BVP

    def odefun(t, X, p, const):
        return (X[1], -abs(X[0]))

    def bcfun(t0, X0, q0, tf, Xf, qf, p, ndp, aux):
        return (X0[0], Xf[0]+2)

    algo = Shooting(odefun, None, bcfun)
    solinit = Solution()
    solinit.t = np.linspace(0,4,2)
    solinit.y = np.array([[0,1],[0,1]])
    out = algo.solve(solinit)
    assert out.y[0][0] < tol
    assert out.y[0][1] - 2.06641646 < tol
    assert out.y[-1][0] + 2 < tol
    assert out.y[-1][1] + 2.87588998 < tol
    assert out.t[-1] - 4 < tol
    assert abs(out.y[0][1] - solinit.y[0][1]) > tol
    assert abs(out.y[-1][0] - solinit.y[-1][0]) - 2 < tol
Пример #5
0
def test_Shooting_4():
    # This problem contains a quad and tests if the bvp solver correctly
    # integrates the quadfun.

    def odefun(t, x, p, const):
        return -x[1], x[0]

    def quadfun(t, x, p, const):
        return x[0]

    def bcfun(t0, X0, q0, tf, Xf, qf, params, ndp, aux):
        return X0[0], X0[1] - 1, qf[0] - 1.0

    algo = Shooting(odefun, quadfun, bcfun)
    solinit = Solution()
    solinit.t = np.linspace(0, np.pi / 2, 2)
    solinit.y = np.array([[1, 0], [1, 0]])
    solinit.q = np.array([[0], [0]])
    out = algo.solve(solinit)
    assert (out.y[0,0] - 0) < tol
    assert (out.y[0,1] - 1) < tol
    assert (out.q[0,0] - 2) < tol
    assert (out.q[-1,0] - 1) < tol
Пример #6
0
    def load(self):
        """
        Loads solution data using dill if not already loaded
        """
        if not self.is_loaded:
            logging.info("Loading datafile " + self.filename + "...")
            out = loadmat(self.filename)

            if 'output' in out:
                out = out['output']['result'][0][0][0][0]
            soldata = out['solution']['phase'][0][0][0][0]

            # if 'solution' not in self._data:
            #     self.is_loaded = False
            #     logging.error("Solution missing in data file :"+self.filename)
            #     raise RuntimeError("Solution missing in data file :"+self.filename)
            # if 'problem_data' not in self._data:
            #     self.is_loaded = False
            #     logging.error("Problem data missing in data file :"+self.filename)
            #     raise RuntimeError("Problem data missing in data file :"+self.filename)
            #
            _sol = Solution()

            tf = max(soldata['time'])
            _sol.x = soldata['time'][:, 0] / tf
            _sol.y = np.r_[soldata['state'].T, soldata['costate'].T,
                           np.ones_like(soldata['time']).T * tf]
            _sol.u = soldata['control'].T

            if 'tf' not in self.problem_data['state_list']:
                self.problem_data['state_list'] = tuple(
                    self.problem_data['state_list']) + ('tf', )

            _sol.arcs = ((0, len(_sol.x) - 1), )

            if self._const is not None:
                _sol.aux = {'const': self._const}

            self._sol = [[_sol]]
            logging.info('Loaded solution from data file')

            self.is_loaded = True
Пример #7
0
def solve(ocp, method, bvp_algorithm, steps, guess_generator):
    """
    Solves the OCP using specified method
    """
    output_file = config['output_file']
    logging.info("Computing the necessary conditions of optimality")

    if method.lower() == 'traditional' or method.lower() == 'brysonho':
        ocp_ws = BH_ocp_to_bvp(ocp, guess_generator)
    elif method.lower() == 'icrm':
        ocp_ws = ICRM_ocp_to_bvp(ocp, guess_generator)
    else:
        raise NotImplementedError

    ocp_ws['problem'] = ocp
    ocp_ws['guess'] = guess_generator
    ocp_ws['problem_data']['custom_functions'] = ocp.custom_functions()
    solinit = Solution()

    solinit.aux['const'] = OrderedDict(
        (str(const.name), float(const.value)) for const in ocp_ws['constants'])

    solinit.aux['dynamical_parameters'] = [
        str(p) for p in ocp_ws['problem_data']['dynamical_parameters']
    ]
    solinit.aux['nondynamical_parameters'] = [
        str(p) for p in ocp_ws['problem_data']['nondynamical_parameters']
    ]

    bvp = preprocess(ocp_ws['problem_data'])
    solinit = ocp_ws['guess'].generate(bvp, solinit)

    state_names = ocp_ws['problem_data']['state_list']

    initial_states = solinit.y[0, :]
    terminal_states = solinit.y[-1, :]

    initial_bc = dict(zip(state_names, initial_states))
    terminal_bc = dict(zip(state_names, terminal_states))

    solinit.aux['initial'] = initial_bc
    solinit.aux['terminal'] = terminal_bc
    tic()
    # TODO: Start from specific step for restart capability
    # TODO: Make class to store result from continuation set?
    out = dict()

    out['problem_data'] = ocp_ws['problem_data']

    ocp._scaling.initialize(ocp_ws)
    ocp_ws['scaling'] = ocp._scaling

    out['solution'] = run_continuation_set(ocp_ws, bvp_algorithm, steps,
                                           solinit, bvp)
    total_time = toc()

    logging.info('Continuation process completed in %0.4f seconds.\n' %
                 total_time)
    bvp_algorithm.close()

    # Final time is appended as a parameter, so scale the output x variables to show the correct time
    for continuation_set in out['solution']:
        for sol in continuation_set:
            tf_ind = [
                i for i, s in enumerate(out['problem_data']
                                        ['dynamical_parameters'])
                if str(s) is 'tf'
            ][0]
            tf = sol.dynamical_parameters[tf_ind]
            sol.t = sol.t * tf

    # Save data
    # del out['problem_data']['s_list']
    del out['problem_data']['states']
    del out['problem_data']['costates']

    qvars = out['problem_data']['quantity_vars']
    qvars = {str(k): str(v) for k, v in qvars.items()}
    out['problem_data']['quantity_vars'] = qvars

    with open(output_file, 'wb') as outfile:
        pickle.dump(out, outfile)

    return out['solution'][-1][-1]
def solve(ocp, method, bvp_algorithm, steps, guess_generator, output_file='data.dill'):
    """
    Solves the OCP using specified method
    """

    # Initialize necessary conditions of optimality object
    # print("Computing the necessary conditions of optimality")
    logging.info("Computing the necessary conditions of optimality")
    from beluga.optimlib import methods

    # TODO: Load oc method by name
    wf = methods[method]
    # wf = brysonho.BrysonHo
    # workspace = brysonho.init_workspace(ocp)
    # ocp_ws = wf(workspace)
    ocp_ws = wf({'problem': ocp, 'guess': guess_generator})

    solinit = Solution()

    solinit.aux['const'] = dict((str(const.name),float(const.value))
                                for const in ocp_ws['constants'])
    solinit.aux['parameters'] = ocp_ws['problem_data']['parameter_list']

    # For path constraints
    solinit.aux['constraint'] = cl.defaultdict(float)
    solinit.aux['constraints'] = dict((s['name'], {'unit':str(s['unit']),
                                                   'expr':str(s['expr']),
                                                   'direction': s['direction'],
                                                   'arc_type': i,
                                                   'pi_list':[str(_) for _ in s['pi_list']]})
                                      for i, s in enumerate(ocp_ws['problem_data']['s_list'],1))
    solinit.aux['arc_seq'] = (0,)
    solinit.aux['pi_seq'] = (None,)
    bvp_fn = bvp_algorithm.preprocess(ocp_ws['problem_data'])
    # The initial guess is automatically stored in the bvp object
    # solinit is just a reference to it
    solinit = ocp_ws['guess'].generate(bvp_fn, solinit)

    # # includes costates
    state_names = ocp_ws['problem_data']['state_list']

    initial_states = solinit.y[:,0] # First column
    terminal_states = solinit.y[:,-1] # Last column
    initial_bc = dict(zip(state_names,initial_states))
    terminal_bc = dict(zip(state_names,terminal_states))

    solinit.aux['initial'] = initial_bc
    solinit.aux['terminal'] = terminal_bc
    solinit2= copy.deepcopy(solinit)
    tic()
    # TODO: Start from specific step for restart capability
    # TODO: Make class to store result from continuation set?
    out = {};

    out['problem_data'] = ocp_ws['problem_data'];

    ocp._scaling.initialize(ocp_ws)
    ocp_ws['scaling'] = ocp._scaling

    out['solution'] = run_continuation_set(ocp_ws, bvp_algorithm, steps, bvp_fn, solinit)
    total_time = toc()

    # tic()
    # out['solution'] = run_continuation_set(ocp_ws, bvp_algorithm, steps, bvp_fn, solinit2)
    # total_time = toc()

    logging.info('Continuation process completed in %0.4f seconds.\n' % total_time)
    bvp_algorithm.close()

    # Save data
    # del out['problem_data']['s_list']
    del out['problem_data']['states']
    del out['problem_data']['costates']

    qvars = out['problem_data']['quantity_vars']
    qvars = {str(k):str(v) for k,v in qvars.items()}
    out['problem_data']['quantity_vars'] = qvars
    with open(output_file, 'wb') as outfile:
        dill.settings['recurse'] = True
        dill.dump(out, outfile) # Dill Beluga object only
Пример #9
0
def solve(ocp, method, bvp_algorithm, steps, guess_generator, **kwargs):
    """
    Solves the OCP using specified method

    +------------------------+-----------------+-----------------+
    | Valid kwargs           | Default Value   | Valid Values    |
    +========================+=================+=================+
    | autoscale              | True            | bool            |
    +------------------------+-----------------+-----------------+
    | n_cpus                 | 1               | integer         |
    +------------------------+-----------------+-----------------+

    """

    autoscale = kwargs.get('autoscale', True)
    n_cpus = int(kwargs.get('n_cpus', 1))

    if n_cpus < 1:
        raise ValueError('Number of cpus must be greater than 1.')

    if n_cpus > 1:
        logging.debug('Starting processing pool with ' + str(n_cpus) +
                      'cpus... ')
        pool = pathos.multiprocessing.Pool(processes=n_cpus)
        logging.debug('Done.')
    else:
        pool = None

    output_file = config['output_file']
    logging.info("Computing the necessary conditions of optimality")

    if method.lower() == 'traditional' or method.lower() == 'brysonho':
        bvp_ws, guess_mapper = BH_ocp_to_bvp(ocp)
    elif method.lower() == 'icrm':
        bvp_ws, guess_mapper = ICRM_ocp_to_bvp(ocp)
    elif method.lower() == 'diffyg':
        bvp_ws, guess_mapper = DIFFYG_ocp_to_bvp(ocp)
    else:
        raise NotImplementedError

    logging.debug('Resulting BVP problem:')
    for key in bvp_ws.keys():
        logging.debug(str(key) + ': ' + str(bvp_ws[key]))

    bvp_ws['problem'] = ocp
    bvp_ws['guess'] = guess_generator
    bvp_ws['custom_functions'] = ocp.custom_functions()
    solinit = Solution()

    solinit.aux['const'] = OrderedDict(
        (const, val)
        for const, val in zip(bvp_ws['constants'], bvp_ws['constants_values']))
    for const in bvp_ws['constants']:
        if not str(const) in solinit.aux['const'].keys():
            solinit.aux['const'][str(const)] = 0

    solinit.aux['dynamical_parameters'] = bvp_ws['dynamical_parameters']
    solinit.aux['nondynamical_parameters'] = bvp_ws['nondynamical_parameters']

    bvp = preprocess(bvp_ws)
    solinit = bvp_ws['guess'].generate(bvp, solinit, guess_mapper)

    state_names = bvp_ws['states']

    initial_states = solinit.y[0, :]
    terminal_states = solinit.y[-1, :]

    initial_bc = dict(zip(state_names, initial_states))
    terminal_bc = dict(zip(state_names, terminal_states))

    for ii in initial_bc:
        if ii + '_0' in solinit.aux['const'].keys():
            solinit.aux['const'][ii + '_0'] = initial_bc[ii]

    for ii in terminal_bc:
        if ii + '_f' in solinit.aux['const'].keys():
            solinit.aux['const'][ii + '_f'] = terminal_bc[ii]

    quad_names = bvp_ws['quads']
    n_quads = len(quad_names)
    if n_quads > 0:
        initial_quads = solinit.q[0, :]
        terminal_quads = solinit.q[-1, :]
        initial_bc = dict(zip(quad_names, initial_quads))
        terminal_bc = dict(zip(quad_names, terminal_quads))

        for ii in initial_bc:
            if ii + '_0' in solinit.aux['const'].keys():
                solinit.aux['const'][ii + '_0'] = initial_bc[ii]

        for ii in terminal_bc:
            if ii + '_f' in solinit.aux['const'].keys():
                solinit.aux['const'][ii + '_f'] = terminal_bc[ii]

    time0 = time.time()
    out = dict()

    out['problem_data'] = bvp_ws
    ocp._scaling.initialize(bvp_ws)
    bvp_ws['scaling'] = ocp._scaling

    out['solution'] = run_continuation_set(bvp_ws, bvp_algorithm, steps,
                                           solinit, bvp, pool, autoscale)
    total_time = time.time() - time0

    logging.info('Continuation process completed in %0.4f seconds.\n' %
                 total_time)
    bvp_algorithm.close()

    # Final time is appended as a parameter, so scale the output x variables to show the correct time
    for continuation_set in out['solution']:
        for sol in continuation_set:
            tf_ind = [
                i for i, s in enumerate(out['problem_data']
                                        ['dynamical_parameters'])
                if str(s) is 'tf'
            ][0]
            tf = sol.dynamical_parameters[tf_ind]
            sol.t = sol.t * tf

    if pool is not None:
        pool.close()

    # Save data
    with open(output_file, 'wb') as outfile:
        pickle.dump(out, outfile)

    return out['solution'][-1][-1]