def read_sdf_to_fb_mol(filename):
    """ read sdf file and return ForceBalance.molecule.Molecule object """
    from forcebalance.molecule import Molecule, Elements
    import numpy as np
    mol_list = read_split_mols(filename)
    assert len(mol_list) == 1, 'file contains multiple molecules'
    oe_mol = mol_list[0]
    # create a new molecule
    fb_mol = Molecule()
    # load elems
    fb_mol.elem = [Elements[a.GetAtomicNum()] for a in oe_mol.GetAtoms()]
    noa = len(fb_mol.elem)
    # load coordinates
    coords_dict = oe_mol.GetCoords()
    fb_mol.xyzs = [np.array([coords_dict[i] for i in range(noa)])]
    # load bonds
    bonds, bond_orders = [], []
    for oe_bond in oe_mol.GetBonds():
        idx_a = oe_bond.GetBgnIdx()
        idx_b = oe_bond.GetEndIdx()
        bond = (idx_a, idx_b) if idx_a <= idx_b else (idx_b, idx_a)
        bonds.append(bond)
        bond_orders.append(oe_bond.GetOrder())
    fb_mol.bonds = bonds
    fb_mol.bond_orders = bond_orders
    # load atomic formal charges
    atomic_formal_charges = [a.GetFormalCharge() for a in oe_mol.GetAtoms()]
    molecular_charge = sum(atomic_formal_charges)
    fb_mol.Data['molecular_charge'] = molecular_charge
    fb_mol.Data['atomic_formal_charges'] = atomic_formal_charges
    # set the oe_mol as one attribute
    fb_mol.oe_mol = oe_mol
    # set the cmiles id
    mapped_smiles = cmiles.utils.mol_to_smiles(oe_mol)
    fb_mol.Data['cmiles_id'] = cmiles.generator.get_molecule_ids(mapped_smiles)
    return fb_mol
def GenerateBox(pdbin, pdbout, box, nmol, tries):
    """
    Call genbox. (Confirmed working with Gromacs version 4.6.7 and 5.1.4).
    Mainly checks whether genbox ran correctly.
    
    Parameters
    ----------
    pdbin : str
        Name of input PDB file containing a single molecule.
    pdbout : str
        Name of output PDB file containing solvent box.
    box : float
        Solvent box size, should be determined previously.
    nmol : int
        Number of molecules to go into the solvent box
    tries : int
        Parameter for genbox to try inserting each molecule (tries) times

    Returns
    -------
    None
        If successful, produces "pdbout" containing solvent box.
    """
    if which('gmx'):
        gmxcmd = 'gmx insert-molecules'
    elif which('genbox'):
        gmxcmd = 'genbox'
    else:
        raise RuntimeError(
            'gmx and/or genbox not in PATH. Please source Gromacs environment variables.'
        )

    fout = open('genbox.out', 'w')
    ferr = open('genbox.err', 'w')
    subprocess.Popen(
        '%s -ci %s -o genbox.pdb -box %.3f %.3f %.3f -nmol %i -try %i' %
        (gmxcmd, pdbin, box, box, box, nmol, tries),
        shell=True,
        stdout=fout,
        stderr=ferr)
    fout.close()
    ferr.close()
    t0 = time.time()
    print("Running %s to create a solvent box..." % gmxcmd)
    print("Time elapsed: % .3f seconds" % (time.time() - t0))
    nmol_out = 0
    for line in open('genbox.err').readlines():
        if 'Output configuration contains' in line:
            nmol_out = int(line.split()[-2])
    if nmol_out == 0:
        raise RuntimeError('genbox failed to produce an output configuration')
    elif nmol_out != nmol:
        raise RuntimeError(
            'genbox failed to create a box with %i molecules (actual %i); '
            'please retry with increased box size or number of tries' %
            (nmol, nmol_out))
    else:
        # genbox throws away the CONECT records in the PDB, this operation adds them back.
        M1 = Molecule(pdbin, build_topology=False)
        M = Molecule('genbox.pdb', build_topology=False)
        solventbox_bonds = []
        # Loop over the number of molecules in the solvent box
        for i in range(nmol):
            for j in M1.bonds:
                # Add the bonds for molecule number "i" in the solvent box
                solventbox_bonds.append((j[0] + i * M1.na, j[1] + i * M1.na))
        M.bonds = solventbox_bonds
        M.write(pdbout)
        print(
            "-=# Output #=- Created %s containing solvent box with %i molecules and length %.3f"
            % (pdbout, nmol, box))