From be59c21185c0fcd80d53f9443b207012458d87fe Mon Sep 17 00:00:00 2001 From: acrovato <a.crovato@uliege.be> Date: Fri, 4 Oct 2024 11:51:38 +0200 Subject: [PATCH] Add partials to API. Fix bug in row assignement for multibody. --- sdpm/api/core.py | 14 ++++++------- sdpm/api/om.py | 36 ++++++++++++++++++++------------ sdpm/src/sdpmGradient.cpp | 3 ++- sdpm/src/sdpmSolverTransonic.cpp | 3 ++- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/sdpm/api/core.py b/sdpm/api/core.py index 10a355e..de386ad 100644 --- a/sdpm/api/core.py +++ b/sdpm/api/core.py @@ -17,15 +17,13 @@ ## Initialize SDPM # Adrien Crovato -def init_sdpm(cfg, use_ad=False): +def init_sdpm(cfg): """Initialize SDPM components Parameters ---------- cfg : dict Dictionary of parameters to configure SDPM - use_ad : bool, optional - Whether to use AD within SDPM (default: False) Returns ------- @@ -44,8 +42,8 @@ def init_sdpm(cfg, use_ad=False): Lifting body sol : sdpm.Solver object Direct solver - adj : sdpm.Adjoint object - Adjoint solver + grd : sdpm.Gradient object + Gradient calculator """ # Imports import sdpm @@ -87,7 +85,9 @@ def init_sdpm(cfg, use_ad=False): # Solver vrb = cfg.get('Verb_lvl', 1) _sol = sdpm.Solver(_pbl, vrb) if 'Transonic_pressure_grad' not in cfg else sdpm.SolverTransonic(_pbl, vrb) - _adj = sdpm.Adjoint(_sol) if use_ad else None + + # Gradient + _grd = sdpm.Gradient(_sol) # Return return { @@ -98,5 +98,5 @@ def init_sdpm(cfg, use_ad=False): 'pbl': _pbl, 'bdy': _bdy, 'sol': _sol, - 'adj': _adj + 'grd': _grd } diff --git a/sdpm/api/om.py b/sdpm/api/om.py index 9fe3a5c..d5edd72 100644 --- a/sdpm/api/om.py +++ b/sdpm/api/om.py @@ -50,20 +50,20 @@ class SdpmSolver(om.ExplicitComponent): self.options.declare('nm', desc='number of modes') self.options.declare('bdy', desc='lifting body', recordable=False) self.options.declare('sol', desc='direct solver', recordable=False) - self.options.declare('adj', desc='adjoint solver', recordable=False) + self.options.declare('grd', desc='gradient calculator', recordable=False) def setup(self): self.nf = self.options['nf'] self.nm = self.options['nm'] self.bdy = self.options['bdy'] self.sol = self.options['sol'] - self.adj = self.options['adj'] + self.grd = self.options['grd'] self.add_input('x_aero0', shape_by_conn=True, desc='aerodynamic surface node coordinates') self.add_input('q_aero', shape_by_conn=True, desc='modal displacements') self.add_output('Q_re', val=np.ones((self.nf, self.nm, self.nm)), desc='real part of generalized aerodynamic forces matrices') self.add_output('Q_im', val=np.ones((self.nf, self.nm, self.nm)), desc='imag part of generalized aerodynamic forces matrices') # Partials - # self.declare_partials(of=['Q_re', 'Q_im'], wrt=['x_aero', 'q_aero'], method='exact') + self.declare_partials(of=['Q_re', 'Q_im'], wrt=['q_aero'], method='exact') def compute(self, inputs, outputs): # Update coordinates @@ -75,16 +75,28 @@ class SdpmSolver(om.ExplicitComponent): x_modes[j, :] = inputs['q_aero'][3*j:3*j+3, i].T self.bdy.setFlexibleMotion(i, 1, x_modes) # Compute - if self.adj is None: - self.sol.update() - self.sol.run() - else: - self.adj.solve() + self.sol.update() + self.sol.run() # Set outputs for i in range(self.nf): outputs['Q_re'][i, :, :] = np.array(self.sol.getGafMatrixRe(i), dtype=float) outputs['Q_im'][i, :, :] = np.array(self.sol.getGafMatrixIm(i), dtype=float) + def compute_partials(self, inputs, partials): + # Compute gradients and set partials + self.grd.run() + for ifrq in range(self.nf): + for imod in range(self.nm): + for jmod in range(self.nm): + dq_re = np.zeros((inputs['q_aero'].shape[0], self.nm)) + dq_im = np.zeros((inputs['q_aero'].shape[0], self.nm)) + for kmod in range(self.nm): + for idof, dof in enumerate(['dz', 'rx', 'ry']): + dq_re[idof::3, kmod] = np.array(self.grd.computePartialsGafRe(ifrq, kmod, imod, jmod, dof), dtype=float) + dq_im[idof::3, kmod] = np.array(self.grd.computePartialsGafIm(ifrq, kmod, imod, jmod, dof), dtype=float) + partials['Q_re', 'q_aero'][ifrq * self.nm * self.nm + imod * self.nm + jmod, :] = dq_re.flatten() + partials['Q_im', 'q_aero'][ifrq * self.nm * self.nm + imod * self.nm + jmod, :] = dq_im.flatten() + class SdpmBuilder(Builder): """SDPM builder for OpenMDAO @@ -99,18 +111,16 @@ class SdpmBuilder(Builder): 'sol': direct solver 'adj': adjoint sovler """ - def __init__(self, cfg, use_ad=False): + def __init__(self, cfg): """Instantiate and initialize SDPM components Parameters ---------- cfg : dict Dictionary of parameters to configure SDPM - use_ad : bool, optional - Whether to use AD within SDPM (default: False) """ from .core import init_sdpm - self.__sdpm = init_sdpm(cfg, use_ad) + self.__sdpm = init_sdpm(cfg) def get_mesh(self): """Return OpenMDAO component to get the initial surface mesh coordinates @@ -120,7 +130,7 @@ class SdpmBuilder(Builder): def get_solver(self, scenario_name=''): """Return OpenMDAO component containing the solver """ - return SdpmSolver(nf=self.__sdpm['n_f'], nm=self.__sdpm['n_m'], bdy=self.__sdpm['bdy'], sol=self.__sdpm['sol'], adj=self.__sdpm['adj']) + return SdpmSolver(nf=self.__sdpm['n_f'], nm=self.__sdpm['n_m'], bdy=self.__sdpm['bdy'], sol=self.__sdpm['sol'], grd=self.__sdpm['grd']) def get_number_of_nodes(self): """Return the number of surface nodes diff --git a/sdpm/src/sdpmGradient.cpp b/sdpm/src/sdpmGradient.cpp index 1603da9..5af4c58 100644 --- a/sdpm/src/sdpmGradient.cpp +++ b/sdpm/src/sdpmGradient.cpp @@ -30,7 +30,8 @@ Gradient::Gradient(Solver &sol) : _sol(sol), int inod = 0; for (auto body : _sol._pbl.getBodies()) for (auto n : body->getNodes()) - _rowsN.insert(std::pair<Node *, int>(n, inod++)); + if (_rowsN.insert(std::pair<Node *, int>(n, inod)).second == true) + ++inod; _nN = _rowsN.size(); // Resize displacement and load containers diff --git a/sdpm/src/sdpmSolverTransonic.cpp b/sdpm/src/sdpmSolverTransonic.cpp index 8783512..6033212 100644 --- a/sdpm/src/sdpmSolverTransonic.cpp +++ b/sdpm/src/sdpmSolverTransonic.cpp @@ -28,7 +28,8 @@ SolverTransonic::SolverTransonic(Problem &pbl, int vrb) : Solver(pbl, vrb), _dCo int i = 0; for (auto body : _pbl.getBodies()) for (auto n : body->getNodes()) - _rowsN.insert(std::pair<Node *, int>(n, i++)); + if (_rowsN.insert(std::pair<Node *, int>(n, i)).second == true) + ++i; } /** -- GitLab