Пример #1
0
def prepare_ints_rdms(wfn,
                      mo_spaces,
                      rdm_level=3,
                      rdm_type=forte.RDMsType.spin_dependent):
    """
    Preparation step for DSRG: compute a CAS and its RDMs.
    :param wfn: reference wave function from psi4
    :param mo_spaces: a dictionary {mo_space: occupation}, e.g., {'ACTIVE': [0,0,0,0]}
    :param rdm_level: max RDM to be computed
    :param rdm_type: RDMs type: spin_dependent or spin_free
    :return: a tuple of (reference energy, MOSpaceInfo, ForteIntegrals, RDMs)
    """

    forte_objects = prepare_forte_objects(wfn, mo_spaces)

    ints = forte_objects['ints']
    as_ints = forte_objects['as_ints']
    scf_info = forte_objects['scf_info']
    mo_space_info = forte_objects['mo_space_info']
    state_weights_map = forte_objects['state_weights_map']

    # build a map {StateInfo: a list of weights} for multi-state computations
    state_weights_map = forte.make_state_weights_map(forte.forte_options,
                                                     mo_space_info)

    # converts {StateInfo: weights} to {StateInfo: nroots}
    state_map = forte.to_state_nroots_map(state_weights_map)

    # create an active space solver object and compute the energy
    as_solver_type = 'FCI'
    as_solver = forte.make_active_space_solver(as_solver_type, state_map,
                                               scf_info, mo_space_info,
                                               as_ints, forte.forte_options)

    state_energies_list = as_solver.compute_energy(
    )  # a map {StateInfo: a list of energies}

    # compute averaged energy --- reference energy for DSRG
    Eref = forte.compute_average_state_energy(state_energies_list,
                                              state_weights_map)

    # compute RDMs
    rdms = as_solver.compute_average_rdms(state_weights_map, rdm_level,
                                          rdm_type)

    # semicanonicalize orbitals
    semi = forte.SemiCanonical(mo_space_info, ints, forte.forte_options)
    semi.semicanonicalize(rdms, rdm_level)

    return {
        'reference_energy': Eref,
        'mo_space_info': mo_space_info,
        'ints': ints,
        'rdms': rdms
    }
Пример #2
0
def forte_driver(state_weights_map, scf_info, options, ints, mo_space_info):
    """
    Driver to perform a Forte calculation using new solvers.

    :param state_weights_map: dictionary of {state: weights}
    :param scf_info: a SCFInfo object of Forte
    :param options: a ForteOptions object of Forte
    :param ints: a ForteIntegrals object of Forte
    :param mo_space_info: a MOSpaceInfo object of Forte

    :return: the computed energy
    """
    # map state to number of roots
    state_map = forte.to_state_nroots_map(state_weights_map)

    # create an active space solver object and compute the energy
    active_space_solver_type = options.get_str('ACTIVE_SPACE_SOLVER')
    as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE",
                                           ["RESTRICTED_DOCC"])
    active_space_solver = forte.make_active_space_solver(
        active_space_solver_type, state_map, scf_info, mo_space_info, as_ints,
        options)
    state_energies_list = active_space_solver.compute_energy()

    if options.get_bool('SPIN_ANALYSIS'):
        rdms = active_space_solver.compute_average_rdms(
            state_weights_map, 2, forte.RDMsType.spin_dependent)
        forte.perform_spin_analysis(rdms, options, mo_space_info, as_ints)

    # solver for dynamical correlation from DSRG
    correlation_solver_type = options.get_str('CORRELATION_SOLVER')
    if correlation_solver_type != 'NONE':
        dsrg_proc = ProcedureDSRG(active_space_solver, state_weights_map,
                                  mo_space_info, ints, options, scf_info)
        return_en = dsrg_proc.compute_energy()
        dsrg_proc.print_summary()
        dsrg_proc.push_to_psi4_environment()
    else:
        average_energy = forte.compute_average_state_energy(
            state_energies_list, state_weights_map)
        return_en = average_energy

    return return_en
Пример #3
0
def forte_driver(state_weights_map, scf_info, options, ints, mo_space_info):
    max_rdm_level = 3  # TODO: set this (Francesco)
    return_en = 0.0

    state_map = forte.to_state_nroots_map(state_weights_map)

    # Create an active space solver object and compute the energy
    active_space_solver_type = options.get_str('ACTIVE_SPACE_SOLVER')
    as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE",
                                           ["RESTRICTED_DOCC"])
    active_space_solver = forte.make_active_space_solver(
        active_space_solver_type, state_map, scf_info, mo_space_info, as_ints,
        options)
    active_space_solver.set_max_rdm_level(max_rdm_level)
    state_energies_list = active_space_solver.compute_energy()

    # Notes (York):
    #     cases to run active space solver: reference relaxation, state-average dsrg
    #     cases to run contracted ci solver (will be put in ActiveSpaceSolver): contracted state-average dsrg
    Etemp1, Etemp2 = 0.0, 0.0

    # Create a dynamical correlation solver object
    correlation_solver_type = options.get_str('CORRELATION_SOLVER')
    if correlation_solver_type != 'NONE':
        # Grab the reference
        reference = active_space_solver.compute_average_reference(
            state_weights_map)  # TODO: this should be chosen in a smart way

        # Compute unitary matrices Ua and Ub that rotate the orbitals to the semicanonical basis
        semi = forte.SemiCanonical(mo_space_info, ints, options)
        if options.get_bool("SEMI_CANONICAL"):
            semi.semicanonicalize(reference, max_rdm_level)
        Ua = semi.Ua_t()
        Ub = semi.Ub_t()

        dsrg = forte.make_dsrg_method(correlation_solver_type, reference,
                                      scf_info, options, ints, mo_space_info)
        dsrg.set_Uactv(Ua, Ub)
        Edsrg = dsrg.compute_energy()
        psi4.core.set_scalar_variable('UNRELAXED ENERGY', Edsrg)

        # dipole moment related
        do_dipole = options.get_bool("DSRG_DIPOLE")
        if do_dipole:
            if correlation_solver_type == 'MRDSRG' or correlation_solver_type == 'THREE-DSRG-MRPT2':
                do_dipole = False
                psi4.core.print_out(
                    "\n  !Dipole moment is not implemented for {}.".format(
                        correlation_solver_type))
                warnings.warn("Dipole moment is not implemented for MRDSRG.",
                              UserWarning)
            udm_x = psi4.core.variable('UNRELAXED DIPOLE X')
            udm_y = psi4.core.variable('UNRELAXED DIPOLE Y')
            udm_z = psi4.core.variable('UNRELAXED DIPOLE Z')
            udm_t = psi4.core.variable('UNRELAXED DIPOLE')

        def dipole_routine(dsrg_method, reference):
            dipole_moments = dsrg_method.nuclear_dipole()
            dipole_dressed = dsrg_method.deGNO_DMbar_actv()
            for i in range(3):
                dipole_moments[i] += dipole_dressed[i].contract_with_densities(
                    reference)
            dm_total = math.sqrt(sum([i * i for i in dipole_moments]))
            dipole_moments.append(dm_total)
            return dipole_moments

        # determine the relaxation procedure
        relax_mode = options.get_str("RELAX_REF")
        is_multi_state = True if options.get_str(
            "CALC_TYPE") != "SS" else False

        if relax_mode == 'NONE' and is_multi_state:
            relax_mode = 'ONCE'

        if relax_mode == 'NONE':
            return Edsrg
        elif relax_mode == 'ONCE':
            maxiter = 1
        elif relax_mode == 'TWICE':
            maxiter = 2
        else:
            maxiter = options.get_int('MAXITER_RELAX_REF')

        # filter out some ms-dsrg algorithms
        ms_dsrg_algorithm = options.get_str("DSRG_MULTI_STATE")
        if is_multi_state and ("SA" not in ms_dsrg_algorithm):
            raise NotImplementedError(
                "MS or XMS is disabled due to the reconstruction.")
        if ms_dsrg_algorithm == "SA_SUB" and relax_mode != 'ONCE':
            raise NotImplementedError(
                "Need to figure out how to compute relaxed SA density.")

        # prepare for reference relaxation iteration
        relax_conv = options.get_double("RELAX_E_CONVERGENCE")
        e_conv = options.get_double("E_CONVERGENCE")
        converged = False if relax_mode != 'ONCE' and relax_mode != 'TWICE' else True

        # store (unrelaxed, relaxed) quantities
        dsrg_energies = []
        dsrg_dipoles = []

        for N in range(maxiter):
            # Grab the effective Hamiltonian in the actice space
            ints_dressed = dsrg.compute_Heff_actv()

            # Compute the energy
            if is_multi_state and ms_dsrg_algorithm == "SA_SUB":
                state_energies_list = active_space_solver.compute_contracted_energy(
                    ints_dressed)
                Erelax = forte.compute_average_state_energy(
                    state_energies_list, state_weights_map)
                return Erelax
            else:
                # Make a new ActiveSpaceSolver with the new ints
                as_solver_relaxed = forte.make_active_space_solver(
                    active_space_solver_type, state_map, scf_info,
                    mo_space_info, ints_dressed, options)
                as_solver_relaxed.set_max_rdm_level(max_rdm_level)
                state_energies_list = as_solver_relaxed.compute_energy()
                Erelax = forte.compute_average_state_energy(
                    state_energies_list, state_weights_map)

            dsrg_energies.append((Edsrg, Erelax))

            if do_dipole:
                if is_multi_state:
                    psi4.core.print_out(
                        "\n  !DSRG transition dipoles are disabled temporarily."
                    )
                    warnings.warn(
                        "DSRG transition dipoles are disabled temporarily.",
                        UserWarning)
                else:
                    reference = as_solver_relaxed.compute_average_reference(
                        state_weights_map)
                    x, y, z, t = dipole_routine(dsrg, reference)
                    dsrg_dipoles.append(
                        ((udm_x, udm_y, udm_z, udm_t), (x, y, z, t)))
                    psi4.core.print_out(
                        "\n\n    {} partially relaxed dipole moment:".format(
                            correlation_solver_type))
                    psi4.core.print_out(
                        "\n      X: {:10.6f}  Y: {:10.6f}"
                        "  Z: {:10.6f}  Total: {:10.6f}\n".format(x, y, z, t))

            # test convergence and break loop
            if abs(Edsrg - Etemp1) < relax_conv and abs(Erelax - Etemp2) < relax_conv \
                and abs(Edsrg - Erelax) < e_conv:
                converged = True
                break

            Etemp1, Etemp2 = Edsrg, Erelax

            # continue iterations
            if N + 1 != maxiter:
                # Compute the reference in the original basis
                # reference available if done relaxed dipole
                if do_dipole and (not is_multi_state):
                    reference = semi.transform_reference(
                        Ua, Ub, reference, max_rdm_level)
                else:
                    reference = semi.transform_reference(
                        Ua, Ub,
                        as_solver_relaxed.compute_average_reference(
                            state_weights_map), max_rdm_level)

                # Now semicanonicalize the reference and orbitals
                semi.semicanonicalize(reference, max_rdm_level)
                Ua = semi.Ua_t()
                Ub = semi.Ub_t()

                # Compute DSRG in the semicanonical basis
                dsrg = forte.make_dsrg_method(correlation_solver_type,
                                              reference, scf_info, options,
                                              ints, mo_space_info)
                dsrg.set_Uactv(Ua, Ub)
                Edsrg = dsrg.compute_energy()

                if do_dipole:
                    udm_x = psi4.core.variable('UNRELAXED DIPOLE X')
                    udm_y = psi4.core.variable('UNRELAXED DIPOLE Y')
                    udm_z = psi4.core.variable('UNRELAXED DIPOLE Z')
                    udm_t = psi4.core.variable('UNRELAXED DIPOLE')

        # printing
        if (not is_multi_state) or maxiter > 1:
            psi4.core.print_out(
                "\n\n  => {} Reference Relaxation Energy Summary <=\n".format(
                    correlation_solver_type))
            indent = ' ' * 4
            dash = '-' * 71
            title = indent + "{:5}  {:>31}  {:>31}\n".format(
                ' ', "Fixed Ref. (a.u.)", "Relaxed Ref. (a.u.)")
            title += indent + "{}  {}  {}\n".format(' ' * 5, '-' * 31,
                                                    '-' * 31)
            title += indent + "{:5}  {:>20} {:>10}  {:>20} {:>10}\n".format(
                "Iter.", "Total Energy", "Delta", "Total Energy", "Delta")
            psi4.core.print_out("\n{}".format(title + indent + dash))
            E0_old, E1_old = 0.0, 0.0
            for n, pair in enumerate(dsrg_energies):
                E0, E1 = pair
                psi4.core.print_out("\n{}{:>5}  {:>20.12f} {:>10.3e}"
                                    "  {:>20.12f} {:>10.3e}".format(
                                        indent, n + 1, E0, E0 - E0_old, E1,
                                        E1 - E1_old))
                E0_old, E1_old = E0, E1

            psi4.core.print_out("\n{}{}".format(indent, dash))

        if do_dipole and (not is_multi_state):
            psi4.core.print_out(
                "\n\n  => {} Reference Relaxation Dipole Summary <=\n".format(
                    correlation_solver_type))
            psi4.core.print_out("\n    {} unrelaxed dipole moment:".format(
                correlation_solver_type))
            psi4.core.print_out(
                "\n      X: {:10.6f}  Y: {:10.6f}  "
                "Z: {:10.6f}  Total: {:10.6f}\n".format(*dsrg_dipoles[0][0]))
            psi4.core.set_scalar_variable('UNRELAXED DIPOLE',
                                          dsrg_dipoles[0][0][-1])

            psi4.core.print_out(
                "\n    {} partially relaxed dipole moment:".format(
                    correlation_solver_type))
            psi4.core.print_out(
                "\n      X: {:10.6f}  Y: {:10.6f}  "
                "Z: {:10.6f}  Total: {:10.6f}\n".format(*dsrg_dipoles[0][1]))
            psi4.core.set_scalar_variable('PARTIALLY RELAXED DIPOLE',
                                          dsrg_dipoles[0][1][-1])

            if maxiter > 1:
                psi4.core.print_out("\n    {} relaxed dipole moment:".format(
                    correlation_solver_type))
                psi4.core.print_out("\n      X: {:10.6f}  Y: {:10.6f}  "
                                    "Z: {:10.6f}  Total: {:10.6f}\n".format(
                                        *dsrg_dipoles[1][0]))
                psi4.core.set_scalar_variable('RELAXED DIPOLE',
                                              dsrg_dipoles[1][0][-1])

        # set energies to environment
        psi4.core.set_scalar_variable('PARTIALLY RELAXED ENERGY',
                                      dsrg_energies[0][1])
        if maxiter > 1:
            psi4.core.set_scalar_variable('RELAXED ENERGY',
                                          dsrg_energies[1][0])

        # throw not converging error if relaxation not converged
        if not converged:
            psi4.core.set_scalar_variable('CURRENT UNRELAXED ENERGY',
                                          dsrg_energies[-1][0])
            psi4.core.set_scalar_variable('CURRENT RELAXED ENERGY',
                                          dsrg_energies[-1][1])
            psi4.core.set_scalar_variable('CURRENT ENERGY',
                                          dsrg_energies[-1][1])
            raise psi4.core.ConvergenceError(
                "DSRG relaxation does not converge in {} cycles".format(
                    maxiter))
        else:
            if relax_mode != 'ONCE' and relax_mode != 'TWICE':
                psi4.core.set_scalar_variable('FULLY RELAXED ENERGY',
                                              dsrg_energies[-1][1])
                psi4.core.set_scalar_variable('CURRENT ENERGY',
                                              dsrg_energies[-1][1])
                if do_dipole and (not is_multi_state):
                    psi4.core.print_out(
                        "\n    {} fully relaxed dipole moment:".format(
                            correlation_solver_type))
                    psi4.core.print_out(
                        "\n      X: {:10.6f}  Y: {:10.6f}  "
                        "Z: {:10.6f}  Total: {:10.6f}\n".format(
                            *dsrg_dipoles[-1][1]))
                    psi4.core.set_scalar_variable('FULLY RELAXED DIPOLE',
                                                  dsrg_dipoles[-1][1][-1])

        return Erelax
    else:

        average_energy = forte.compute_average_state_energy(
            state_energies_list, state_weights_map)
        return_en = average_energy

    return return_en
Пример #4
0
    def compute_energy(self):
        """ Compute energy with reference relaxation and return current DSRG energy. """
        # Notes (York):
        # cases to run active space solver: reference relaxation, state-average dsrg
        # cases to run contracted ci solver (will be put in ActiveSpaceSolver): contracted state-average dsrg

        e_relax = 0.0  # initialize this to avoid PyCharm warning
        self.energies = []
        self.dipoles = []

        # Perform the initial un-relaxed DSRG
        self.make_dsrg_solver()
        self.dsrg_setup()
        e_dsrg = self.dsrg_solver.compute_energy()
        psi4.core.set_scalar_variable("UNRELAXED ENERGY", e_dsrg)

        self.energies_environment[0] = {k: v for k, v in psi4.core.variables().items()
                                        if 'ROOT' in k}

        # Spit out energy if reference relaxation not implemented
        if not self.Heff_implemented:
            self.relax_maxiter = 0

        # Reference relaxation procedure
        for n in range(self.relax_maxiter):
            # Grab effective Hamiltonian in the active space
            # These active integrals are in the original basis (before semi-canonicalize in the init function),
            # so that the CI coefficients are comparable before and after DSRG dressing.
            ints_dressed = self.dsrg_solver.compute_Heff_actv()

            # Spit out contracted SA-DSRG energy
            if self.do_multi_state and self.multi_state_type == "SA_SUB":
                max_rdm_level = 3 if self.options.get_bool("FORM_HBAR3") else 2
                state_energies_list = self.active_space_solver.compute_contracted_energy(ints_dressed, max_rdm_level)
                e_relax = forte.compute_average_state_energy(state_energies_list, self.state_weights_map)
                self.energies.append((e_dsrg, e_relax))
                break

            # Solve active space using dressed integrals
            self.active_space_solver.set_active_space_integrals(ints_dressed)
            state_energies_list = self.active_space_solver.compute_energy()

            # Reorder weights if needed
            if self.state_ci_wfn_map is not None:
                state_ci_wfn_map = self.active_space_solver.state_ci_wfn_map()
                self.reorder_weights(state_ci_wfn_map)
                self.state_ci_wfn_map = state_ci_wfn_map

            e_relax = forte.compute_average_state_energy(state_energies_list, self.state_weights_map)
            self.energies.append((e_dsrg, e_relax))

            # Compute relaxed dipole
            if self.do_dipole:
                self.rdms = self.active_space_solver.compute_average_rdms(self.state_weights_map, self.max_rdm_level,
                                                                          self.rdm_type)
                dm_u = ProcedureDSRG.grab_dipole_unrelaxed()
                dm_r = self.compute_dipole_relaxed()
                self.dipoles.append((dm_u, dm_r))

            # Save energies that have been pushed to Psi4 environment
            self.energies_environment[n + 1] = {k: v for k, v in psi4.core.variables().items()
                                                if 'ROOT' in k}
            self.energies_environment[n + 1]["DSRG FIXED"] = e_dsrg
            self.energies_environment[n + 1]["DSRG RELAXED"] = e_relax

            # Test convergence and break loop
            if self.test_relaxation_convergence(n):
                break

            # Continue to solve DSRG equations

            # - Compute RDMs (RDMs available if done relaxed dipole)
            if self.do_multi_state or (not self.do_dipole):
                self.rdms = self.active_space_solver.compute_average_rdms(self.state_weights_map, self.max_rdm_level,
                                                                          self.rdm_type)

            # - Transform RDMs to the semi-canonical orbitals of last step (because of integrals)
            self.rdms.rotate(self.Ua, self.Ub)

            # - Semi-canonicalize RDMs and orbitals
            if self.do_semicanonical:
                self.semi.semicanonicalize(self.rdms)
                # NOT read previous orbitals if fixing orbital ordering and phases failed
                if (not self.semi.fix_orbital_success()) and self.Heff_implemented:
                    psi4.core.print_out("\n  DSRG checkpoint files removed due to the unsuccessful"
                                        " attempt to fix orbital phase and order.")
                    self.dsrg_solver.clean_checkpoints()
            self.Ua["ik"] = self.Ua["ij"] * self.semi.Ua_t()["jk"]
            self.Ub["ik"] = self.Ub["ij"] * self.semi.Ub_t()["jk"]

            # - Compute DSRG energy
            self.make_dsrg_solver()
            self.dsrg_setup()
            self.dsrg_solver.set_read_cwd_amps(not self.restart_amps)  # don't read from cwd if checkpoint available
            e_dsrg = self.dsrg_solver.compute_energy()

        self.dsrg_cleanup()

        # dump reference relaxation energies to json file
        if self.save_relax_energies:
            with open('dsrg_relaxed_energies.json', 'w') as w:
                json.dump(self.energies_environment, w, sort_keys=True, indent=4)

        e_current = e_dsrg if len(self.energies) == 0 else e_relax
        psi4.core.set_scalar_variable("CURRENT ENERGY", e_current)

        return e_current
Пример #5
0
def forte_driver(state_weights_map, scf_info, options, ints, mo_space_info):
    max_rdm_level = 3 # TODO: set this (Francesco)
    return_en = 0.0

    state_map = forte.to_state_nroots_map(state_weights_map)

    # Create an active space solver object and compute the energy
    active_space_solver_type = options.get_str('ACTIVE_SPACE_SOLVER')
    as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE", ["RESTRICTED_DOCC"]);
    active_space_solver = forte.make_active_space_solver(active_space_solver_type,state_map,scf_info,mo_space_info,as_ints,options)
    state_energies_list = active_space_solver.compute_energy()


    # Notes (York):
    #     cases to run active space solver: reference relaxation, state-average dsrg
    #     cases to run contracted ci solver (will be put in ActiveSpaceSolver): contracted state-average dsrg
    Etemp1, Etemp2 = 0.0, 0.0

    # Create a dynamical correlation solver object
    correlation_solver_type = options.get_str('CORRELATION_SOLVER')
    if correlation_solver_type != 'NONE':
        # Grab the reference
        rdms = active_space_solver.compute_average_rdms(state_weights_map, 3) # TODO: max_rdm_level should be chosen in a smart way

        # Compute unitary matrices Ua and Ub that rotate the orbitals to the semicanonical basis
        semi = forte.SemiCanonical(mo_space_info, ints, options)
        if options.get_bool("SEMI_CANONICAL"):
            semi.semicanonicalize(rdms, max_rdm_level)
        Ua = semi.Ua_t()
        Ub = semi.Ub_t()

        dsrg = forte.make_dsrg_method(correlation_solver_type, rdms,
                                      scf_info, options, ints, mo_space_info)
        dsrg.set_Uactv(Ua, Ub)
        Edsrg = dsrg.compute_energy()
        psi4.core.set_scalar_variable('UNRELAXED ENERGY', Edsrg)

        # dipole moment related
        do_dipole = options.get_bool("DSRG_DIPOLE")
        if do_dipole:
            if correlation_solver_type == 'MRDSRG' or correlation_solver_type == 'THREE-DSRG-MRPT2':
                do_dipole = False
                psi4.core.print_out("\n  !Dipole moment is not implemented for {}.".format(correlation_solver_type))
                warnings.warn("Dipole moment is not implemented for MRDSRG.", UserWarning)
            udm_x = psi4.core.variable('UNRELAXED DIPOLE X')
            udm_y = psi4.core.variable('UNRELAXED DIPOLE Y')
            udm_z = psi4.core.variable('UNRELAXED DIPOLE Z')
            udm_t = psi4.core.variable('UNRELAXED DIPOLE')

        def dipole_routine(dsrg_method, rdms):
            dipole_moments = dsrg_method.nuclear_dipole()
            dipole_dressed = dsrg_method.deGNO_DMbar_actv()
            for i in range(3):
                dipole_moments[i] += dipole_dressed[i].contract_with_rdms(rdms)
            dm_total = math.sqrt(sum([i * i for i in dipole_moments]))
            dipole_moments.append(dm_total)
            return dipole_moments

        # determine the relaxation procedure
        relax_mode = options.get_str("RELAX_REF")
        is_multi_state = True if options.get_str("CALC_TYPE") != "SS" else False

        if relax_mode == 'NONE' and is_multi_state:
            relax_mode = 'ONCE'

        if relax_mode == 'NONE':
            return Edsrg
        elif relax_mode == 'ONCE':
            maxiter = 1
        elif relax_mode == 'TWICE':
            maxiter = 2
        else:
            maxiter = options.get_int('MAXITER_RELAX_REF')

        # filter out some ms-dsrg algorithms
        ms_dsrg_algorithm = options.get_str("DSRG_MULTI_STATE")
        if is_multi_state and ("SA" not in ms_dsrg_algorithm):
            raise NotImplementedError("MS or XMS is disabled due to the reconstruction.")
        if ms_dsrg_algorithm == "SA_SUB" and relax_mode != 'ONCE':
            raise NotImplementedError("Need to figure out how to compute relaxed SA density.")

        # prepare for reference relaxation iteration
        relax_conv = options.get_double("RELAX_E_CONVERGENCE")
        e_conv = options.get_double("E_CONVERGENCE")
        converged = False if relax_mode != 'ONCE' and relax_mode != 'TWICE' else True

        # store (unrelaxed, relaxed) quantities
        dsrg_energies = []
        dsrg_dipoles = []

        for N in range(maxiter):
            # Grab the effective Hamiltonian in the actice space
            ints_dressed = dsrg.compute_Heff_actv()

            # Compute the energy
            if is_multi_state and ms_dsrg_algorithm == "SA_SUB":
                sa_sub_max_rdm = 2 # TODO: This should be 3 if do_hbar3 is true
                state_energies_list = active_space_solver.compute_contracted_energy(ints_dressed, sa_sub_max_rdm)
                Erelax = forte.compute_average_state_energy(state_energies_list,state_weights_map)
                return Erelax
            else:
                # Make a new ActiveSpaceSolver with the new ints
                as_solver_relaxed = forte.make_active_space_solver(active_space_solver_type,
                                                                   state_map,scf_info,
                                                                   mo_space_info,ints_dressed,
                                                                   options)
                state_energies_list = as_solver_relaxed.compute_energy()
                Erelax = forte.compute_average_state_energy(state_energies_list,state_weights_map)

            dsrg_energies.append((Edsrg, Erelax))

            if do_dipole:
                if is_multi_state:
                    psi4.core.print_out("\n  !DSRG transition dipoles are disabled temporarily.")
                    warnings.warn("DSRG transition dipoles are disabled temporarily.", UserWarning)
                else:
                    rdms = as_solver_relaxed.compute_average_rdms(state_weights_map, 3)
                    x, y, z, t = dipole_routine(dsrg, rdms)
                    dsrg_dipoles.append(((udm_x, udm_y, udm_z, udm_t), (x, y, z, t)))
                    psi4.core.print_out("\n\n    {} partially relaxed dipole moment:".format(correlation_solver_type))
                    psi4.core.print_out("\n      X: {:10.6f}  Y: {:10.6f}"
                                        "  Z: {:10.6f}  Total: {:10.6f}\n".format(x, y, z, t))

            # test convergence and break loop
            if abs(Edsrg - Etemp1) < relax_conv and abs(Erelax - Etemp2) < relax_conv \
                and abs(Edsrg - Erelax) < e_conv:
                converged = True
                break

            Etemp1, Etemp2 = Edsrg, Erelax

            # continue iterations
            if N + 1 != maxiter:
                # Compute the rdms in the original basis
                # rdms available if done relaxed dipole
                if do_dipole and (not is_multi_state):
                    rdms = semi.transform_rdms(Ua, Ub, rdms, max_rdm_level)
                else:
                    rdms = semi.transform_rdms(Ua, Ub, as_solver_relaxed.compute_average_rdms(state_weights_map, 3),
                                                         max_rdm_level)

                # Now semicanonicalize the reference and orbitals
                semi.semicanonicalize(rdms, max_rdm_level)
                Ua = semi.Ua_t()
                Ub = semi.Ub_t()

                # Compute DSRG in the semicanonical basis
                dsrg = forte.make_dsrg_method(correlation_solver_type, rdms,
                                              scf_info, options, ints, mo_space_info)
                dsrg.set_Uactv(Ua, Ub)
                Edsrg = dsrg.compute_energy()

                if do_dipole:
                    udm_x = psi4.core.variable('UNRELAXED DIPOLE X')
                    udm_y = psi4.core.variable('UNRELAXED DIPOLE Y')
                    udm_z = psi4.core.variable('UNRELAXED DIPOLE Z')
                    udm_t = psi4.core.variable('UNRELAXED DIPOLE')

        # printing
        if (not is_multi_state) or maxiter > 1:
            psi4.core.print_out("\n\n  => {} Reference Relaxation Energy Summary <=\n".format(correlation_solver_type))
            indent = ' ' * 4
            dash = '-' * 71
            title = indent + "{:5}  {:>31}  {:>31}\n".format(' ', "Fixed Ref. (a.u.)",
                                                             "Relaxed Ref. (a.u.)")
            title += indent + "{}  {}  {}\n".format(' ' * 5, '-' * 31, '-' * 31)
            title += indent + "{:5}  {:>20} {:>10}  {:>20} {:>10}\n".format("Iter.", "Total Energy", "Delta",
                                                                        "Total Energy", "Delta")
            psi4.core.print_out("\n{}".format(title + indent + dash))
            E0_old, E1_old = 0.0, 0.0
            for n, pair in enumerate(dsrg_energies):
                E0, E1 = pair
                psi4.core.print_out("\n{}{:>5}  {:>20.12f} {:>10.3e}"
                                    "  {:>20.12f} {:>10.3e}".format(indent, n + 1,
                                                                    E0, E0 - E0_old, E1, E1 - E1_old))
                E0_old, E1_old = E0, E1

            psi4.core.print_out("\n{}{}".format(indent, dash))

        if do_dipole and (not is_multi_state):
            psi4.core.print_out("\n\n  => {} Reference Relaxation Dipole Summary <=\n".format(correlation_solver_type))
            psi4.core.print_out("\n    {} unrelaxed dipole moment:".format(correlation_solver_type))
            psi4.core.print_out("\n      X: {:10.6f}  Y: {:10.6f}  "
                                "Z: {:10.6f}  Total: {:10.6f}\n".format(*dsrg_dipoles[0][0]))
            psi4.core.set_scalar_variable('UNRELAXED DIPOLE', dsrg_dipoles[0][0][-1])

            psi4.core.print_out("\n    {} partially relaxed dipole moment:".format(correlation_solver_type))
            psi4.core.print_out("\n      X: {:10.6f}  Y: {:10.6f}  "
                                "Z: {:10.6f}  Total: {:10.6f}\n".format(*dsrg_dipoles[0][1]))
            psi4.core.set_scalar_variable('PARTIALLY RELAXED DIPOLE', dsrg_dipoles[0][1][-1])

            if maxiter > 1:
                psi4.core.print_out("\n    {} relaxed dipole moment:".format(correlation_solver_type))
                psi4.core.print_out("\n      X: {:10.6f}  Y: {:10.6f}  "
                                    "Z: {:10.6f}  Total: {:10.6f}\n".format(*dsrg_dipoles[1][0]))
                psi4.core.set_scalar_variable('RELAXED DIPOLE', dsrg_dipoles[1][0][-1])

        # set energies to environment
        psi4.core.set_scalar_variable('PARTIALLY RELAXED ENERGY', dsrg_energies[0][1])
        if maxiter > 1:
            psi4.core.set_scalar_variable('RELAXED ENERGY', dsrg_energies[1][0])

        # throw not converging error if relaxation not converged
        if not converged:
            psi4.core.set_scalar_variable('CURRENT UNRELAXED ENERGY', dsrg_energies[-1][0])
            psi4.core.set_scalar_variable('CURRENT RELAXED ENERGY', dsrg_energies[-1][1])
            psi4.core.set_scalar_variable('CURRENT ENERGY', dsrg_energies[-1][1])
            raise psi4.core.ConvergenceError("DSRG relaxation does not converge in {} cycles".format(maxiter))
        else:
            if relax_mode != 'ONCE' and relax_mode != 'TWICE':
                psi4.core.set_scalar_variable('FULLY RELAXED ENERGY', dsrg_energies[-1][1])
                psi4.core.set_scalar_variable('CURRENT ENERGY', dsrg_energies[-1][1])
                if do_dipole and (not is_multi_state):
                    psi4.core.print_out("\n    {} fully relaxed dipole moment:".format(correlation_solver_type))
                    psi4.core.print_out("\n      X: {:10.6f}  Y: {:10.6f}  "
                                        "Z: {:10.6f}  Total: {:10.6f}\n".format(*dsrg_dipoles[-1][1]))
                    psi4.core.set_scalar_variable('FULLY RELAXED DIPOLE', dsrg_dipoles[-1][1][-1])

        return Erelax
    else : 

        average_energy = forte.compute_average_state_energy(state_energies_list,state_weights_map)
        return_en = average_energy

    return return_en