Repository: climlab/climlab

Issue:
Diagnostics failure for a simple EBM
This minimal zero-dimensional EBM configuration is currently failing:

```
import climlab
state = climlab.surface_state(num_lat=1)
olr = climlab.radiation.Boltzmann(state=state, name='OutgoingLongwave')
asr = climlab.radiation.SimpleAbsorbedShortwave(state=state, name='AbsorbedShortwave')
ebm = climlab.couple([olr,asr], name='EBM')

ebm.step_forward()
```

fails with
```
AttributeError: 'float' object has no attribute 'shape'
```

Full traceback:
```
AttributeError                            Traceback (most recent call last)
Cell In[16], line 1
----> 1 ebm.step_forward()

File ~/miniconda3/envs/new-climlab-courseware/lib/python3.13/site-packages/climlab/process/time_dependent_process.py:342, in TimeDependentProcess.step_forward(self)
    316 def step_forward(self):
    317     """Updates state variables with computed tendencies.
    318
    319     Calls the :func:`compute` method to get current tendencies for all
   (...)
    340
    341     """
--> 342     tenddict = self.compute()
    343     #  Total tendency is applied as an explicit forward timestep
    344     # (already accounting properly for order of operations in compute() )
    345     for varname, tend in tenddict.items():

File ~/miniconda3/envs/new-climlab-courseware/lib/python3.13/site-packages/climlab/process/time_dependent_process.py:249, in TimeDependentProcess.compute(self)
    247 for procname, proc in self.subprocess.items():
    248     for diagname, value in proc.diagnostics.items():
--> 249         if self.__dict__[diagname].shape == value.shape:
    250             self.__dict__[diagname] += value
    251 return self.tendencies

AttributeError: 'float' object has no attribute 'shape'
```

Discussion:

Patch:
diff --git a/climlab/radiation/absorbed_shorwave.py b/climlab/radiation/absorbed_shorwave.py
index c7930a0..1ec249a 100644
--- a/climlab/radiation/absorbed_shorwave.py
+++ b/climlab/radiation/absorbed_shorwave.py
@@ -29,5 +29,5 @@ class SimpleAbsorbedShortwave(EnergyBudget):
         self.topdown = False  # call subprocess compute methods first
 
     def _compute_heating_rates(self):
-        self.ASR = (1-self.albedo) * self.insolation
+        self.ASR[:] = (1-self.albedo) * self.insolation
         self.heating_rate['Ts'] = self.ASR


Test patch:
diff --git a/climlab/tests/test_ebm.py b/climlab/tests/test_ebm.py
index 78f9f4c..0413a50 100644
--- a/climlab/tests/test_ebm.py
+++ b/climlab/tests/test_ebm.py
@@ -23,6 +23,14 @@ def _check_minmax(array, amin, amax):
     return (np.allclose(array.min(), amin) and
             np.allclose(array.max(), amax))
 
+def test_homemade_ebm():
+    """Create the simplest zero-dimensional EBM from components and step forward."""
+    state = climlab.surface_state(num_lat=1)
+    olr = climlab.radiation.Boltzmann(state=state, name='OutgoingLongwave')
+    asr = climlab.radiation.SimpleAbsorbedShortwave(state=state, name='AbsorbedShortwave')
+    ebm = climlab.couple([olr,asr], name='EBM')
+    ebm.step_forward()
+
 @pytest.mark.fast
 def test_model_creation(EBM_seasonal):
     """Just make sure we can create a model."""