Repository: OpenMDAO/OpenMDAO

Issue:
Case._get_units method unable to get units for some variables.
### Description

In some cases the Case._get_units method cannot find the units for variable and raises an exception. But information about the units can be found in `case_recorder.problem_metadata['variables'][name]['units']
`.  It is just not being used. 


### Example

This script shows how the units for a variable can be gotten from the problem_metadata and also how the _get_units method fails to get it. This script works with the attached file. Just need to unzip the attachment.

```
from openmdao.recorders.sqlite_reader import SqliteCaseReader
cr = SqliteCaseReader('driver_history.sql')
case = cr.get_case(0)

name = 'traj.phases.accel->final_boundary_constraint->EAS'

units_from_problem_metadata = cr.problem_metadata['variables'][name]['units']
print(f"{units_from_problem_metadata=}")

units = case._get_units(name)
```








### OpenMDAO Version

3.36.1-dev

### Relevant environment information

_No response_

Hints from issue comments:
@hschilling: Here is the attachment

[driver_history.sql.zip](https://github.com/user-attachments/files/18912711/driver_history.sql.zip)

Solution patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 87bc0a162..f2b2add8e 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 3.36.1-dev
+current_version = 3.37.1-dev
 commit = False
 tag = False
 parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index c8417da91..8135ef0f8 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -23,7 +23,7 @@ body:
     attributes:
       label: OpenMDAO Version
       description: What version of OpenMDAO is being used.
-      placeholder: "3.36.1-dev"
+      placeholder: "3.37.1-dev"
     validations:
       required: true
   - type: textarea
diff --git a/openmdao/__init__.py b/openmdao/__init__.py
index 3478abaab..1023ddbf2 100644
--- a/openmdao/__init__.py
+++ b/openmdao/__init__.py
@@ -1,3 +1,3 @@
-__version__ = '3.36.1-dev'
+__version__ = '3.37.1-dev'
 
 INF_BOUND = 1.0E30
diff --git a/openmdao/recorders/case.py b/openmdao/recorders/case.py
index 42b1adcdb..b45ca5152 100644
--- a/openmdao/recorders/case.py
+++ b/openmdao/recorders/case.py
@@ -309,6 +309,10 @@ class Case(object):
             abs_name = prom2abs['input'][name][0]
             return meta[self._conns[abs_name]]['units']
 
+        elif name in self._var_info:
+            # This can happen if name is an alias.
+            return self._var_info[name]['units']
+
         raise KeyError('Variable name "{}" not found.'.format(name))
 
     def get_design_vars(self, scaled=True, use_indices=True):
diff --git a/release_notes.md b/release_notes.md
index 17e79c2ea..45af6e39a 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -1,3 +1,49 @@
+***********************************
+# Release Notes for OpenMDAO 3.37.0
+
+Feb 21, 2025
+
+OpenMDAO 3.37.0 introduces a new AnalysisDriver, which is intended to eventually replace DOEDriver, but allow for users to more easily specify what variables they wish to change when evaluating a model.
+See the documentation for more explanation of how to use it.
+
+In JaxExplicitComponent and JaxImplicitComponent, the user now has the ability to specify the name of the argument corresponding to the OpenMDAO input name using the `primal_name` option.  This is necessary in cases where the OpenMDAO input/output name is not a legal Python variable name.
+
+When using JaxExplicitComponent, users no longer are required to explicitly declare the partials.
+The component will determine the appropriate derivatives itself. In addition, `declare_coloring`
+can now be used in JaxExplicitComponent to compute the derivatives more quickly. Note that this
+feature is still in development and may not give a significant improvement over uncolored derivative calculation.
+
+From a performance perspective, an unnecessary nonlinear solve was removed when performing a hot start.
+
+## New Features
+
+- Added AnalysisDriver [#3365](https://github.com/OpenMDAO/OpenMDAO/pull/3365)
+- Added `is_undefined` function for MPI-safe and array-compatible checks. [#3423](https://github.com/OpenMDAO/OpenMDAO/pull/3423)
+- Updated check_partials and check_totals to measure absolute and relative err in the same way that np.assert_allclose does [#3442](https://github.com/OpenMDAO/OpenMDAO/pull/3442)
+- Make printout of sparsity summary subject to the 'show_summary' flag. [#3427](https://github.com/OpenMDAO/OpenMDAO/pull/3427)
+- Implemented automatic sparsity detection and coloring for Jax explicit components [#3451](https://github.com/OpenMDAO/OpenMDAO/pull/3451)
+- Added a smooth_round function to om.jax [#3457](https://github.com/OpenMDAO/OpenMDAO/pull/3457)
+
+## Bug Fixes
+
+- Fixed an issue with the dependency check for parallel derivative coloring [#3419](https://github.com/OpenMDAO/OpenMDAO/pull/3419)
+- Modified assert_check_partials to use numpy.assert_allclose [#3424](https://github.com/OpenMDAO/OpenMDAO/pull/3424)
+- Fixed a NumPy 2.x compatibility issue in FiniteDifference [#3429](https://github.com/OpenMDAO/OpenMDAO/pull/3429)
+- Addressed change in `numpy.testing.allclose` error message in NumPy 2.x [#3438](https://github.com/OpenMDAO/OpenMDAO/pull/3438)
+- Fix for computed sparsity when some subjacs are zero. [#3430](https://github.com/OpenMDAO/OpenMDAO/pull/3430)
+- Removed unnecessary NL solve when performing a hot start. [#3432](https://github.com/OpenMDAO/OpenMDAO/pull/3432)
+- Added name mapping from component names to valid python names for use in compute_primal method [#3444](https://github.com/OpenMDAO/OpenMDAO/pull/3444)
+- _CheckingJacobian no longer raises if the sparsity pattern is bad [#3450](https://github.com/OpenMDAO/OpenMDAO/pull/3450)
+- Updated the list of disallowed variable names for ExecComp [#3456](https://github.com/OpenMDAO/OpenMDAO/pull/3456)
+- Fix bug in list_driver_vars where the bounds are wrong if it is called twice with driver_scaling=False. [#3461](https://github.com/OpenMDAO/OpenMDAO/pull/3461)
+
+## Miscellaneous
+
+- Updated Ubuntu images used by GitHub test workflows [#3425](https://github.com/OpenMDAO/OpenMDAO/pull/3425)
+- Updated latest GitHub workflow to use a known working version of PETSc [#3446](https://github.com/OpenMDAO/OpenMDAO/pull/3446)
+- Added an image definition and GitHub workflow to publish an image [#3454](https://github.com/OpenMDAO/OpenMDAO/pull/3454)
+
+
 ***********************************
 # Release Notes for OpenMDAO 3.36.0
 
@@ -15,7 +61,7 @@ OpenMDAO now provides a dashboard utility for examining the contents of recordin
 In another significant change, AutoIVC outputs can now be recorded more easily. Recording items by the promoted name
 will always record the _output_, while specifying an input by absolute name will result in it being recorded as an input.
 Since OpenMDAO no longer has "dangling" inputs, recording by absolute name is only really necessary when debugging the
-input values as seen by a component. 
+input values as seen by a component.
 
 ## New Features
 


Test patch:
diff --git a/openmdao/recorders/tests/test_sqlite_reader.py b/openmdao/recorders/tests/test_sqlite_reader.py
index 8386dee20..3a06beeac 100644
--- a/openmdao/recorders/tests/test_sqlite_reader.py
+++ b/openmdao/recorders/tests/test_sqlite_reader.py
@@ -2831,6 +2831,34 @@ class TestSqliteCaseReader(unittest.TestCase):
         for i, line in enumerate(expected_cases):
             self.assertEqual(text[i], line)
 
+    def test_alias_units(self):
+        prob = SellarProblem()
+
+        if prob.model._static_mode and prob.model._static_responses:
+            responses = prob.model._static_responses
+        else:
+            responses = prob.model._responses
+        
+        responses.clear()
+
+        prob.model.add_objective('obj', alias='objective_alias')
+        prob.setup()
+
+        prob.add_recorder(self.recorder)
+        prob.driver.add_recorder(self.recorder)
+
+        prob.run_driver()
+
+        prob.cleanup()   
+
+        cr = om.CaseReader(prob.get_outputs_dir() / self.filename)     
+        cr.list_cases()
+        c = cr.get_case(0)
+        
+        units = c._get_units('obj')
+        units_alias = c._get_units('objective_alias')
+        self.assertEqual(units, units_alias)
+
     def test_list_sources_format(self):
         prob = SellarProblem()
         prob.setup()