Project: s41467-024-47659-w | Function: ffs_complex (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Three-state thermodynamic equilibrium system solver for DDX3X-RNA interactions, implementing mass balance equations for ssRNA, dsRNA, free DDX3X, and DDX3X-ssRNA complex populations

**KEY TERMS:** {
  "S": "single-stranded RNA concentration",
  "D": "double-stranded RNA concentration",
  "P": "free DDX3X protein concentration",
  "PS": "DDX3X-ssRNA complex concentration",
  "CT": "total protein concentration",
  "LT": "total ligand (RNA) concentration",
  "K1": "dissociation constant for ssRNA binding (Kd)",
  "K2": "equilibrium constant for dsRNA hybridization (Km)"
}

**CONTEXT CODE:** # -*- coding: utf-8 -*-
"""
# Fitting of 19F signal intensities to the binding model
# where DDX3X binds exclusively to ssRNA in the presence of the dsRNA-ssRNA equilibrium.

# numpy ver. 1.24.3
# matplotlib ver. 3.7.1
# pandas ver. 1.5.3
# lmfit ver. 1.2.2
"""

import numpy as np
from scipy import optimize as opt
import pandas as pd
from functools import partial
import matplotlib.pyplot as plt

from lmfit import minimize, Parameters, fit_report

############################
## Import data
############################

def load_data():
    try:
        data = pd.read_csv("input.csv")
        LT = 100E-6 # Total RNA concentration

        conc = np.array(data.conc*1E-6)
        ds = np.array(data.Int_d)
        ss = np.array(data.Int_s)
        b = np.array(data.Int_b)
        return data, LT, conc, ds, ss, b
    except FileNotFoundError:
        # For testing purposes when run from different directory
        return None, 100E-6, None, None, None, None

data, LT, conc, ds, ss, b = load_data()


##############################
# Functions
##############################

def ffs_complex(q,p):
    # MASKED: Three-state thermodynamic equilibrium system solver for DDX3X-RNA interactions, implementing mass balance equations for ssRNA, dsRNA, free DDX3X, and DDX3X-ssRNA complex populations
    raise NotImplementedError("This function is masked for testing purposes.")

# Function to calculate the molar concentration terms.
# conc needs to be an array.
def modelcalc(conc,LT,K1,K2):
    
    S = np.zeros(len(conc))
    D = np.zeros(len(conc))
    P = np.zeros(len(conc))
    PS = np.zeros(len(conc))
    
    for i in range(len(conc)):
        p = [1e-6,LT/2,conc[i],1e-6]
        q = [conc[i],LT,K1,K2]
        ffs_partial = partial(ffs_complex,q)
        # Solutions are ordered according to how the initial guess vector is arranged
        S[i],D[i],P[i],PS[i] = opt.root(ffs_partial,p,method='lm').x
    return S,D,P,PS

# Function to convert the molar concentration into the NMR signal intensity
def getmag(S,D,PS,Mag_d,Mag_s,Mag_b):
    LT =  2*D + S + PS 
    Int_d = Mag_d*2*D/LT
    Int_s = Mag_s*S/LT
    Int_b = Mag_b*PS/LT
    return Int_d, Int_s, Int_b
    

####################################
# Output data frame
####################################
   
col1 = ['K1','K2','Mag_d','Mag_s','Mag_b',
        'K1_std','K2_std','Mag_d_std','Mag_s_std','Mag_b_std']

params_df = pd.DataFrame(columns=col1)
plotname = "plot"


############################
## Fitting
############################

if __name__ == "__main__":
    if data is None:
        print("No data file found - running in test mode")
        exit()

    fit_params = Parameters()
    fit_params.add('Mag_d',value=1E8,vary=True)
    fit_params.add('Mag_s',expr='Mag_d')
    fit_params.add('Mag_b',expr='Mag_d')
    
    fit_params.add('K1',value=70000,vary=True)
    fit_params.add('K2',value=24270,vary=True)
    
    def objective(fit_params):
        
        Mag_d = fit_params['Mag_d']
        Mag_s = fit_params['Mag_s']
        Mag_b = fit_params['Mag_b']
        
        K1 = fit_params['K1']
        K2 = fit_params['K2']
        
        S = np.zeros(len(conc))
        D = np.zeros(len(conc))
        P = np.zeros(len(conc))
        PS = np.zeros(len(conc))
        
        S,D,P,PS = modelcalc(conc,LT,K1,K2)
    
        Int_d,Int_s,Int_b = getmag(S,D,PS,Mag_d,Mag_s,Mag_b)
        
        return np.concatenate([ds-Int_d,ss-Int_s,b-Int_b])
    
    result = minimize(objective,fit_params,method="leastsq")   
    print(fit_report(result))
    
    with open("result.txt", 'w') as fh:
        fh.write(fit_report(result))
    
    RMSD = np.sqrt(result.chisqr/result.ndata)
    
    ###############################
    #  Calculate the best fit value
    ###############################
    
    opt_params = result.params
    
    opt_Mag_d = opt_params["Mag_d"].value 
    opt_Mag_s = opt_params["Mag_s"].value 
    opt_Mag_b = opt_params["Mag_b"].value 
    
    opt_K1 = opt_params["K1"].value 
    opt_K2 = opt_params["K2"].value 
    
    


Complete the function implementation replacing "raise NotImplementedError".