def computeContacts(mut, contacts, denominator_cons, denominator_cen, outf):
    # for each contact, compute two separated values for wild type and mutant
    contacts_keys = [x for x in contacts.keys() if x.split(",")[1].isdigit()]
    contacts_keys = sorted(contacts_keys, key=lambda x: int(x.split(",")[1]))
    idx = 1
    outfh = open(outf, "w")
    normal_cmap = args.sdir + "/" + mut.p.lower() + ".clean.cmap"

    for con in contacts_keys:
        numerator_w = sum([float(x.split()[1]) for x in contacts[con] if x.split()[0] == mut.w])
        numerator_m = sum([float(x.split()[1]) for x in contacts[con] if x.split()[0] == mut.m])
        if numerator_w == 0:
            contactdegree_w = 0
        else:
            denominator_cen_w = [x for x in denominator_cen if x.split()[0] == PDB.s2t(mut.w)][0].split()[1:]
            denominator_con = denominator_cons[con].split()[1:]
            denominator_w = 0
            for p1, p2 in itertools.product(denominator_cen_w[1:], denominator_con[1:]):
                denominator_w += float(p1) * float(p2)
            denominator_w *= float(denominator_cen_w[0]) * float(denominator_con[0])
            contactdegree_w = numerator_w / denominator_w
        if numerator_m == 0:
            contactdegree_m = 0
        else:
            denominator_cen_m = [x for x in denominator_cen if x.split()[0] == PDB.s2t(mut.m)][0].split()[1:]
            denominator_con = denominator_cons[con].split()[1:]
            denominator_m = 0
            for p1, p2 in itertools.product(denominator_cen_m[1:], denominator_con[1:]):
                denominator_m += float(p1) * float(p2)
            denominator_m *= float(denominator_cen_m[0]) * float(denominator_con[0])
            contactdegree_m = numerator_m / denominator_m
        contactdegree_w, contactdegree_m = format(contactdegree_w, ".4f"), format(contactdegree_m, ".4f")

        # also add normal contact degree between these two position:
        normal_cond = Fragment.getConD(normal_cmap, mut.c + "," + str(mut.n), con)
        normal_cond = format(normal_cond, ".4f")

        outstring = (
            "\t".join(
                map(
                    str,
                    [
                        idx,
                        mut.p,
                        mut.c + "," + str(mut.n),
                        con,
                        contactdegree_w,
                        contactdegree_m,
                        normal_cond,
                        denominator_cons[con].split()[0],
                    ],
                )
            )
            + "\n"
        )
        idx += 1
        outfh.write(outstring)

        # there could be some contacts which are not detected by two side chains
    normal_cons, normal_conress = Fragment.contactList(normal_cmap, mut.c, mut.n, dcut=0.01)
    for k in range(len(normal_cons)):
        if normal_cons[k] in contacts_keys:  # already indexed contact
            continue
        else:
            normal_cond = Fragment.getConD(normal_cmap, mut.c + "," + str(mut.n), normal_cons[k])
            normal_cond = format(normal_cond, ".4f")
            outstring = (
                "\t".join(
                    map(
                        str,
                        [
                            idx,
                            mut.p,
                            mut.c + "," + str(mut.n),
                            normal_cons[k],
                            0.0000,
                            0.0000,
                            normal_cond,
                            normal_conress[k],
                        ],
                    )
                )
                + "\n"
            )
            idx += 1
            outfh.write(outstring)

            # it would be also nice to have permanent contact, but they are rare and probably captured by environment

    outfh.close()