← Back to Analysis1 documentation
Analysis1 - Source Code¶
File: userfiles/NewUseCase_Template/subsystem1/Analysis1.py
# Copyright (C) The DistributedDesignOptimizer Contributors
# Licensed under the GNU General Public License v3.0. See LICENSE file for details.
"""Analysis module for Subsystem 1 in the new use-case.
This module defines the Analysis1 class which implements the physics-based
analysis computations and response mapping for Subsystem 1 in the distributed
design optimization framework.
"""
from typing import List
from Distributed_Design_Optimizer.subsystem.optimization import AnalysisInterface
from Distributed_Design_Optimizer.subsystem import LocalSubSystemBasis
from Distributed_Design_Optimizer.subsystem.tools import ScalerBasis
class Analysis1(AnalysisInterface):
"""Analysis class for Subsystem 1 in the new use-case."""
def __init__(self) -> None:
"""Initialize the Analysis1 instance."""
pass
def evaluateLocalResponses(self, subsystem: LocalSubSystemBasis) -> None:
"""Evaluate the physical responses of Subsystem 1.
Computes the subsystem responses based on the current design variables.
The responses include geometric programming formulas involving powers,
inverse powers, and square root operations.
Args:
subsystem: The LocalSubSystemBasis instance containing design variables
and where computed responses will be stored.
"""
des_var: List[float] = subsystem.get_DesignVariables_Unscaled() # unscaled values
# load copymappedresponsevariables from other neighborhing subsystmes which may be necessary for this analysis
# scalers: List[ScalerBasis] = subsystem.get_Scalers()
# copymappedresponsevariables_neighbor_id_scaled01: List[float] | None = subsystem.get_Copy_MappedResponseVariables(id=neighbor_id) # scaled01 values
# # to unscale, run
# copymappedresponsevariables_neighbor_id = scalers[corresponding_index].inverse_transform(copymappedresponsevariables_neighbor_id_scaled01) # unscaled value
# Compute responses using des_var and copymappedresponsevariables
################################################################
### USER CODE: Compute responses ###
################################################################
responses = [... ,
... ,
]
# responses is a unscaled quantity
################################################################
### END USER CODE ###
################################################################
subsystem.set_Responses_Unscaled(responses)
def mapLocalResponsesDesignVariables_to_CouplingParameters(self, subsystem: LocalSubSystemBasis) -> None:
"""Map responses and design variables for inter-subsystem coupling.
Maps computed responses and shared/target design variables to neighboring
subsystems.
Args:
subsystem: The LocalSubSystemBasis instance containing responses
and design variables to be mapped.
"""
responses: List[float] = subsystem.get_Responses_Unscaled() # unscaled values
scalers: List[ScalerBasis] = subsystem.get_Scalers()
des_var: List[float] = subsystem.get_DesignVariables() # scaled01 values
des_var_unscaled: List[float] = subsystem.get_DesignVariables_Unscaled() # unscaled values
# map responses and shared/target design variables
################################################################
### USER CODE: Map to coupling parameters ###
################################################################
# only map scaled01 quantities!
# subsystem.set_MappedResponseVariables(id=,
# mappedresponsesin=,
# mappedresponsesin_unscaled=)
# subsystem.set_MappedResponseVariables(id=,
# mappedresponsesin=,
# mappedresponsesin_unscaled=)
# subsystem.set_CouplingVariables(id=,
# couplingvariablein=,
# couplingvariablein_unscaled=)
# subsystem.set_CouplingVariables(id=,
# couplingvariablein=,
# couplingvariablein_unscaled=)
# subsystem.set_TargetSharedDesignVariables(id=,
# targetdesignvariablesin=,
# targetdesignvariablesin_unscaled=)
# subsystem.set_TargetSharedDesignVariables(id=,
# targetdesignvariablesin=,
# targetdesignvariablesin_unscaled=)
# subsystem.set_SharedDesignVariables(id=,
# shareddesignvariablesin=,
# shareddesignvaraiblesin_unscaled)
# subsystem.set_SharedDesignVariables(id=,
# shareddesignvariablesin=,
# shareddesignvaraiblesin_unscaled)
################################################################
### END USER CODE ###
################################################################
return
def mapLocalResponsesDesignVariables_to_CouplingParameters_Jacobians(self, subsystem: LocalSubSystemBasis) -> None:
"""Map the Jacobians of the mapped responses.
Args:
subsystem: The subsystem for which the Jacobians are mapped.
"""
# === Tutorial: scaled <-> unscaled mapped-response Jacobian (chain rule) ====
# The mapped response is passed to the neighbor in SCALED [0, 1] space, and
# the design variables are scaled too, so the Jacobian row stored here must be
# d(scaled mapped response) / d(scaled design variables). Every affine scaler
# has a constant slope get_scale() = d(scaled)/d(unscaled). From the UNSCALED
# partials dH/dx_u[j] convert component-wise:
# dH_s/ds_j = get_scale(mapped) * dH/dx_u[j] / get_scale(dv_scaler_j)
# This method uses a SETTER (set_MappedResponses_Jacobian) and returns None.
# ===========================================================================
responses: List[float] = subsystem.get_Responses_Unscaled()
scalers: List[ScalerBasis] = subsystem.get_Scalers()
des_var: List[float] = subsystem.get_DesignVariables()
################################################################
### USER CODE: Compute Jacobians ###
################################################################
# If the mapped responses have no closed-form Jacobian (e.g. they come
# from a complex/physics-based analysis), return None so the framework
# falls back to its internal finite-difference computation. For
# consistency with use-cases that do call the setter, you may instead
# pass an all-None matrix of the correct shape
# (number_of_mapped_responses, number_of_design_variables) per neighbor:
#
# n_dv: int = len(des_var)
# subsystem.set_MappedResponses_Jacobian(
# id="<neighbor_id>",
# mappedresponses_jacobian_in=[[None] * n_dv
# for _ in range(number_of_mapped_responses)])
return None
################################################################
### END USER CODE ###
################################################################
def mapLocalResponsesDesignVariables_to_CouplingParameters_Hessian(self, subsystem: LocalSubSystemBasis) -> None:
"""Map the Hessians of the mapped responses, if known a priori.
Args:
subsystem: The subsystem for which the Hessians are mapped.
"""
# === Tutorial: scaled <-> unscaled mapped-response Hessian (2nd order) ======
# The mapped response is exchanged in SCALED [0, 1] space, so its Hessian
# must be d^2(scaled mapped response) / d(scaled design vars)^2. Each affine
# scaler has a constant slope get_scale() = d(scaled)/d(unscaled); from the
# UNSCALED second derivatives d^2H/dx_j dx_k convert element-wise:
# d2H_s/ds_j ds_k = get_scale(mapped) * d2H/dx_j dx_k
# / (get_scale(x_j) * get_scale(x_k))
# This method RETURNS the tensor [coupling][response][n_dv][n_dv], or None.
# ===========================================================================
################################################################
### USER CODE: Compute Hessians ###
################################################################
# No closed-form Hessian available; return None to let the framework
# fall back to its internal finite-difference computation.
return None
################################################################
### END USER CODE ###
################################################################