code: def d2logpdf_df2_dtheta(self, f, y, Y_metadata=None):
          
          if self.size > 0:
              if self.not_block_really:
                  raise NotImplementedError("Need to make a decorator for this!")
              if isinstance(self.gp_link, link_functions.Identity):
                  return self.d2logpdf_dlink2_dtheta(f, y, Y_metadata=Y_metadata)
              else:
                  inv_link_f = self.gp_link.transf(f)
                  dlink_df = self.gp_link.dtransf_df(f)
                  d2link_df2 = self.gp_link.d2transf_df2(f)
                  d2logpdf_dlink2_dtheta = self.d2logpdf_dlink2_dtheta(inv_link_f, y, Y_metadata=Y_metadata)
                  dlogpdf_dlink_dtheta = self.dlogpdf_dlink_dtheta(inv_link_f, y, Y_metadata=Y_metadata)
  
                  d2logpdf_df2_dtheta = np.zeros((self.size, f.shape[0], f.shape[1]))
                  #Chain each parameter of hte likelihood seperately
                  for p in range(self.size):
                      d2logpdf_df2_dtheta[p, :, :] = chain_2(d2logpdf_dlink2_dtheta[p,:,:], dlink_df, dlogpdf_dlink_dtheta[p,:,:], d2link_df2)
                  return d2logpdf_df2_dtheta
                  #return chain_2(d2logpdf_dlink2_dtheta, dlink_df, dlogpdf_dlink_dtheta, d2link_df2)
          else:
              # There are no parameters so return an empty array for derivatives
              return np.zeros((0, f.shape[0], f.shape[1]))
docs: TODO: Doc strings