Changeset be43e39 in sasmodels for sasmodels/generate.py
- Timestamp:
- Oct 19, 2018 5:49:12 PM (6 years ago)
- 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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/generate.py
r6e45516 re44432d 671 671 672 672 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*[(]", 675 674 flags=re.MULTILINE) 676 675 def find_xy_mode(source): … … 701 700 return 'qa' 702 701 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) 706 def 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) 718 def 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 703 728 704 729 def _add_source(source, code, path, lineno=1): … … 730 755 # dispersion. Need to be careful that necessary parameters are available 731 756 # for computing volume even if we allow non-disperse volume parameters. 732 733 757 partable = model_info.parameters 734 758 … … 743 767 for path, code in user_code: 744 768 _add_source(source, code, path) 745 746 769 if model_info.c_code: 747 770 _add_source(source, model_info.c_code, model_info.filename, … … 751 774 q, qx, qy, qab, qa, qb, qc \ 752 775 = [Parameter(name=v) for v in 'q qx qy qab qa qb qc'.split()] 776 753 777 # Generate form_volume function, etc. from body only 754 778 if isinstance(model_info.form_volume, str): 755 779 pars = partable.form_volume_parameters 756 780 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)) 757 784 if isinstance(model_info.Iq, str): 758 785 pars = [q] + partable.iq_parameters … … 767 794 pars = [qa, qb, qc] + partable.iq_parameters 768 795 source.append(_gen_fn(model_info, 'Iqabc', pars)) 796 797 # Check for shell_volume in source 798 is_hollow = contains_shell_volume(source) 769 799 770 800 # What kind of 2D model do we need? Is it consistent with the parameters? … … 789 819 source.append("\\\n".join(p.as_definition() 790 820 for p in partable.kernel_parameters)) 791 792 821 # Define the function calls 822 call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(_mode, _v) 0.0" 793 823 if partable.form_volume_parameters: 794 824 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)) 796 831 else: 797 832 # Model doesn't have volume. We could make the kernel run a little 798 833 # faster by not using/transferring the volume normalizations, but 799 834 # 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)" 801 836 source.append(call_volume) 802 837 source.append(call_effective_radius) 803 838 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" 806 848 if xy_mode == 'qabc': 807 849 pars = ",".join(["_qa", "_qb", "_qc"] + model_refs) … … 812 854 call_iqxy = "#define CALL_IQ_AC(_qa,_qc,_v) Iqac(%s)" % pars 813 855 clear_iqxy = "#undef CALL_IQ_AC" 814 elif xy_mode == 'qa' :856 elif xy_mode == 'qa' and not model_info.have_Fq: 815 857 pars = ",".join(["_qa"] + model_refs) 816 858 call_iqxy = "#define CALL_IQ_A(_qa,_v) Iq(%s)" % pars 817 859 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" 818 868 elif xy_mode == 'qxy': 819 869 orientation_refs = _call_pars("_v.", partable.orientation_parameters) … … 831 881 magpars = [k-2 for k, p in enumerate(partable.call_parameters) 832 882 if p.type == 'sld'] 833 834 883 # Fill in definitions for numbers of parameters 835 884 source.append("#define MAX_PD %s"%partable.max_pd) … … 839 888 source.append("#define MAGNETIC_PARS %s"%",".join(str(k) for k in magpars)) 840 889 source.append("#define PROJECTION %d"%PROJECTION) 841 842 890 # 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 846 894 result = { 847 895 'dll': '\n'.join(source+dll[0]+dll[1]+dll[2]), 848 896 'opencl': '\n'.join(source+ocl[0]+ocl[1]+ocl[2]), 849 897 } 850 851 898 return result 852 899 853 900 854 def _kernels(kernel, call_iq, c all_iqxy, clear_iqxy, name):901 def _kernels(kernel, call_iq, clear_iq, call_iqxy, clear_iqxy, name): 855 902 # type: ([str,str], str, str, str) -> List[str] 856 903 code = kernel[0] … … 862 909 '#line 1 "%s Iq"' % path, 863 910 code, 864 "#undef CALL_IQ",911 clear_iq, 865 912 "#undef KERNEL_NAME", 866 913 ]
Note: See TracChangeset
for help on using the changeset viewer.