def mpi_split_evaluator_run(target_evaluator, termination_params=None, core_params=None, exception_handling_params=None, log=None, gradient_only=False, line_search=True):
    'The supported scenario is that each MPI worker rank has a target evaluator\n  that has part of the data.  Each rank calculates a bit of the functional and\n  gradients, but then mpi reduce is used to sum them all up.  There has been\n  no low-level redesign to support MPI.  In particular, the ext.minimizer is\n  run (wastefully) by every worker rank, using the same data.  It is assumed that\n  the calculation of compute_functional_and_gradients() is overwhelmingly the rate\n  limiting step, and that is what MPI parallelism is intended to distribute here.'
    from libtbx.mpi4py import MPI
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()
    if (termination_params is None):
        termination_params = termination_parameters()
    if (core_params is None):
        core_params = core_parameters()
    if (exception_handling_params is None):
        exception_handling_params = exception_handling_parameters()
    x = target_evaluator.x
    if (log is not None):
        print('lbfgs minimizer():', file=log)
        print('  x.size():', x.size(), file=log)
        print('  m:', core_params.m, file=log)
        print('  maxfev:', core_params.maxfev, file=log)
        print('  gtol:', core_params.gtol, file=log)
        print('  xtol:', core_params.xtol, file=log)
        print('  stpmin:', core_params.stpmin, file=log)
        print('  stpmax:', core_params.stpmax, file=log)
        print('lbfgs traditional_convergence_test:', termination_params.traditional_convergence_test, file=log)
    minimizer = ext.minimizer(x.size(), core_params.m, core_params.maxfev, core_params.gtol, core_params.xtol, core_params.stpmin, core_params.stpmax)
    if termination_params.traditional_convergence_test:
        is_converged = ext.traditional_convergence_test(x.size(), termination_params.traditional_convergence_test_eps)
    else:
        is_converged = ext.drop_convergence_test(n_test_points=termination_params.drop_convergence_test_n_test_points, max_drop_eps=termination_params.drop_convergence_test_max_drop_eps, iteration_coefficient=termination_params.drop_convergence_test_iteration_coefficient)
    callback_after_step = getattr(target_evaluator, 'callback_after_step', None)
    diag_mode = getattr(target_evaluator, 'diag_mode', None)
    if (diag_mode is not None):
        assert (diag_mode in ['once', 'always'])
    (f_min, x_min) = (None, None)
    (f, g) = (None, None)
    try:
        while 1:
            if (diag_mode is None):
                (f_term, g_term) = target_evaluator.compute_functional_and_gradients()
                f_total = comm.reduce(f_term, MPI.SUM, 0)
                g_total = comm.reduce(g_term, MPI.SUM, 0)
                if (rank == 0):
                    transmit = (f_total, g_total)
                else:
                    transmit = None
                (f, g) = comm.bcast(transmit, root=0)
                if (False and (rank == 0)):
                    print(('%s %10.4f' % ('MPI stp', f)), '[', ' '.join([('%10.4f' % a) for a in x]), ']')
                d = None
            else:
                (f, g, d) = target_evaluator.compute_functional_gradients_diag()
                if (diag_mode == 'once'):
                    diag_mode = None
            if (f_min is None):
                if (not termination_params.traditional_convergence_test):
                    is_converged(f)
                (f_min, x_min) = (f, x.deep_copy())
            elif (f_min > f):
                (f_min, x_min) = (f, x.deep_copy())
            if (log is not None):
                print(('lbfgs minimizer.run(): f=%.6g, |g|=%.6g, x_min=%.6g, x_mean=%.6g, x_max=%.6g' % (f, g.norm(), flex.min(x), flex.mean(x), flex.max(x))), file=log)
            if (d is None):
                if minimizer.run(x, f, g, gradient_only, line_search):
                    continue
            elif minimizer.run(x, f, g, d, gradient_only, line_search):
                continue
            if (log is not None):
                print('lbfgs minimizer step', file=log)
            if (callback_after_step is not None):
                if (callback_after_step(minimizer) is True):
                    if (log is not None):
                        print('lbfgs minimizer stop: callback_after_step is True', file=log)
                    break
            if termination_params.traditional_convergence_test:
                if ((minimizer.iter() >= termination_params.min_iterations) and is_converged(x, g)):
                    if (log is not None):
                        print('lbfgs minimizer stop: traditional_convergence_test', file=log)
                    break
            elif is_converged(f):
                if (log is not None):
                    print('lbfgs minimizer stop: drop_convergence_test', file=log)
                break
            if ((termination_params.max_iterations is not None) and (minimizer.iter() >= termination_params.max_iterations)):
                if (log is not None):
                    print('lbfgs minimizer stop: max_iterations', file=log)
                break
            if ((termination_params.max_calls is not None) and (minimizer.nfun() > termination_params.max_calls)):
                if (log is not None):
                    print('lbfgs minimizer stop: max_calls', file=log)
                break
            if (d is None):
                if (not minimizer.run(x, f, g, gradient_only, line_search)):
                    break
            elif (not minimizer.run(x, f, g, d, gradient_only, line_search)):
                break
    except RuntimeError as e:
        minimizer.error = str(e)
        if (log is not None):
            print('lbfgs minimizer exception:', str(e), file=log)
        if (x_min is not None):
            x.clear()
            x.extend(x_min)
        error_classification = exception_handling_params.filter(minimizer.error, x.size(), x, g)
        if (error_classification > 0):
            raise
        elif (error_classification < 0):
            minimizer.is_unusual_error = True
        else:
            minimizer.is_unusual_error = False
    else:
        minimizer.error = None
        minimizer.is_unusual_error = None
    if (log is not None):
        print('lbfgs minimizer done.', file=log)
    return minimizer
The supported scenario is that each MPI worker rank has a target evaluator
that has part of the data.  Each rank calculates a bit of the functional and
gradients, but then mpi reduce is used to sum them all up.  There has been
no low-level redesign to support MPI.  In particular, the ext.minimizer is
run (wastefully) by every worker rank, using the same data.  It is assumed that
the calculation of compute_functional_and_gradients() is overwhelmingly the rate
limiting step, and that is what MPI parallelism is intended to distribute here.
def mpi_split_evaluator_run(target_evaluator, termination_params=None, core_params=None, exception_handling_params=None, log=None, gradient_only=False, line_search=True):
    'The supported scenario is that each MPI worker rank has a target evaluator\n  that has part of the data.  Each rank calculates a bit of the functional and\n  gradients, but then mpi reduce is used to sum them all up.  There has been\n  no low-level redesign to support MPI.  In particular, the ext.minimizer is\n  run (wastefully) by every worker rank, using the same data.  It is assumed that\n  the calculation of compute_functional_and_gradients() is overwhelmingly the rate\n  limiting step, and that is what MPI parallelism is intended to distribute here.'
    from libtbx.mpi4py import MPI
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()
    if (termination_params is None):
        termination_params = termination_parameters()
    if (core_params is None):
        core_params = core_parameters()
    if (exception_handling_params is None):
        exception_handling_params = exception_handling_parameters()
    x = target_evaluator.x
    if (log is not None):
        print('lbfgs minimizer():', file=log)
        print('  x.size():', x.size(), file=log)
        print('  m:', core_params.m, file=log)
        print('  maxfev:', core_params.maxfev, file=log)
        print('  gtol:', core_params.gtol, file=log)
        print('  xtol:', core_params.xtol, file=log)
        print('  stpmin:', core_params.stpmin, file=log)
        print('  stpmax:', core_params.stpmax, file=log)
        print('lbfgs traditional_convergence_test:', termination_params.traditional_convergence_test, file=log)
    minimizer = ext.minimizer(x.size(), core_params.m, core_params.maxfev, core_params.gtol, core_params.xtol, core_params.stpmin, core_params.stpmax)
    if termination_params.traditional_convergence_test:
        is_converged = ext.traditional_convergence_test(x.size(), termination_params.traditional_convergence_test_eps)
    else:
        is_converged = ext.drop_convergence_test(n_test_points=termination_params.drop_convergence_test_n_test_points, max_drop_eps=termination_params.drop_convergence_test_max_drop_eps, iteration_coefficient=termination_params.drop_convergence_test_iteration_coefficient)
    callback_after_step = getattr(target_evaluator, 'callback_after_step', None)
    diag_mode = getattr(target_evaluator, 'diag_mode', None)
    if (diag_mode is not None):
        assert (diag_mode in ['once', 'always'])
    (f_min, x_min) = (None, None)
    (f, g) = (None, None)
    try:
        while 1:
            if (diag_mode is None):
                (f_term, g_term) = target_evaluator.compute_functional_and_gradients()
                f_total = comm.reduce(f_term, MPI.SUM, 0)
                g_total = comm.reduce(g_term, MPI.SUM, 0)
                if (rank == 0):
                    transmit = (f_total, g_total)
                else:
                    transmit = None
                (f, g) = comm.bcast(transmit, root=0)
                if (False and (rank == 0)):
                    print(('%s %10.4f' % ('MPI stp', f)), '[', ' '.join([('%10.4f' % a) for a in x]), ']')
                d = None
            else:
                (f, g, d) = target_evaluator.compute_functional_gradients_diag()
                if (diag_mode == 'once'):
                    diag_mode = None
            if (f_min is None):
                if (not termination_params.traditional_convergence_test):
                    is_converged(f)
                (f_min, x_min) = (f, x.deep_copy())
            elif (f_min > f):
                (f_min, x_min) = (f, x.deep_copy())
            if (log is not None):
                print(('lbfgs minimizer.run(): f=%.6g, |g|=%.6g, x_min=%.6g, x_mean=%.6g, x_max=%.6g' % (f, g.norm(), flex.min(x), flex.mean(x), flex.max(x))), file=log)
            if (d is None):
                if minimizer.run(x, f, g, gradient_only, line_search):
                    continue
            elif minimizer.run(x, f, g, d, gradient_only, line_search):
                continue
            if (log is not None):
                print('lbfgs minimizer step', file=log)
            if (callback_after_step is not None):
                if (callback_after_step(minimizer) is True):
                    if (log is not None):
                        print('lbfgs minimizer stop: callback_after_step is True', file=log)
                    break
            if termination_params.traditional_convergence_test:
                if ((minimizer.iter() >= termination_params.min_iterations) and is_converged(x, g)):
                    if (log is not None):
                        print('lbfgs minimizer stop: traditional_convergence_test', file=log)
                    break
            elif is_converged(f):
                if (log is not None):
                    print('lbfgs minimizer stop: drop_convergence_test', file=log)
                break
            if ((termination_params.max_iterations is not None) and (minimizer.iter() >= termination_params.max_iterations)):
                if (log is not None):
                    print('lbfgs minimizer stop: max_iterations', file=log)
                break
            if ((termination_params.max_calls is not None) and (minimizer.nfun() > termination_params.max_calls)):
                if (log is not None):
                    print('lbfgs minimizer stop: max_calls', file=log)
                break
            if (d is None):
                if (not minimizer.run(x, f, g, gradient_only, line_search)):
                    break
            elif (not minimizer.run(x, f, g, d, gradient_only, line_search)):
                break
    except RuntimeError as e:
        minimizer.error = str(e)
        if (log is not None):
            print('lbfgs minimizer exception:', str(e), file=log)
        if (x_min is not None):
            x.clear()
            x.extend(x_min)
        error_classification = exception_handling_params.filter(minimizer.error, x.size(), x, g)
        if (error_classification > 0):
            raise
        elif (error_classification < 0):
            minimizer.is_unusual_error = True
        else:
            minimizer.is_unusual_error = False
    else:
        minimizer.error = None
        minimizer.is_unusual_error = None
    if (log is not None):
        print('lbfgs minimizer done.', file=log)
    return minimizer