def aposteriori_spawning(fin, fout, pin, pout, save_canonical=False):
    """
    :param f: An ``IOManager`` instance providing the simulation data.
    :param datablock: The data block where the results are.
    """
    # Number of time steps we saved
    timesteps = fin.load_wavepacket_timegrid()
    nrtimesteps = timesteps.shape[0]

    params = fin.load_wavepacket_parameters()
    coeffs = fin.load_wavepacket_coefficients()

    # A data transformation needed by API specification
    coeffs = [ [ coeffs[i,j,:] for j in xrange(pin["ncomponents"]) ] for i in xrange(nrtimesteps) ]

    # The potential
    Potential = PotentialFactory().create_potential(pin)

    # Initialize a mother Hagedorn wavepacket with the data from another simulation
    HAWP = HagedornWavepacket(pin)
    HAWP.set_quadrature(None)

    # Initialize an empty wavepacket for spawning
    SWP = HagedornWavepacket(pout)
    SWP.set_quadrature(None)

    # Initialize a Spawner
    NAS = NonAdiabaticSpawnerKF(pout)

    # Try spawning for these components, if none is given, try it for all.
    if not "spawn_components" in parametersout:
        components = range(pin["ncomponents"])
    else:
        components = parametersout["spawn_components"]

    # Iterate over all timesteps and spawn
    for i, step in enumerate(timesteps):
        print(" Try spawning at timestep "+str(step))

        # Configure the wave packet and project to the eigenbasis.
        HAWP.set_parameters(params[i])
        HAWP.set_coefficients(coeffs[i])

        # Project to the eigenbasis as the parameter estimation
        # has to happen there because of coupling.
        T = HAWP.clone()
        T.project_to_eigen(Potential)

        # Try spawning a new packet for each component
        estps = [ NAS.estimate_parameters(T, component=acomp) for acomp in components ]

        # The quadrature
        quadrature = InhomogeneousQuadrature()

        # Quadrature, assume same quadrature order for both packets
        # Assure the "right" quadrature is choosen if mother and child have
        # different basis sizes
        if max(HAWP.get_basis_size()) > max(SWP.get_basis_size()):
            quadrature.set_qr(HAWP.get_quadrature().get_qr())
        else:
            quadrature.set_qr(SWP.get_quadrature().get_qr())

        for index, ps in enumerate(estps):
            if ps is not None:
                # One choice of the sign
                U = SWP.clone()
                U.set_parameters(ps)
                # Project the coefficients to the spawned packet
                tmp = T.clone()
                NAS.project_coefficients(tmp, U, component=components[index])

                # Other choice of the sign
                V = SWP.clone()
                # Transform parameters
                psm = list(ps)
                B = ps[0]
                Bm = -np.real(B)+1.0j*np.imag(B)
                psm[0] = Bm
                V.set_parameters(psm)
                # Project the coefficients to the spawned packet
                tmp = T.clone()
                NAS.project_coefficients(tmp, V, component=components[index])

                # Compute some inner products to finally determine which parameter set we use
                ou = abs(quadrature.quadrature(T,U, component=components[index]))
                ov = abs(quadrature.quadrature(T,V, component=components[index]))

                # Choose the packet which maximizes the inner product. This is the main point!
                if ou >= ov:
                    U = U
                else:
                    U = V

                # Finally do the spawning, this is essentially to get the remainder T right
                # The packet U is already ok by now.
                NAS.project_coefficients(T, U, component=components[index])

                # Transform back
                if save_canonical is True:
                    T.project_to_canonical(Potential)
                    U.project_to_canonical(Potential)

                # Save the mother packet rest
                fout.save_wavepacket_parameters(T.get_parameters(), timestep=step, blockid=2*index)
                fout.save_wavepacket_coefficients(T.get_coefficients(), timestep=step, blockid=2*index)

                # Save the spawned packet
                fout.save_wavepacket_parameters(U.get_parameters(), timestep=step, blockid=2*index+1)
                fout.save_wavepacket_coefficients(U.get_coefficients(), timestep=step, blockid=2*index+1)
    def spawn_basis_projection(self, mother, child, component, order=None):
        """Update the superposition coefficients of mother and
        spawned wavepacket. We do a full basis projection to the
        basis of the spawned wavepacket here.
        """
        c_old = mother.get_coefficients(component=component)

        # Mother packet
        c_new_m = np.zeros(c_old.shape, dtype=np.complexfloating)

        # Spawned packet
        c_new_s = np.zeros((child.get_basis_size(component=component),1), dtype=np.complexfloating)

        # The quadrature
        quadrature = InhomogeneousQuadrature()

        # Quadrature rule. Assure the "right" quadrature is choosen if
        # mother and child have different basis sizes
        if mother.get_basis_size(component=component) > child.get_basis_size(component=component):
            quadrature.set_qr( mother.get_quadrature().get_qr() )
        else:
            quadrature.set_qr( child.get_quadrature().get_qr() )

        # The quadrature nodes and weights
        q0, QS = quadrature.mix_parameters(mother.get_parameters(), child.get_parameters())
        nodes = quadrature.transform_nodes(mother.get_parameters(), child.get_parameters(), mother.eps)
        weights = quadrature.get_qr().get_weights()

        # Basis sets for both packets
        basis_m = mother.evaluate_basis_at(nodes, prefactor=True)
        basis_s = child.evaluate_basis_at(nodes, prefactor=True)

        max_order = min(child.get_basis_size(component=component), self.max_order)

        # Project to the basis of the spawned wavepacket
        # Original, inefficient code for projection
        # R = QR.get_order()
        # for i in xrange(max_order):
        #     # Loop over all quadrature points
        #     tmp = 0.0j
        #     for r in xrange(R):
        #         tmp += np.conj(np.dot( c_old[:,0], basis_m[:,r] )) * basis_s[i,r] * weights[0,r]
        #     c_new_s[i,0] = self.eps * QS * tmp

        # Optimised and vectorised code (in ugly formatting)
        c_new_s[:max_order,:] = self.eps * QS * (
            np.reshape(
                np.sum(
                    np.transpose(
                        np.reshape(
                            np.conj(
                                np.sum(c_old[:,:] * basis_m[:,:],axis=0)
                            ) ,(-1,1)
                        )
                    ) * (basis_s[:max_order,:] * weights[:,:]), axis=1
                ) ,(-1,1)
            ))

        # Reassign the new coefficients
        mother.set_coefficients(c_new_m, component=component)
        child.set_coefficients(c_new_s, component=component)

        return (mother, child)