def Sim(data,VARS=VARS):
    VARS=VARS
    F =[]
    beta=rgh.beta
    total_wt=0
    domain={}

    for i in range(DOMAIN_NUMBER):
        #do this part by fitting u and OC instead
        #extract the fitting par values in the associated attribute and then do the scaling(initiation+processing, actually update the fitting parameter values)
        #VARS['domain_class_'+str(int(i+1))].init_sim_batch(batch_path_head+VARS['sim_batch_file_domain'+str(int(i+1))])
        #VARS['domain_class_'+str(int(i+1))].scale_opt_batch(batch_path_head+VARS['scale_operation_file_domain'+str(int(i+1))])
        
        #create matching lib dynamically during fitting
        if USE_BV:
            vars()['match_lib_fitting_'+str(i+1)+'A'],vars()['match_lib_fitting_'+str(i+1)+'B']=deepcopy(VARS['match_lib_'+str(i+1)+'A']),deepcopy(VARS['match_lib_'+str(i+1)+'B'])
            create_match_lib_during_fitting(domain_class=VARS['domain_class_'+str(int(i+1))],domain=VARS['domain'+str(int(i+1))+'A'],atm_list=VARS['atm_list_'+str(int(i+1))+'A'],pb_list=VARS['pb_list_domain'+str(int(i+1))+'a'],HO_list=VARS['HO_list_domain'+str(int(i+1))+'a'],match_lib=vars()['match_lib_fitting_'+str(int(i+1))+'A'])
        
        #grap wt for each domain and cal the total wt
        vars()['wt_domain'+str(int(i+1))]=VARS['rgh_domain'+str(int(i+1))].wt
        total_wt=total_wt+vars()['wt_domain'+str(int(i+1))]

        #update sorbates
        for j in range(VARS['Pb_NUMBER'][i]):
            pb_coors_a=[]
            O_coors_a=[]
            if len(VARS['Pb_ATTACH_ATOM'][i][j])==1:#monodentate case
                phi=getattr(VARS['rgh_domain'+str(int(i+1))],'phi')
                r=getattr(VARS['rgh_domain'+str(int(i+1))],'r')
                ids=[VARS['Pb_ATTACH_ATOM'][i][j][0]+'_D'+str(int(i+1))+'A']
                offset=VARS['Pb_ATTACH_ATOM_OFFSET'][i][j][0]
                pb_id=VARS['pb_list_domain'+str(int(i+1))+'a'][j]#pb_id is a str NOT list
                O_index=[0]+[sum(VARS['O_NUMBER'][i][0:ii+1]) for ii in range(len(VARS['O_NUMBER'][i]))]
                #for [1,2,2], which means inside one domain there are 1OH corresponding to pb1, 2 OH's corresponding to pb2 and so son.
                #will return [0,1,3,5], O_id extract OH according to O_index
                O_id=VARS['HO_list_domain'+str(int(i+1))+'a'][O_index[j]:O_index[j+1]]#O_ide is a list of str
                sorbate_coors=VARS['domain_class_'+str(int(i+1))].adding_sorbate_bipyramid_monodentate(domain=VARS['domain'+str(int(i+1))+'A'],phi=phi,r=r,attach_atm_id=ids,offset=offset,pb_id=pb_id,O_id=O_id)           
                pb_coors_a.append(sorbate_coors[0])
                [O_coors_a.append(sorbate_coors[k]) for k in range(len(sorbate_coors))[1:]]
                pb_id_B=VARS['pb_list_domain'+str(int(i+1))+'b'][j]
                O_id_B=VARS['HO_list_domain'+str(int(i+1))+'b'][O_index[j]:O_index[j+1]]
                #now put on sorbate on the symmetrically related domain
                sorbate_ids=[pb_id_B]+O_id_B
                sorbate_els=['Pb']+['O']*(len(O_id_B))
                add_atom(domain=VARS['domain'+str(int(i+1))+'B'],ref_coor=np.array(pb_coors_a+O_coors_a)*[-1,1,1]-[-1.,0.06955,0.5],ids=sorbate_ids,els=sorbate_els)
            elif len(VARS['Pb_ATTACH_ATOM'][i][j])==2:#bidentate case
                theta=getattr(VARS['rgh_domain'+str(int(i+1))],'theta')
                phi=getattr(VARS['rgh_domain'+str(int(i+1))],'phi')
                ids=[VARS['Pb_ATTACH_ATOM'][i][j][0]+'_D'+str(int(i+1))+'A',VARS['Pb_ATTACH_ATOM'][i][j][1]+'_D'+str(int(i+1))+'A']
                offset=VARS['Pb_ATTACH_ATOM_OFFSET'][i][j]
                pb_id=VARS['pb_list_domain'+str(int(i+1))+'a'][j]
                O_index=[0]+[sum(VARS['O_NUMBER'][i][0:ii+1]) for ii in range(len(VARS['O_NUMBER'][i]))]
                O_id=VARS['HO_list_domain'+str(int(i+1))+'a'][O_index[j]:O_index[j+1]]
                sorbate_coors=VARS['domain_class_'+str(int(i+1))].adding_sorbate_trigonal_bipyramid(domain=VARS['domain'+str(int(i+1))+'A'],theta=theta,phi=phi,flag=VARS['FLAG'][i][j],extend_flag=VARS['ED_FLAG'][i][j],attach_atm_ids=ids,offset=offset,pb_id=pb_id,O_id=O_id,mirror=VARS['MIRROR'])
                pb_coors_a.append(sorbate_coors[0])
                [O_coors_a.append(sorbate_coors[k]) for k in range(len(sorbate_coors))[1:]]
                pb_id_B=VARS['pb_list_domain'+str(int(i+1))+'b'][j]
                O_id_B=VARS['HO_list_domain'+str(int(i+1))+'b'][O_index[j]:O_index[j+1]]
                #now put on sorbate on the symmetrically related domain
                sorbate_ids=[pb_id_B]+O_id_B
                sorbate_els=['Pb']+['O']*(len(O_id_B))
                add_atom(domain=VARS['domain'+str(int(i+1))+'B'],ref_coor=np.array(pb_coors_a+O_coors_a)*[-1,1,1]-[-1.,0.06955,0.5],ids=sorbate_ids,els=sorbate_els)
            elif len(VARS['Pb_ATTACH_ATOM'][i][j])==3:#tridentate case (no oxygen sorbate here considering it is a trigonal pyramid structure)
                ids=[VARS['Pb_ATTACH_ATOM'][i][j][0]+'_D'+str(int(i+1))+'A',VARS['Pb_ATTACH_ATOM'][i][j][1]+'_D'+str(int(i+1))+'A',VARS['Pb_ATTACH_ATOM'][i][j][2]+'_D'+str(int(i+1))+'A']
                offset=VARS['Pb_ATTACH_ATOM_OFFSET'][i][j]
                pb_id=VARS['pb_list_domain'+str(int(i+1))+'a'][j]
                O_index=[0]+[sum(VARS['O_NUMBER'][i][0:ii+1]) for ii in range(len(VARS['O_NUMBER'][i]))]
                O_id=VARS['HO_list_domain'+str(int(i+1))+'a'][O_index[j]:O_index[j+1]]
                sorbate_coors=VARS['domain_class_'+str(int(i+1))].adding_share_triple_trigonal_bipyramid(domain=VARS['domain'+str(int(i+1))+'A'],attach_atm_ids_ref=ids[0:2],attach_atm_id_third=[ids[-1]],offset=offset,sorbate_id=pb_id,sorbate_oxygen_ids=O_id)
                pb_coors_a.append(sorbate_coors[0])
                [O_coors_a.append(sorbate_coors[k]) for k in range(len(sorbate_coors))[1:]]
                pb_id_B=VARS['pb_list_domain'+str(int(i+1))+'b'][j]
                O_id_B=VARS['HO_list_domain'+str(int(i+1))+'b'][O_index[j]:O_index[j+1]]
                #now put on sorbate on the symmetrically related domain
                sorbate_ids=[pb_id_B]+O_id_B
                sorbate_els=['Pb']+['O']*(len(O_id_B))
                add_atom(domain=VARS['domain'+str(int(i+1))+'B'],ref_coor=np.array(pb_coors_a+O_coors_a)*[-1,1,1]-[-1.,0.06955,0.5],ids=sorbate_ids,els=sorbate_els)    
    #set up multiple domains
    #note for each domain there are two sub domains which symmetrically related to each other, so have equivalent wt
    for i in range(DOMAIN_NUMBER):
        domain['domain'+str(int(i+1))+'A']={'slab':VARS['domain'+str(int(i+1))+'A'],'wt':0.5*vars()['wt_domain'+str(int(i+1))]/total_wt}
        domain['domain'+str(int(i+1))+'B']={'slab':VARS['domain'+str(int(i+1))+'B'],'wt':0.5*vars()['wt_domain'+str(int(i+1))]/total_wt}
    
    #set up sample
    sample = model.Sample(inst, bulk, domain, unitcell,coherence=False,surface_parms={'delta1':0.,'delta2':0.1391})

    #bond valence won't be integrated as part of data sets, but you can print out to check the bv as one of the post-fitting work
    if USE_BV:
        bond_valence=[domain_class_1.cal_bond_valence3(domain=VARS['domain'+str(i+1)+'A'],match_lib=vars()['match_lib_fitting_'+str(i+1)+'A']) for i in range(DOMAIN_NUMBER)]
        for bv in bond_valence:
            for key in bv.keys():
                print "%s\t%5.3f\n"%(key,bv[key])
    
    #cal structure factor for each dataset in this for loop
    for data_set in data:
        h = data_set.extra_data['h']
        k = data_set.extra_data['k']
        l = data_set.extra_data['l']
        LB = data_set.extra_data['LB']
        dL = data_set.extra_data['dL']
        rough = (1-beta)/((1-beta)**2 + 4*beta*np.sin(np.pi*(l-LB)/dL)**2)**0.5#roughness model, double check LB and dL values are correctly set up in data file
        f = rough*sample.calc_f(h, k, l,f1f2,res_el)
        F.append(abs(f))
    #print_data(N_sorbate=4,N_atm=40,domain=domain1A,z_shift=1,save_file='D://model.xyz')    
    #export the model results for plotting if PLOT set to true
    if PLOT:
        plot_data_container_experiment={}
        plot_data_container_model={}
        for data_set in data:
            f=np.array([])   
            h = data_set.extra_data['h']
            k = data_set.extra_data['k']
            l = data_set.x
            LB = data_set.extra_data['LB']
            dL = data_set.extra_data['dL']
            I=data_set.y
            eI=data_set.error
            #make dumy hkl and f to make the plot look smoother
            l_dumy=np.arange(l[0],l[-1],0.1)
            N=len(l_dumy)
            h_dumy=np.array([h[0]]*N)
            k_dumy=np.array([k[0]]*N)
            LB_dumy=[]
            dL_dumy=[]
            for i in range(N):
                index=list(l-l_dumy[i]).index(min(l-l_dumy[i]))
                LB_dumy.append(LB[index])
                dL_dumy.append(dL[index])
            LB_dumy=np.array(LB_dumy)
            dL_dumy=np.array(dL_dumy)
            rough_dumy = (1-beta)/((1-beta)**2 + 4*beta*np.sin(np.pi*(l_dumy-LB_dumy)/dL_dumy)**2)**0.5
            f_dumy = rough_dumy*sample.calc_f(h_dumy, k_dumy, l_dumy)
            
            label=str(int(h[0]))+str(int(k[0]))+'L'
            plot_data_container_experiment[label]=np.concatenate((l[:,np.newaxis],I[:,np.newaxis],eI[:,np.newaxis]),axis=1)
            plot_data_container_model[label]=np.concatenate((l_dumy[:,np.newaxis],f_dumy[:,np.newaxis]),axis=1)
        hkls=['00L','02L','10L','11L','20L','22L','30L','2-1L','21L']
        plot_data_list=[]
        for hkl in hkls:
            plot_data_list.append([plot_data_container_experiment[hkl],plot_data_container_model[hkl]])
        pickle.dump(plot_data_list,open("D:\\Google Drive\\useful codes\\plotting\\temp_plot","wb"))
    return F
def Sim(data,VARS=VARS):
    VARS=VARS
    F =[]
    bv=0
    beta=rgh.beta
    SCALES=[getattr(rgh,scale) for scale in scales]
    total_wt=0
    domain={}

    for i in range(DOMAIN_NUMBER):
        #extract the fitting par values in the associated attribute and then do the scaling(initiation+processing, actually update the fitting parameter values)
        #VARS['domain_class_'+str(int(i+1))].init_sim_batch(batch_path_head+VARS['sim_batch_file_domain'+str(int(i+1))])
        #VARS['domain_class_'+str(int(i+1))].scale_opt_batch(batch_path_head+VARS['scale_operation_file_domain'+str(int(i+1))])
                
        #grap wt for each domain and cal the total wt
        vars()['wt_domain'+str(int(i+1))]=VARS['rgh_domain'+str(int(i+1))].wt
        total_wt=total_wt+vars()['wt_domain'+str(int(i+1))]

        #update sorbates
        for j in range(VARS['Pb_NUMBER'][i]):
            pb_coors_a=[]
            O_coors_a=[]
            if len(VARS['Pb_ATTACH_ATOM'][i][j])==1:#monodentate case
                top_angle=getattr(VARS['rgh_domain'+str(int(i+1))],'top_angle')
                phi=getattr(VARS['rgh_domain'+str(int(i+1))],'phi')
                r=getattr(VARS['rgh_domain'+str(int(i+1))],'r')
                ids=[VARS['Pb_ATTACH_ATOM'][i][j][0]+'_D'+str(int(i+1))+'A']
                offset=VARS['Pb_ATTACH_ATOM_OFFSET'][i][j]
                pb_id=VARS['pb_list_domain'+str(int(i+1))+'a'][j]#pb_id is a str NOT list
                O_index=[0]+[sum(VARS['O_NUMBER'][i][0:ii+1]) for ii in range(len(VARS['O_NUMBER'][i]))]
                #for [1,2,2], which means inside one domain there are 1OH corresponding to pb1, 2 OH's corresponding to pb2 and so son.
                #will return [0,1,3,5], O_id extract OH according to O_index
                O_id=VARS['HO_list_domain'+str(int(i+1))+'a'][O_index[j]:O_index[j+1]]#O_ide is a list of str
                sorbate_coors=VARS['domain_class_'+str(int(i+1))].adding_sorbate_pyramid_monodentate(domain=VARS['domain'+str(int(i+1))+'A'],top_angle=top_angle,phi=phi,r=r,attach_atm_ids=ids,offset=offset,pb_id=pb_id,O_id=O_id,mirror=VARS['MIRROR'])           
                pb_coors_a.append(sorbate_coors[0])
                [O_coors_a.append(sorbate_coors[k]) for k in range(len(sorbate_coors))[1:]]
                pb_id_B=VARS['pb_list_domain'+str(int(i+1))+'b'][j]
                O_id_B=VARS['HO_list_domain'+str(int(i+1))+'b'][O_index[j]:O_index[j+1]]
                #now put on sorbate on the symmetrically related domain
                sorbate_ids=[pb_id_B]+O_id_B
                sorbate_els=['Pb']+['O']*(len(O_id_B))
                add_atom(domain=VARS['domain'+str(int(i+1))+'B'],ref_coor=np.array(pb_coors_a+O_coors_a)*[-1,1,1]-[-1.,0.06955,0.5],ids=sorbate_ids,els=sorbate_els)
            elif len(VARS['Pb_ATTACH_ATOM'][i][j])==2:#bidentate case
                top_angle=getattr(VARS['rgh_domain'+str(int(i+1))],'top_angle')
                phi=getattr(VARS['rgh_domain'+str(int(i+1))],'phi')
                ids=[VARS['Pb_ATTACH_ATOM'][i][j][0]+'_D'+str(int(i+1))+'A',VARS['Pb_ATTACH_ATOM'][i][j][1]+'_D'+str(int(i+1))+'A']
                offset=VARS['Pb_ATTACH_ATOM_OFFSET'][i][j]
                pb_id=VARS['pb_list_domain'+str(int(i+1))+'a'][j]
                O_index=[0]+[sum(VARS['O_NUMBER'][i][0:ii+1]) for ii in range(len(VARS['O_NUMBER'][i]))]
                O_id=VARS['HO_list_domain'+str(int(i+1))+'a'][O_index[j]:O_index[j+1]]
                sorbate_coors=VARS['domain_class_'+str(int(i+1))].adding_sorbate_pyramid_distortion(domain=VARS['domain'+str(int(i+1))+'A'],top_angle=top_angle,phi=phi,edge_offset=[0,0],attach_atm_ids=ids,offset=offset,pb_id=pb_id,O_id=O_id,mirror=VARS['MIRROR'])
                pb_coors_a.append(sorbate_coors[0])
                [O_coors_a.append(sorbate_coors[k]) for k in range(len(sorbate_coors))[1:]]
                pb_id_B=VARS['pb_list_domain'+str(int(i+1))+'b'][j]
                O_id_B=VARS['HO_list_domain'+str(int(i+1))+'b'][O_index[j]:O_index[j+1]]
                #now put on sorbate on the symmetrically related domain
                sorbate_ids=[pb_id_B]+O_id_B
                sorbate_els=['Pb']+['O']*(len(O_id_B))
                add_atom(domain=VARS['domain'+str(int(i+1))+'B'],ref_coor=np.array(pb_coors_a+O_coors_a)*[-1,1,1]-[-1.,0.06955,0.5],ids=sorbate_ids,els=sorbate_els)
            elif len(VARS['Pb_ATTACH_ATOM'][i][j])==3:#tridentate case (no oxygen sorbate here considering it is a trigonal pyramid structure)
                r=getattr(VARS['rgh_domain'+str(int(i+1))],'r')
                ids=[VARS['Pb_ATTACH_ATOM'][i][j][0]+'_D'+str(int(i+1))+'A',VARS['Pb_ATTACH_ATOM'][i][j][1]+'_D'+str(int(i+1))+'A',VARS['Pb_ATTACH_ATOM'][i][j][2]+'_D'+str(int(i+1))+'A']
                offset=VARS['Pb_ATTACH_ATOM_OFFSET'][i][j]
                pb_id=VARS['pb_list_domain'+str(int(i+1))+'a'][j]
                sorbate_coors=VARS['domain_class_'+str(int(i+1))].adding_pb_share_triple3(domain=VARS['domain'+str(int(i+1))+'A'],r=r,attach_atm_ids=ids,offset=offset,pb_id=pb_id)
                pb_coors_a.append(sorbate_coors)
                pb_id_B=VARS['pb_list_domain'+str(int(i+1))+'b'][j]
                #now put on sorbate on the symmetrically related domain
                sorbate_ids=[pb_id_B]
                sorbate_els=['Pb']
                add_atom(domain=VARS['domain'+str(int(i+1))+'B'],ref_coor=np.array(pb_coors_a)*[-1,1,1]-[-1.,0.06955,0.5],ids=sorbate_ids,els=sorbate_els)
                #create matching lib dynamically during fitting
        
        if USE_BV:
            N_sorbate=Pb_NUMBER[i]+sum(O_NUMBER[i])
            N_water=WATER_NUMBER[i]
            domain_class=None
            #consider 6 surface atom layers plus the sorbates (not including water if any) to build super cell and remove the first iron layer if considring half layer
            #only consdier domainA since domain B is symmetry related to domainA
            if DOMAIN[i]==1:
                domain_class=VARS['domain_class_'+str(i+1)].build_super_cell2(VARS['domain'+str(i+1)+'A'],[0,1]+range(4,14)+range(-(N_sorbate+N_water),-N_water))
            elif DOMAIN[i]==2:
                domain_class=VARS['domain_class_'+str(i+1)].build_super_cell2(VARS['domain'+str(i+1)+'A'],range(0,12)+range(-(N_sorbate+N_water),-N_water))
            for key in VARS['match_lib_'+str(i+1)+'A'].keys():
                #the searching radius is 2.5A considering the bond length of Pb-O or Fe-O is less than 2.5 A
                #if the radius is set too high you may force a nonreasonable panalty to scale the bv
                temp_bv=domain_class_1.cal_bond_valence1_new2(domain_class,key,2.5,VARS['match_lib_'+str(i+1)+'A'][key],50,False)['total_valence']
                if 'O' in key:
                    #For O you may consider possible binding to proton (+0.8) or hydrogen bond (0.2) and any possible combos among them
                    #And note the maximum coordination number for O is 4
                    case_tag=len(VARS['match_lib_'+str(i+1)+'A'][key])
                    bond_valence_corrected_value=np.array([0.])
                    if ((case_tag==1.)&(temp_bv<2)):
                        bond_valence_corrected_value=np.array([1.8,1.6,1.2,1.,0.8,0.6,0.4,0.2,0.])
                    elif ((case_tag==2.)&(temp_bv<2)):
                        bond_valence_corrected_value=np.array([1.6,1.,0.8,0.4,0.2,0.])
                    elif ((case_tag==3.)&(temp_bv<2)):
                        bond_valence_corrected_value=np.array([0.8,0.2,0.])
                    else:pass
                    ref=np.sign(temp_bv+np.array(bond_valence_corrected_value)-2.)*(temp_bv+np.array(bond_valence_corrected_value)-2.)
                    temp_bv=temp_bv+bond_valence_corrected_value[np.where(ref==np.min(ref))[0][0]]
                    bv=bv+abs(2-temp_bv)
                elif 'Fe' in key:
                    bv=bv+abs(3-temp_bv)
                elif 'Pb' in key:
                    bv=bv+abs(2-temp_bv)    
    #set up multiple domains
    #note for each domain there are two sub domains which symmetrically related to each other, so have equivalent wt
    for i in range(DOMAIN_NUMBER):
        domain['domain'+str(int(i+1))+'A']={'slab':VARS['domain'+str(int(i+1))+'A'],'wt':0.5*vars()['wt_domain'+str(int(i+1))]/total_wt}
        domain['domain'+str(int(i+1))+'B']={'slab':VARS['domain'+str(int(i+1))+'B'],'wt':0.5*vars()['wt_domain'+str(int(i+1))]/total_wt}
    
    #set up sample
 
    #bond valence won't be integrated as part of data sets, but you can print out to check the bv as one of the post-fitting work
    PRINT_BV=False
    if USE_BV&PRINT_BV:
        bond_valence=[domain_class_1.cal_bond_valence3(domain=VARS['domain'+str(i+1)+'A'],match_lib=vars()['match_lib_fitting_'+str(i+1)+'A']) for i in range(DOMAIN_NUMBER)]
        for bv in bond_valence:
            for key in bv.keys():
                print "%s\t%5.3f\n"%(key,bv[key])
    
    #cal structure factor for each dataset in this for loop
    for data_set in data:
        f=np.array([])   
        h = data_set.extra_data['h']
        k = data_set.extra_data['k']
        x = data_set.x
        y = data_set.extra_data['Y']
        LB = data_set.extra_data['LB']
        dL = data_set.extra_data['dL']
        if x[0]>100:#a sign for RAXS dataset(first column is Energy which is in the order of 1000 ev)
            sample = model2.Sample(inst, bulk, domain, unitcell,coherence=False,surface_parms={'delta1':0.,'delta2':0.1391})
            rough = (1-beta)/((1-beta)**2 + 4*beta*np.sin(np.pi*(y-LB)/dL)**2)**0.5#roughness model, double check LB and dL values are correctly set up in data file
            f = SCALES[1]*rough*sample.calc_f(h, k, y,f1f2,res_el)
            F.append(abs(f))
        else:#First column is l for CTR dataset, l is a relative small number (less than 10 usually)
            sample = model.Sample(inst, bulk, domain, unitcell,coherence=False,surface_parms={'delta1':0.,'delta2':0.1391})
            rough = (1-beta)/((1-beta)**2 + 4*beta*np.sin(np.pi*(x-LB)/dL)**2)**0.5#roughness model, double check LB and dL values are correctly set up in data file
            f = SCALES[0]*rough*sample.calc_f(h, k, x)
            F.append(abs(f))
      
    #print_data(N_sorbate=6,N_atm=40,domain=domain1A,z_shift=1,half_layer=True,save_file='D://model2.xyz')    
    #export the model results for plotting if PLOT set to true
    #print domain_class_1.cal_bond_valence1(domain_class_1.build_super_cell2(domain1A,[0,1,4,5]+range(-6,0)),'Pb1_D1A',3,False)
    #print domain_class_1.cal_bond_valence1(domain_class_1.build_super_cell(domain1A),'O1_5_0_D1A',2.3,False)
    #print domain_class_1.cal_bond_valence1(domain_class_1.build_super_cell2(domain1A,[0,1,4,5]+range(-6,0)),'Pb1_D1A',3,False)
    #print domain_class_1.cal_bond_valence1_new2(domain_class_1.build_super_cell2(domain1A,[0,1,4,5]+range(-6,0)),'Pb1_D1A',3,['HO1_D1','O1_1_0','O1_2_0'],10,False)

    if PLOT:
        plot_data_container_experiment={}
        plot_data_container_model={}
        for data_set in data:
            f=np.array([])   
            h = data_set.extra_data['h']
            k = data_set.extra_data['k']
            l = data_set.x
            LB = data_set.extra_data['LB']
            dL = data_set.extra_data['dL']
            I=data_set.y
            eI=data_set.error
            #make dumy hkl and f to make the plot look smoother
            l_dumy=np.arange(l[0],l[-1],0.1)
            N=len(l_dumy)
            h_dumy=np.array([h[0]]*N)
            k_dumy=np.array([k[0]]*N)
            LB_dumy=[]
            dL_dumy=[]
            for i in range(N):
                index=list(l-l_dumy[i]).index(min(l-l_dumy[i]))
                LB_dumy.append(LB[index])
                dL_dumy.append(dL[index])
            LB_dumy=np.array(LB_dumy)
            dL_dumy=np.array(dL_dumy)
            rough_dumy = (1-beta)/((1-beta)**2 + 4*beta*np.sin(np.pi*(l_dumy-LB_dumy)/dL_dumy)**2)**0.5
            f_dumy = rough_dumy*sample.calc_f(h_dumy, k_dumy, l_dumy)
            
            label=str(int(h[0]))+str(int(k[0]))+'L'
            plot_data_container_experiment[label]=np.concatenate((l[:,np.newaxis],I[:,np.newaxis],eI[:,np.newaxis]),axis=1)
            plot_data_container_model[label]=np.concatenate((l_dumy[:,np.newaxis],f_dumy[:,np.newaxis]),axis=1)
        hkls=['00L','02L','10L','11L','20L','22L','30L','2-1L','21L']
        plot_data_list=[]
        for hkl in hkls:
            plot_data_list.append([plot_data_container_experiment[hkl],plot_data_container_model[hkl]])
        pickle.dump(plot_data_list,open("D:\\Google Drive\\useful codes\\plotting\\temp_plot","wb"))
    #you may play with the weighting rule by setting eg 2**bv, 5**bv for the wt factor, that way you are pushing the GenX to find a fit btween 
    #good fit (low wt factor) and a reasonable fit (high wt factor)
    return F,10**bv
     ids=Pb_ATTACH_ATOM[i][j][0]+'_D'+str(int(i+1))+'A'
     offset=Pb_ATTACH_ATOM_OFFSET[i][j][0]
     pb_id=vars()['pb_list_domain'+str(int(i+1))+'a'][j]#pb_id is a str NOT list
     O_index=[0]+[sum(O_NUMBER[i][0:ii+1]) for ii in range(len(O_NUMBER[i]))]
     #for [1,2,2], which means inside one domain there are 1OH corresponding to pb1, 2 OH's corresponding to pb2 and so son.
     #will return [0,1,3,5], O_id extract OH according to O_index
     O_id=vars()['HO_list_domain'+str(int(i+1))+'a'][O_index[j]:O_index[j+1]]#O_ide is a list of str
     sorbate_coors=vars()['domain_class_'+str(int(i+1))].adding_sorbate_bipyramid_monodentate(domain=vars()['domain'+str(int(i+1))+'A'],phi=PHI[i][j],r=R_S[i][j],attach_atm_id=ids,offset=offset,pb_id=pb_id,O_id=O_id)           
     pb_coors_a.append(sorbate_coors[0])
     [O_coors_a.append(sorbate_coors[k]) for k in range(len(sorbate_coors))[1:]]
     pb_id_B=vars()['pb_list_domain'+str(int(i+1))+'b'][j]
     O_id_B=vars()['HO_list_domain'+str(int(i+1))+'b'][O_index[j]:O_index[j+1]]
     #now put on sorbate on the symmetrically related domain
     sorbate_ids=[pb_id_B]+O_id_B
     sorbate_els=['Pb']+['O']*(len(O_id_B))
     add_atom(domain=vars()['domain'+str(int(i+1))+'B'],ref_coor=np.array(pb_coors_a+O_coors_a)*[-1,1,1]-[-1.,0.06955,0.5],ids=sorbate_ids,els=sorbate_els)
     #grouping sorbates (each set of Pb and HO, set the occupancy equivalent during fitting, looks like gp_sorbates_set1_D1)
     #also group the oxygen sorbate to set equivalent u during fitting (looks like gp_HO_set1_D1)
     sorbate_set_ids=[pb_id]+O_id+[pb_id_B]+O_id_B
     HO_set_ids=O_id+O_id_B
     N=len(sorbate_set_ids)/2
     M=len(O_id)
     vars()['gp_sorbates_set'+str(j+1)+'_D'+str(int(i+1))]=vars()['domain_class_'+str(int(i+1))].grouping_discrete_layer(domain=[vars()['domain'+str(int(i+1))+'A']]*N+[vars()['domain'+str(int(i+1))+'B']]*N,atom_ids=sorbate_set_ids)
     vars()['gp_HO_set'+str(j+1)+'_D'+str(int(i+1))]=vars()['domain_class_'+str(int(i+1))].grouping_discrete_layer(domain=[vars()['domain'+str(int(i+1))+'A']]*M+[vars()['domain'+str(int(i+1))+'B']]*M,atom_ids=HO_set_ids)
 elif len(Pb_ATTACH_ATOM[i][j])==2:#bidentate case
     ids=[Pb_ATTACH_ATOM[i][j][0]+'_D'+str(int(i+1))+'A',Pb_ATTACH_ATOM[i][j][1]+'_D'+str(int(i+1))+'A']
     offset=Pb_ATTACH_ATOM_OFFSET[i][j]
     pb_id=vars()['pb_list_domain'+str(int(i+1))+'a'][j]
     O_index=[0]+[sum(O_NUMBER[i][0:ii+1]) for ii in range(len(O_NUMBER[i]))]
     O_id=vars()['HO_list_domain'+str(int(i+1))+'a'][O_index[j]:O_index[j+1]]
     sorbate_coors=vars()['domain_class_'+str(int(i+1))].adding_sorbate_trigonal_bipyramid(domain=vars()['domain'+str(int(i+1))+'A'],theta=THETA[i][j],phi=PHI[i][j],flag=FLAG[i][j],extend_flag=ED_FLAG[i][j],attach_atm_ids=ids,offset=offset,pb_id=pb_id,O_id=O_id,mirror=MIRROR)
        M=len(sorbate_id_a[1:])
        vars()['gp_sorbates_set'+str(j+1)+'_D'+str(int(i+1))]=vars()['domain_class_'+str(int(i+1))].grouping_discrete_layer(domain=[vars()['domain'+str(int(i+1))+'A']]*N+[vars()['domain'+str(int(i+1))+'B']]*N,atom_ids=sorbate_set_ids)
        vars()['gp_HO_set'+str(j+1)+'_D'+str(int(i+1))]=vars()['domain_class_'+str(int(i+1))].grouping_discrete_layer(domain=[vars()['domain'+str(int(i+1))+'A']]*M+[vars()['domain'+str(int(i+1))+'B']]*M,atom_ids=HO_set_ids)

    if WATER_NUMBER[i]!=0:#add water molecules if any
        for jj in range(WATER_NUMBER[i]/2):#note will add water pair (two oxygens) each time, and you can't add single water 
            O_ids_a=vars()['Os_list_domain'+str(int(i+1))+'a'][jj*2:jj*2+2]
            O_ids_b=vars()['Os_list_domain'+str(int(i+1))+'b'][jj*2:jj*2+2]
            #set the first pb atm to be the ref atm(if you have two layers, same ref point but different height)
            H2O_coors_a=[]
            try:#anchor the first sorbate
                H2O_coors_a=vars()['domain_class_'+str(int(i+1))].add_oxygen_pair2(domain=vars()['domain'+str(int(i+1))+'A'],O_ids=O_ids_a,ref_id=vars()['pb_list_domain'+str(int(i+1))+'a'][0],v_shift=V_SHIFT[i][jj],r=R[i][jj],alpha=ALPHA[i][jj])
            except:#anchor O1 if without sorbate
                H2O_coors_a=vars()['domain_class_'+str(int(i+1))].add_oxygen_pair2(domain=vars()['domain'+str(int(i+1))+'A'],O_ids=O_ids_a,ref_id='O1_1_0_D'+str(i+1)+'A',v_shift=V_SHIFT[i][jj],r=R[i][jj],alpha=ALPHA[i][jj])

            add_atom(domain=vars()['domain'+str(int(i+1))+'B'],ref_coor=H2O_coors_a*[-1,1,1]-[-1.,0.06955,0.5],ids=O_ids_b,els=['O','O'])
            #group water molecules at each layer (set equivalent the oc and u during fitting)
            M=len(O_ids_a)
            vars()['gp_waters_set'+str(jj+1)+'_D'+str(int(i+1))]=vars()['domain_class_'+str(int(i+1))].grouping_discrete_layer(domain=[vars()['domain'+str(int(i+1))+'A']]*M+[vars()['domain'+str(int(i+1))+'B']]*M,atom_ids=O_ids_a+O_ids_b)
    #set variables
    vars()['domain_class_'+str(int(i+1))].set_new_vars(head_list=['u_o_n','u_Fe_n','oc_n'],N_list=[4,3,7])
    vars()['domain_class_'+str(int(i+1))].set_discrete_new_vars_batch(batch_path_head+vars()['discrete_vars_file_domain'+str(int(i+1))])
    
######################################do grouping###############################################
for i in range(DOMAIN_NUMBER):
    #note the grouping here is on a layer basis, ie atoms of same layer are groupped together (4 atms grouped together in sequence grouping)
    #you may group in symmetry, then atoms of same layer are not independent (and know the use_sym set to false here)
    if DOMAIN[i]==1:
        vars()['atm_gp_list_domain'+str(int(i+1))]=vars()['domain_class_'+str(int(i+1))].grouping_sequence_layer(domain=[vars()['domain'+str(int(i+1))+'A'],vars()['domain'+str(int(i+1))+'B']], first_atom_id=['O1_1_0_D'+str(int(i+1))+'A','O1_7_0_D'+str(int(i+1))+'B'],\
                                sym_file=vars()['sym_file_domain'+str(int(i+1))], id_match_in_sym=vars()['id_match_in_sym_domain'+str(int(i+1))],layers_N=10,use_sym=False)
    elif DOMAIN[i]==2: