8000 Python: Cleanup code generation, sim solver by sandmaennchen · Pull Request #1397 · acados/acados · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Python: Cleanup code generation, sim solver #1397

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions interfaces/acados_template/acados_template/acados_ocp_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def shared_lib(self,):
"""`shared_lib` - solver shared library"""
return self.__shared_lib

# TODO move this to AcadosOcp
@classmethod
def generate(cls, acados_ocp: Union[AcadosOcp, AcadosMultiphaseOcp], json_file: str, simulink_opts=None, cmake_builder: CMakeBuilder = None):
"""
Expand Down Expand Up @@ -1979,16 +1980,18 @@ def options_set(self, field_, value_):
"""
Set options of the solver.

:param field: string, e.g. 'print_level', 'rti_phase', 'globalization_fixed_step_length', 'globalization_alpha_min', 'globalization_alpha_reduction',
'qp_warm_start', 'globalization_line_search_use_sufficient_descent',
'globalization_full_step_dual', 'globalization_use_SOC', 'qp_tol_stat',
'qp_tol_eq', 'qp_tol_ineq', 'qp_tol_comp', 'qp_tau_min',
'qp_mu0', 'qp_print_level', 'globalization_funnel_init_increase_factor',
'globalization_funnel_init_upper_bound', 'globalization_funnel_sufficient_decrease_factor',
'globalization_funnel_kappa', 'globalization_funnel_fraction_switching_condition',
'globalization_funnel_initial_penalty_parameter', 'levenberg_marquardt',
'adaptive_levenberg_marquardt_lam', 'adaptive_levenberg_marquardt_mu_min',
'adaptive_levenberg_marquardt_mu0',
:param field: string, possible values are:
'print_level', 'rti_phase', 'nlp_solver_max_iter, 'as_rti_level',
'tol_eq', 'tol_stat', 'tol_ineq', 'tol_comp',
'qp_tol_stat', 'qp_tol_eq', 'qp_tol_ineq', 'qp_tol_comp', 'qp_tau_min',
'qp_warm_start', 'qp_mu0', 'qp_print_level', 'warm_start_first_qp',
'globalization_fixed_step_length' 8000 ;, 'globalization_alpha_min', 'globalization_alpha_reduction',
'globalization_line_search_use_sufficient_descent', 'globalization_full_step_dual', 'globalization_use_SOC',
'globalization_funnel_init_upper_bound', 'globalization_funnel_sufficient_decrease_factor',
'globalization_funnel_kappa', 'globalization_funnel_fraction_switching_condition',
'globalization_funnel_initial_penalty_parameter', 'globalization_funnel_init_increase_factor',
'levenberg_marquardt',
'adaptive_levenberg_marquardt_lam', 'adaptive_levenberg_marquardt_mu_min', 'adaptive_levenberg_marquardt_mu0',

:param value: of type int, float, string, bool

Expand All @@ -2009,6 +2012,7 @@ def options_set(self, field_, value_):
'warm_start_first_qp',
'as_rti_level',
'max_iter',
'nlp_solver_max_iter',
'qp_warm_start',
'qp_print_level']
double_fields = ['globalization_fixed_step_length',
Expand Down Expand Up @@ -2065,7 +2069,7 @@ def options_set(self, field_, value_):
f' Possible values are {fields}.')


if field_ == 'max_iter' and value_ > self.__solver_options['nlp_solver_max_iter']:
if (field_ == 'max_iter' or field_ == 'nlp_solver_max_iter') and value_ > self.__solver_options['nlp_solver_max_iter']:
raise Exception('AcadosOcpSolver.options_set() cannot increase nlp_solver_max_iter' \
f' above initial value {self.__nlp_solver_max_iter} (you have {value_})')
return
Expand Down
99 changes: 92 additions & 7 deletions interfaces/acados_template/acados_template/acados_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,19 @@
# POSSIBILITY OF SUCH DAMAGE.;
#

import os
import os, json
import numpy as np
from copy import deepcopy
from .acados_model import AcadosModel
from .acados_dims import AcadosSimDims
from .utils import get_acados_path, get_shared_lib_ext
from .builders import CMakeBuilder
from .utils import (get_acados_path, get_shared_lib_ext, format_class_dict, check_casadi_version,
make_object_json_dumpable, render_template)
from .casadi_function_generation import (
GenerateContext,
generate_c_code_explicit_ode,
generate_c_code_gnsf,
generate_c_code_implicit_ode)

class AcadosSimOptions:
"""
Expand Down Expand Up @@ -313,14 +321,91 @@ def parameter_values(self, parameter_values):
f'Expected numpy array, got {type(parameter_values)}.')

def make_consistent(self):
dims = self.dims
model = self.model
model.make_consistent(dims)
self.model.make_consistent(self.dims)

if self.parameter_values.shape[0] != dims.np:
if self.parameter_values.shape[0] != self.dims.np:
raise Exception('inconsistent dimension np, regarding model.p and parameter_values.' + \
f'\nGot np = {dims.np}, acados_sim.parameter_values.shape = {self.parameter_values.shape[0]}\n')
f'\nGot np = {self.dims.np}, acados_sim.parameter_values.shape = {self.parameter_values.shape[0]}\n')

# check required arguments are given
if self.solver_options.T is None:
raise Exception('acados_sim.solver_options.T is None, should be provided.')


def to_dict(self) -> dict:
# Copy input sim object dictionary
sim_dict = dict(deepcopy(self).__dict__)

# convert acados classes to dicts
for key, v in sim_dict.items():
# skip non dict attributes
if isinstance(v, (AcadosSim, AcadosSimDims, AcadosSimOptions, AcadosModel)):
sim_dict[key]=dict(getattr(self, key).__dict__)

return format_class_dict(sim_dict)


def dump_to_json(self, json_file='acados_sim.json') -> None:
with open(json_file, 'w') as f:
json.dump(self.to_dict(), f, default=make_object_json_dumpable, indent=4, sort_keys=True)


def render_templates(self, json_file, cmake_options: CMakeBuilder = None):
# setting up loader and environment
json_path = os.path.join(os.getcwd(), json_file)

if not os.path.exists(json_path):
raise Exception(f"{json_path} not found!")

template_list = [
('acados_sim_solver.in.c', f'acados_sim_solver_{self.model.name}.c'),
('acados_sim_solver.in.h', f'acados_sim_solver_{self.model.name}.h'),
('acados_sim_solver.in.pxd', 'acados_sim_solver.pxd'),
('main_sim.in.c', f'main_sim_{self.model.name}.c'),
]

# Builder
if cmake_options is not None:
template_list.append(('CMakeLists.in.txt', 'CMakeLists.txt'))
else:
template_list.append(('Makefile.in', 'Makefile'))

# Render templates
for (in_file, out_file) in template_list:
render_template(in_file, out_file, self.code_export_directory, json_path)

# folder model
model_dir = os.path.join(self.code_export_directory, self.model.name + '_model')

in_file = 'model.in.h'
out_file = f'{self.model.name}_model.h'
render_template(in_file, out_file, model_dir, json_path)


def generate_external_functions(self, ):

integrator_type = self.solver_options.integrator_type

opts = dict(generate_hess = self.solver_options.sens_hess,
code_export_directory = self.code_export_directory)

# create code_export_dir, model_dir
code_export_dir = self.code_export_directory
opts['code_export_directory'] = code_export_dir
model_dir = os.path.join(code_export_dir, self.model.name + '_model')
if not os.path.exists(model_dir):
os.makedirs(model_dir)

context = GenerateContext(self.model.p_global, self.model.name, opts)

# generate external functions
check_casadi_version()
if integrator_type == 'ERK':
generate_c_code_explicit_ode(context, self.model, model_dir)
elif integrator_type == 'IRK':
generate_c_code_implicit_ode(context, self.model, model_dir)
elif integrator_type == 'GNSF':
generate_c_code_gnsf(context, self.model, model_dir)

context.finalize()
self.__external_function_files_model = context.get_external_function_file_list(ocp_specific=False)
Loading
Loading
0