Changeset be43e39 in sasmodels for sasmodels/generate.py


Ignore:
Timestamp:
Oct 19, 2018 5:49:12 PM (6 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
31fc4ad
Parents:
e44432d (diff), 353e899 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into beta_approx

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/generate.py

    r6e45516 re44432d  
    671671 
    672672 
    673 # type in IQXY pattern could be single, float, double, long double, ... 
    674 _IQXY_PATTERN = re.compile(r"(^|\s)double\s+I(?P<mode>q(ab?c|xy))\s*[(]", 
     673_IQXY_PATTERN = re.compile(r"(^|\s)double\s+I(?P<mode>q(ac|abc|xy))\s*[(]", 
    675674                           flags=re.MULTILINE) 
    676675def find_xy_mode(source): 
     
    701700    return 'qa' 
    702701 
     702# Note: not presently used.  Need to know whether Fq is available before 
     703# trying to compile the source.  Leave the code here in case we decide that 
     704# define have_Fq for each form factor is too tedious and error prone. 
     705_FQ_PATTERN = re.compile(r"(^|\s)void\s+Fq[(]", flags=re.MULTILINE) 
     706def contains_Fq(source): 
     707    # type: (List[str]) -> bool 
     708    """ 
     709    Return True if C source defines "void Fq(". 
     710    """ 
     711    for code in source: 
     712        m = _FQ_PATTERN.search(code) 
     713        if m is not None: 
     714            return True 
     715    return False 
     716 
     717_SHELL_VOLUME_PATTERN = re.compile(r"(^|\s)double\s+shell_volume[(]", flags=re.MULTILINE) 
     718def contains_shell_volume(source): 
     719    # type: (List[str]) -> bool 
     720    """ 
     721    Return True if C source defines "void Fq(". 
     722    """ 
     723    for code in source: 
     724        m = _SHELL_VOLUME_PATTERN.search(code) 
     725        if m is not None: 
     726            return True 
     727    return False 
    703728 
    704729def _add_source(source, code, path, lineno=1): 
     
    730755    # dispersion.  Need to be careful that necessary parameters are available 
    731756    # for computing volume even if we allow non-disperse volume parameters. 
    732  
    733757    partable = model_info.parameters 
    734758 
     
    743767    for path, code in user_code: 
    744768        _add_source(source, code, path) 
    745  
    746769    if model_info.c_code: 
    747770        _add_source(source, model_info.c_code, model_info.filename, 
     
    751774    q, qx, qy, qab, qa, qb, qc \ 
    752775        = [Parameter(name=v) for v in 'q qx qy qab qa qb qc'.split()] 
     776 
    753777    # Generate form_volume function, etc. from body only 
    754778    if isinstance(model_info.form_volume, str): 
    755779        pars = partable.form_volume_parameters 
    756780        source.append(_gen_fn(model_info, 'form_volume', pars)) 
     781    if isinstance(model_info.shell_volume, str): 
     782        pars = partable.form_volume_parameters 
     783        source.append(_gen_fn(model_info, 'shell_volume', pars)) 
    757784    if isinstance(model_info.Iq, str): 
    758785        pars = [q] + partable.iq_parameters 
     
    767794        pars = [qa, qb, qc] + partable.iq_parameters 
    768795        source.append(_gen_fn(model_info, 'Iqabc', pars)) 
     796 
     797    # Check for shell_volume in source 
     798    is_hollow = contains_shell_volume(source) 
    769799 
    770800    # What kind of 2D model do we need?  Is it consistent with the parameters? 
     
    789819    source.append("\\\n".join(p.as_definition() 
    790820                              for p in partable.kernel_parameters)) 
    791  
    792821    # Define the function calls 
     822    call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(_mode, _v) 0.0" 
    793823    if partable.form_volume_parameters: 
    794824        refs = _call_pars("_v.", partable.form_volume_parameters) 
    795         call_volume = "#define CALL_VOLUME(_v) form_volume(%s)"%(",".join(refs)) 
     825        if is_hollow: 
     826            call_volume = "#define CALL_VOLUME(_form, _shell, _v) do { _form = form_volume(%s); _shell = shell_volume(%s); } while (0)"%((",".join(refs),)*2) 
     827        else: 
     828            call_volume = "#define CALL_VOLUME(_form, _shell, _v) do { _form = _shell = form_volume(%s); } while (0)"%(",".join(refs)) 
     829        if model_info.effective_radius_type: 
     830            call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(_mode, _v) effective_radius(_mode, %s)"%(",".join(refs)) 
    796831    else: 
    797832        # Model doesn't have volume.  We could make the kernel run a little 
    798833        # faster by not using/transferring the volume normalizations, but 
    799834        # the ifdef's reduce readability more than is worthwhile. 
    800         call_volume = "#define CALL_VOLUME(v) 1.0" 
     835        call_volume = "#define CALL_VOLUME(_form, _shell, _v) do { _form = _shell = 1.0; } while (0)" 
    801836    source.append(call_volume) 
    802  
     837    source.append(call_effective_radius) 
    803838    model_refs = _call_pars("_v.", partable.iq_parameters) 
    804     pars = ",".join(["_q"] + model_refs) 
    805     call_iq = "#define CALL_IQ(_q, _v) Iq(%s)" % pars 
     839 
     840    if model_info.have_Fq: 
     841        pars = ",".join(["_q", "&_F1", "&_F2",] + model_refs) 
     842        call_iq = "#define CALL_FQ(_q, _F1, _F2, _v) Fq(%s)" % pars 
     843        clear_iq = "#undef CALL_FQ" 
     844    else: 
     845        pars = ",".join(["_q"] + model_refs) 
     846        call_iq = "#define CALL_IQ(_q, _v) Iq(%s)" % pars 
     847        clear_iq = "#undef CALL_IQ" 
    806848    if xy_mode == 'qabc': 
    807849        pars = ",".join(["_qa", "_qb", "_qc"] + model_refs) 
     
    812854        call_iqxy = "#define CALL_IQ_AC(_qa,_qc,_v) Iqac(%s)" % pars 
    813855        clear_iqxy = "#undef CALL_IQ_AC" 
    814     elif xy_mode == 'qa': 
     856    elif xy_mode == 'qa' and not model_info.have_Fq: 
    815857        pars = ",".join(["_qa"] + model_refs) 
    816858        call_iqxy = "#define CALL_IQ_A(_qa,_v) Iq(%s)" % pars 
    817859        clear_iqxy = "#undef CALL_IQ_A" 
     860    elif xy_mode == 'qa' and model_info.have_Fq: 
     861        pars = ",".join(["_qa", "&_F1", "&_F2",] + model_refs) 
     862        # Note: uses rare C construction (expr1, expr2) which computes 
     863        # expr1 then expr2 and evaluates to expr2.  This allows us to 
     864        # leave it looking like a function even though it is returning 
     865        # its values by reference. 
     866        call_iqxy = "#define CALL_FQ_A(_qa,_F1,_F2,_v) (Fq(%s),_F2)" % pars 
     867        clear_iqxy = "#undef CALL_FQ_A" 
    818868    elif xy_mode == 'qxy': 
    819869        orientation_refs = _call_pars("_v.", partable.orientation_parameters) 
     
    831881    magpars = [k-2 for k, p in enumerate(partable.call_parameters) 
    832882               if p.type == 'sld'] 
    833  
    834883    # Fill in definitions for numbers of parameters 
    835884    source.append("#define MAX_PD %s"%partable.max_pd) 
     
    839888    source.append("#define MAGNETIC_PARS %s"%",".join(str(k) for k in magpars)) 
    840889    source.append("#define PROJECTION %d"%PROJECTION) 
    841  
    842890    # TODO: allow mixed python/opencl kernels? 
    843  
    844     ocl = _kernels(kernel_code, call_iq, call_iqxy, clear_iqxy, model_info.name) 
    845     dll = _kernels(kernel_code, call_iq, call_iqxy, clear_iqxy, model_info.name) 
     891    ocl = _kernels(kernel_code, call_iq, clear_iq, call_iqxy, clear_iqxy, model_info.name) 
     892    dll = _kernels(kernel_code, call_iq, clear_iq, call_iqxy, clear_iqxy, model_info.name) 
     893 
    846894    result = { 
    847895        'dll': '\n'.join(source+dll[0]+dll[1]+dll[2]), 
    848896        'opencl': '\n'.join(source+ocl[0]+ocl[1]+ocl[2]), 
    849897    } 
    850  
    851898    return result 
    852899 
    853900 
    854 def _kernels(kernel, call_iq, call_iqxy, clear_iqxy, name): 
     901def _kernels(kernel, call_iq, clear_iq, call_iqxy, clear_iqxy, name): 
    855902    # type: ([str,str], str, str, str) -> List[str] 
    856903    code = kernel[0] 
     
    862909        '#line 1 "%s Iq"' % path, 
    863910        code, 
    864         "#undef CALL_IQ", 
     911        clear_iq, 
    865912        "#undef KERNEL_NAME", 
    866913        ] 
Note: See TracChangeset for help on using the changeset viewer.