def run_model(self, dt=1., t_end=1000., t_spinup=48.): """ Run the current model with a simple Euler marching algorithm Parameters ---------- dt : float Timestep, in hours t_end : float Cut-off time in hours to end integration/marching t_spinup : float Time in hours after which productivity will be scaled by daily averages of nutrient availability Returns ------- result : DataFrame A DataFrame with the columns V, S, N, O corresponding to the components of the model state vector, indexed along time in hours. S, N, O are in kg/m3 and mmol/m3, and V is % of initial volume """ # Initialize output as an array out_y = vstack([self.y0, ]) ts = [0., ] # Main integration loop i, t = 1, 0. while t < t_end: # Pop last state off of stack y = out_y[-1].T # If we're past spin-up, then average the N concentration over # the last 24 hours to scale productivity if t > t_spinup: n_24hrs = int(ceil(24./dt)) P_scale = \ mean(out_y[-n_24hrs:, 2]/out_y[-n_24hrs:, 0])/self.N_ocean else: P_scale = 1. # Euler step t += dt new_y = y + dt*self.estuary_ode(y, t, P_scale) # Correct non-physical V, S, N, or O (where they're < 0) new_y[new_y < 0] = 0. # Save output onto stack out_y = vstack([out_y, new_y]) ts.append(t) i += 1 # Shape output into DataFrame out = out_y[:] ts = array(ts) result = DataFrame(data=out, columns=['V', 'S', 'N', 'O'], dtype=float, index=Index(ts, name='time')) # Convert to molar concentrations result.S /= result.V result.N /= result.V result.O /= result.V # Add tidal height (meters) to output result['Z'] = result.V/self.estuary_area # Convert volume to percentage relative to initial result.V = 100*(result.V - self.V)/self.V return result