def run_simulation(**kwargs):
    kp = KwargsParser(kwargs, DEFAULTS)
    folder = Path(kp.folder).expanduser()
    folder.mkdir(exist_ok=True, parents=True)

    file_str = f'L_{kp.L}_chi_{kp.chi}_g_{kp.g}_{kp.contraction_method}'
    logger = Logger(None, True)
    opt_logger = Logger(folder.joinpath(file_str + '.opt.log'), True)
    kp.log(opt_logger)
    opt_logger.lineskip()
    outfile = folder.joinpath(file_str + '.pkl')
    statefile = folder.joinpath(file_str + '.state.pkl')
    kp.log(logger)

    def callback(tensors, k):
        if (k % kp.save_interval == 0) and (k > 0):
            with open(statefile, 'wb') as _f:
                pickle.dump(dict(kwargs=kp.kwargs(), k=k, tensors=tensors), _f)

    opt_opts = dict(display_fun=get_display_fun(opt_logger),
                    line_search_fn='strong_wolfe',
                    max_iter=kp.max_iter,
                    callback=callback,
                    dtype=np.complex128)
    cont_opts = dict(contraction_method=kp.contraction_method)

    model = TFIM(kp.g, 'obc', lx=kp.L, ly=kp.L, dtype_hamiltonian=np.float64)
    gs, gs_energy = model.groundstate(kp.chi, (kp.L, kp.L), kp.initial_state, kp.initial_noise,
                                      cont_opts, opt_opts)

    results = dict(kwargs=kp.kwargs(),
                   gs_energy=gs_energy,
                   gs_tensors=gs.get_tensors(),
                   logfile=str(logger.logfile))

    print(f'saving results to {outfile}')
    # noinspection PyTypeChecker
    with open(outfile, 'wb') as f:
        pickle.dump(results, f)
def run_simulation(**kwargs):
    kp = KwargsParser(kwargs, DEFAULTS)
    folder = Path(kp.folder).expanduser()
    folder.mkdir(exist_ok=True, parents=True)
    logger = Logger(
        folder.joinpath(f'chi_{kp.chi}_Dopt_{kp.D_opt}_{kp.init}.log'), True)
    kp.log(logger)

    gs = None

    for g in kp.g_list:
        logger.lineskip()
        logger.log(f'g={g}')

        file_str = f'chi_{kp.chi}_Dopt_{kp.D_opt}_g_{g}_{kp.init}'
        opt_logger = Logger(folder.joinpath(file_str + '.opt.log'), True)
        outfile = folder.joinpath(file_str + '.pkl')

        opt_opts = dict(display_fun=get_display_fun(opt_logger),
                        line_search_fn='strong_wolfe',
                        max_iter=kp.max_iter,
                        dtype=np.float64)
        cont_opts = dict(chi_ctm=kp.D_opt)

        model = TFIM(g, bc='infinite', dtype_hamiltonian=np.float64)

        # initial state
        if kp.init == 'load':
            # find the file with the closest g
            g_closest = np.inf
            file_closest = None
            for f in os.listdir(folder):
                if f[-3:] != 'pkl':
                    continue
                start = f.rfind('_g_')
                if start == -1:
                    continue
                ends = [
                    f.rfind(f'_{init}') for init in ['ps', 'z+', 'x+', 'load']
                ]
                end = [e for e in ends if e != -1][0]
                _g = float(f[start + 3:end])
                if np.abs(g - _g) < np.abs(g -
                                           g_closest):  # closer then previous
                    g_closest = _g
                    file_closest = f

            # noinspection PyBroadException
            try:
                with open(folder.joinpath(file_closest), 'rb') as f:
                    results = pickle.load(f)
                init = results['gs']
                initial_noise = 0.
                print(f'loaded initial guess from {file_closest}')
            except Exception:
                if gs:  # if gs is available from previous loop iteration, use that
                    # failed to load even though this is not the first loop iteration
                    print('warning: loading from file failed', file=sys.stderr)
                    init = gs
                    initial_noise = 0.001
                else:  # if nothing found, use product state
                    init = 'ps'
                    initial_noise = 0.05
        elif kp.init == 'last':
            if gs:
                init = gs
                initial_noise = 0.
            else:
                init = 'ps'
                initial_noise = 0.05
        else:
            init = kp.init
            initial_noise = 0.05

        gs, gs_energy = model.groundstate(chi=kp.chi,
                                          initial_state=init,
                                          initial_noise=initial_noise,
                                          contraction_options=cont_opts,
                                          optimisation_options=opt_opts)

        en_list = []
        mag_list = []
        D_obs_list = []

        for D_obs in list(range(kp.D_opt))[10::10] + [kp.D_opt]:
            logger.log(f'D_obs={D_obs}')
            D_obs_list.append(D_obs)
            cont_opts['chi_ctm'] = D_obs
            en_list.append(model.energy(gs, **cont_opts))
            mag_list.append(
                LocalOperator(sx, np.array([[0]]),
                              hermitian=True).expval(gs, **cont_opts))

        print(f'saving results to {outfile}')

        results = dict(kwargs=kwargs,
                       g=g,
                       optimal_energy=gs_energy,
                       D_obs_list=D_obs_list,
                       en_list=en_list,
                       mag_list=mag_list,
                       logfile=str(opt_logger.logfile),
                       gs_tensors=gs.get_tensors())
        with open(outfile, 'wb') as f:
            pickle.dump(results, f)

        for D_obs in list(range(kp.D_opt,
                                2 * kp.D_opt))[10::10] + [2 * kp.D_opt]:
            logger.log(f'D_obs={D_obs}')
            D_obs_list.append(D_obs)
            cont_opts['chi_ctm'] = D_obs
            en_list.append(model.energy(gs, **cont_opts))
            mag_list.append(
                LocalOperator(sx, np.array([[0]]),
                              hermitian=True).expval(gs, **cont_opts))

        results = dict(kwargs=kwargs,
                       g=g,
                       optimal_energy=gs_energy,
                       D_obs_list=D_obs_list,
                       en_list=en_list,
                       mag_list=mag_list,
                       logfile=str(opt_logger.logfile),
                       gs_tensors=gs.get_tensors())

        with open(outfile, 'wb') as f:
            pickle.dump(results, f)