Changeset 03cac08 in sasmodels
- Timestamp:
- Mar 20, 2016 9:44:11 PM (9 years ago)
- Branches:
- master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 303d8d6
- Parents:
- d5ac45f
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/developer/calculator.rst
rd5ac45f r03cac08 7 7 - KERNEL declares a function to be available externally 8 8 - KERNEL_NAME is the name of the function being declared 9 - MAX_PD is the maximum depth of the polydispersity loop 9 10 - NPARS is the number of parameters in the kernel 10 11 - PARAMETER_TABLE is the declaration of the parameters to the kernel:: … … 29 30 double sld_solvent 30 31 31 - CALL_IQ(q, nq,i, pars) is the declaration of a call to the kernel::32 - CALL_IQ(q, i, pars) is the declaration of a call to the kernel:: 32 33 33 34 Cylinder: 34 35 35 #define CALL_IQ(q, nq, i, var) \ 36 Iq(q[i], \ 36 #define CALL_IQ(q, i, var) Iq(q[i], \ 37 37 var.length, \ 38 38 var.radius, \ … … 42 42 Multi-shell cylinder: 43 43 44 #define CALL_IQ(q, nq, i, var) \ 45 Iq(q[i], \ 44 #define CALL_IQ(q, i, var) Iq(q[i], \ 46 45 var.num_shells, \ 47 46 var.length, \ … … 50 49 var.sld_solvent) 51 50 51 Cylinder2D: 52 53 #define CALL_IQ(q, i, var) Iqxy(q[2*i], q[2*i+1], \ 54 var.length, \ 55 var.radius, \ 56 var.sld, \ 57 var.sld_solvent, \ 58 var.theta, \ 59 var.phi) 60 52 61 - CALL_VOLUME(var) is similar, but for calling the form volume:: 53 62 … … 69 78 inline bool constrained(p1, p2, p3) { return expression; } 70 79 #define INVALID(var) constrained(var.p1, var.p2, var.p3) 71 72 - IQ_FUNC could be Iq or Iqxy73 - IQ_PARS could be q[i] or q[2*i],q[2*i+1]74 80 75 81 Our design supports a limited number of polydispersity loops, wherein … … 200 206 201 207 TODO: cutoff 208 209 For accuracy we may want to introduce Kahan summation into the integration:: 210 211 212 double accumulated_error = 0.0; 213 ... 214 #if USE_KAHAN_SUMMATION 215 const double y = next - accumulated_error; 216 const double t = ret + y; 217 accumulated_error = (t - ret) - y; 218 ret = t; 219 #else 220 ret += next; 221 #endif -
sasmodels/generate.py
rd5ac45f r03cac08 236 236 237 237 TEMPLATE_ROOT = dirname(__file__) 238 239 MAX_PD = 4 238 240 239 241 F16 = np.dtype('float16') … … 420 422 return _template_cache[filename][1] 421 423 424 _FN_TEMPLATE = """\ 425 double %(name)s(%(pars)s); 426 double %(name)s(%(pars)s) { 427 %(body)s 428 } 429 430 431 """ 432 422 433 def _gen_fn(name, pars, body): 423 434 """ … … 431 442 } 432 443 """ 433 template = """\434 double %(name)s(%(pars)s);435 double %(name)s(%(pars)s) {436 %(body)s437 }438 439 440 """441 444 par_decl = ', '.join('double ' + p for p in pars) if pars else 'void' 442 return template % {'name': name, 'body': body, 'pars': par_decl} 443 444 def _gen_call_pars(name, pars): 445 name += "." 446 return ",".join(name+p for p in pars) 445 return _FN_TEMPLATE % {'name': name, 'body': body, 'pars': par_decl} 446 447 def _call_pars(prefix, pars): 448 """ 449 Return a list of *prefix.parameter* from parameter items. 450 """ 451 prefix += "." 452 return [prefix+p.name for p in pars] 453 454 _IQXY_PATTERN = re.compile("^((inline|static) )? *(double )? *Iqxy *([(]|$)", 455 flags=re.MULTILINE) 456 def _have_Iqxy(sources): 457 """ 458 Return true if any file defines Iqxy. 459 460 Note this is not a C parser, and so can be easily confused by 461 non-standard syntax. Also, it will incorrectly identify the following 462 as having Iqxy:: 463 464 /* 465 double Iqxy(qx, qy, ...) { ... fill this in later ... } 466 */ 467 468 If you want to comment out an Iqxy function, use // on the front of the 469 line instead. 470 """ 471 for code in sources: 472 if _IQXY_PATTERN.search(code): 473 return True 474 else: 475 return False 447 476 448 477 def make_source(model_info): … … 464 493 # for computing volume even if we allow non-disperse volume parameters. 465 494 466 # Load template 467 source = [load_template('kernel_header.c')] 468 469 # Load additional sources 470 source += [open(f).read() for f in model_sources(model_info)] 471 472 # Prepare defines 473 defines = [] 474 475 iq_parameters = [p.name 476 for p in model_info['parameters'][2:] # skip scale, background 477 if p.name in model_info['par_set']['1d']] 478 iqxy_parameters = [p.name 479 for p in model_info['parameters'][2:] # skip scale, background 480 if p.name in model_info['par_set']['2d']] 481 volume_parameters = model_info['par_type']['volume'] 495 # kernel_iq assumes scale and background are the first parameters; 496 # they should be first for 1d and 2d parameter lists as well. 497 assert model_info['parameters'][0].name == 'scale' 498 assert model_info['parameters'][1].name == 'background' 499 500 # Identify parameter types 501 iq_parameters = model_info['par_type']['1d'][2:] 502 iqxy_parameters = model_info['par_type']['2d'][2:] 503 vol_parameters = model_info['par_type']['volume'] 504 505 # Load templates and user code 506 kernel_header = load_template('kernel_header.c') 507 kernel_code = load_template('kernel_iq.c') 508 user_code = [open(f).read() for f in model_sources(model_info)] 509 510 # Build initial sources 511 source = [kernel_header] + user_code 482 512 483 513 # Generate form_volume function, etc. from body only 484 514 if model_info['form_volume'] is not None: 485 pnames = [p.name for p in vol ume_parameters]515 pnames = [p.name for p in vol_parameters] 486 516 source.append(_gen_fn('form_volume', pnames, model_info['form_volume'])) 487 517 if model_info['Iq'] is not None: … … 492 522 source.append(_gen_fn('Iqxy', pnames, model_info['Iqxy'])) 493 523 494 # Fill in definitions for volume parameters 495 if volume_parameters: 496 deref_vol = ",".join("v."+p.name for p in volume_parameters) 497 defines.append(('CALL_VOLUME(v)', 'form_volume(%s)\n'%deref_vol)) 524 # Define the parameter table 525 source.append("#define PARAMETER_TABLE \\") 526 source.append("\\\n ".join("double %s;"%p.name 527 for p in model_info['parameters'][2:])) 528 529 # Define the function calls 530 if vol_parameters: 531 refs = ",".join(_call_pars("v", vol_parameters)) 532 call_volume = "#define CALL_VOLUME(v) form_volume(%s)"%refs 498 533 else: 499 534 # Model doesn't have volume. We could make the kernel run a little 500 535 # faster by not using/transferring the volume normalizations, but 501 536 # the ifdef's reduce readability more than is worthwhile. 502 defines.append(('CALL_VOLUME(v)', '0.0')) 503 504 # Fill in definitions for Iq parameters 505 defines.append(('KERNEL_NAME', model_info['name'])) 506 defines.append(('IQ_PARAMETERS', ', '.join(iq_parameters))) 507 if fixed_1d: 508 defines.append(('IQ_FIXED_PARAMETER_DECLARATIONS', 509 ', \\\n '.join('const double %s' % p for p in fixed_1d))) 510 # Fill in definitions for Iqxy parameters 511 defines.append(('IQXY_KERNEL_NAME', model_info['name'] + '_Iqxy')) 512 defines.append(('IQXY_PARAMETERS', ', '.join(iqxy_parameters))) 513 if fixed_2d: 514 defines.append(('IQXY_FIXED_PARAMETER_DECLARATIONS', 515 ', \\\n '.join('const double %s' % p for p in fixed_2d))) 516 if pd_2d: 517 defines.append(('IQXY_WEIGHT_PRODUCT', 518 '*'.join(p + '_w' for p in pd_2d))) 519 defines.append(('IQXY_DISPERSION_LENGTH_DECLARATIONS', 520 ', \\\n '.join('const int N%s' % p for p in pd_2d))) 521 defines.append(('IQXY_DISPERSION_LENGTH_SUM', 522 '+'.join('N' + p for p in pd_2d))) 523 open_loops, close_loops = build_polydispersity_loops(pd_2d) 524 defines.append(('IQXY_OPEN_LOOPS', 525 open_loops.replace('\n', ' \\\n'))) 526 defines.append(('IQXY_CLOSE_LOOPS', 527 close_loops.replace('\n', ' \\\n'))) 528 # Need to know if we have a theta parameter for Iqxy; it is not there 529 # for the magnetic sphere model, for example, which has a magnetic 530 # orientation but no shape orientation. 531 if 'theta' in pd_2d: 532 defines.append(('IQXY_HAS_THETA', '1')) 533 534 #for d in defines: print(d) 535 defines = '\n'.join('#define %s %s' % (k, v) for k, v in defines) 536 sources = '\n\n'.join(source) 537 return C_KERNEL_TEMPLATE % { 538 'DEFINES': defines, 539 'SOURCES': sources, 540 } 537 call_volume = "#define CALL_VOLUME(v) 0.0" 538 source.append(call_volume) 539 540 refs = ["q[i]"] + _call_pars("v", iq_parameters) 541 call_iq = "#define CALL_IQ(q,i,v) Iq(%s)" % (",".join(refs)) 542 if _have_Iqxy(user_code): 543 # Call 2D model 544 refs = ["q[2*i]", "q[2*i+1]"] + _call_pars("v", iqxy_parameters) 545 call_iqxy = "#define CALL_IQ(q,i,v) Iqxy(%s)" % (",".join(refs)) 546 else: 547 # Call 1D model with sqrt(qx^2 + qy^2) 548 warnings.warn("Creating Iqxy = Iq(sqrt(qx^2 + qy^2))") 549 # still defined:: refs = ["q[i]"] + _call_pars("v", iq_parameters) 550 pars_sqrt = ["sqrt(q[2*i]*q[2*i]+q[2*i+1]*q[2*i+1])"] + refs[1:] 551 call_iqxy = "#define CALL_IQ(q,i,v) Iq(%s)" % (",".join(pars_sqrt)) 552 553 # Fill in definitions for numbers of parameters 554 source.append("#define MAX_PD %s"%MAX_PD) 555 source.append("#define NPARS %d"%(len(model_info['parameters'])-2)) 556 557 # TODO: allow mixed python/opencl kernels? 558 559 # define the Iq kernel 560 source.append("#define KERNEL_NAME %s_Iq"%model_info['name']) 561 source.append(call_iq) 562 source.append(kernel_code) 563 source.append("#undef CALL_IQ") 564 source.append("#undef KERNEL_NAME") 565 566 # define the Iqxy kernel from the same source with different #defines 567 source.append("#define KERNEL_NAME %s_Iqxy"%model_info['name']) 568 source.append(call_iqxy) 569 source.append(kernel_code) 570 source.append("#undef CALL_IQ") 571 source.append("#undef KERNEL_NAME") 572 573 return '\n'.join(source) 541 574 542 575 def categorize_parameters(pars): … … 588 621 } 589 622 for p in pars: 590 par_type[p.type if p.type else 'other'].append(p .name)623 par_type[p.type if p.type else 'other'].append(p) 591 624 return par_type 592 625 … … 605 638 pars = [Parameter(*p) for p in model_info['parameters']] 606 639 # Fill in the derived attributes 640 par_type = collect_types(pars) 641 par_type.update(categorize_parameters(pars)) 607 642 model_info['parameters'] = pars 608 partype = categorize_parameters(pars)609 643 model_info['limits'] = dict((p.name, p.limits) for p in pars) 610 model_info['par_type'] = collect_types(pars) 611 model_info['par_set'] = categorize_parameters(pars) 644 model_info['par_type'] = par_type 612 645 model_info['defaults'] = dict((p.name, p.default) for p in pars) 613 646 if model_info.get('demo', None) is None: 614 647 model_info['demo'] = model_info['defaults'] 615 model_info['has_2d'] = partype['orientation'] or partype['magnetic'] 648 model_info['has_2d'] = par_type['orientation'] or par_type['magnetic'] 649 650 def create_default_functions(model_info): 651 """ 652 Autogenerate missing functions, such as Iqxy from Iq. 653 654 This only works for Iqxy when Iq is written in python. :func:`make_source` 655 performs a similar role for Iq written in C. 656 """ 657 if model_info['Iq'] is not None and model_info['Iqxy'] is None: 658 if model_info['par_type']['1d'] != model_info['par_type']['2d']: 659 raise ValueError("Iqxy model is missing") 660 Iq = model_info['Iq'] 661 def Iqxy(qx, qy, **kw): 662 return Iq(np.sqrt(qx**2 + qy**2), **kw) 663 model_info['Iqxy'] = Iqxy 616 664 617 665 def make_model_info(kernel_module): … … 693 741 functions = "ER VR form_volume Iq Iqxy shape sesans".split() 694 742 model_info.update((k, getattr(kernel_module, k, None)) for k in functions) 743 create_default_functions(model_info) 695 744 return model_info 696 745 -
sasmodels/kernel_header.c
r2e44ac7 r03cac08 1 1 #ifdef __OPENCL_VERSION__ 2 2 # define USE_OPENCL 3 #elif defined(_OPENMP) 4 # define USE_OPENMP 3 5 #endif 4 5 #define USE_KAHAN_SUMMATION 06 6 7 7 // If opencl is not available, then we are compiling a C function … … 16 16 #include <float.h> 17 17 #define kernel extern "C" __declspec( dllexport ) 18 inlinedouble trunc(double x) { return x>=0?floor(x):-floor(-x); }19 inlinedouble fmin(double x, double y) { return x>y ? y : x; }20 inlinedouble fmax(double x, double y) { return x<y ? y : x; }21 inlinedouble isnan(double x) { return _isnan(x); }18 static double trunc(double x) { return x>=0?floor(x):-floor(-x); } 19 static double fmin(double x, double y) { return x>y ? y : x; } 20 static double fmax(double x, double y) { return x<y ? y : x; } 21 static double isnan(double x) { return _isnan(x); } 22 22 #define NAN (std::numeric_limits<double>::quiet_NaN()) // non-signalling NaN 23 23 static double cephes_expm1(double x) { … … 48 48 #define kernel extern "C" 49 49 #endif 50 inlinevoid SINCOS(double angle, double &svar, double &cvar) { svar=sin(angle); cvar=cos(angle); }50 static void SINCOS(double angle, double &svar, double &cvar) { svar=sin(angle); cvar=cos(angle); } 51 51 # else 52 52 #include <stdio.h> … … 99 99 # define M_4PI_3 4.18879020478639 100 100 #endif 101 //inline double square(double x) { return pow(x,2.0); } 102 //inline double square(double x) { return pown(x,2); } 103 inline double square(double x) { return x*x; } 104 inline double cube(double x) { return x*x*x; } 105 inline double sinc(double x) { return x==0 ? 1.0 : sin(x)/x; } 101 static double square(double x) { return x*x; } 102 static double cube(double x) { return x*x*x; } 103 static double sinc(double x) { return x==0 ? 1.0 : sin(x)/x; } 106 104 -
sasmodels/kernel_iq.c
rd5ac45f r03cac08 12 12 */ 13 13 14 #ifndef _PAR_BLOCK_ // protected block so we can include this code twice. 15 #define _PAR_BLOCK_ 14 16 15 17 #define MAX_PD 4 // MAX_PD is the max number of polydisperse parameters 16 #define PD_2N 16 // PD_2N is the size of the coordination step table17 18 18 19 typedef struct { … … 31 32 32 33 typedef struct { 33 PARAMETER_ DECL;34 PARAMETER_TABLE; 34 35 } ParameterBlock; 35 36 #define FULL_KERNEL_NAME KERNEL_NAME ## _ ## IQ_FUNC 37 KERNEL 38 void FULL_KERNEL_NAME( 36 #endif 37 38 39 kernel 40 void KERNEL_NAME( 39 41 int nq, // number of q values 40 42 global const ProblemDetails *problem, … … 42 44 global const double *pars, 43 45 global const double *q, // nq q values, with padding to boundary 44 global double *result, // nq return values, again with padding46 global double *result, // nq+3 return values, again with padding 45 47 const double cutoff, // cutoff in the polydispersity weight product 46 48 const int pd_start, // where we are in the polydispersity loop 47 const int pd_stop ,// where we are stopping in the polydispersity loop49 const int pd_stop // where we are stopping in the polydispersity loop 48 50 ) 49 51 { … … 52 54 // walk the polydispersity cube. 53 55 local ParameterBlock local_pars; // current parameter values 54 const double *parvec = &local_pars; // Alias named parameters with a vector56 double *pvec = (double *)(&local_pars); // Alias named parameters with a vector 55 57 56 58 local int offset[NPARS-2]; … … 60 62 // Shouldn't need to copy!! 61 63 for (int k=0; k < NPARS; k++) { 62 p arvec[k] = pars[k+2]; // skip scale and background64 pvec[k] = pars[k+2]; // skip scale and background 63 65 } 64 66 … … 68 70 for (int i=0; i < nq; i++) { 69 71 { 70 const double scattering = IQ_FUNC(IQ_PARS, IQ_PARAMETERS);72 const double scattering = CALL_IQ(q, i, local_pars); 71 73 result[i] += pars[0]*scattering + pars[1]; 72 74 } … … 99 101 norm = result[nq]; 100 102 vol = result[nq+1]; 101 norm_vol = result s[nq+2];103 norm_vol = result[nq+2]; 102 104 } 103 105 104 106 // Location in the polydispersity hypercube, one index per dimension. 105 local int pd_index[ PD_MAX];107 local int pd_index[MAX_PD]; 106 108 107 109 // Trigger the reset behaviour that happens at the end the fast loop 108 110 // by setting the initial index >= weight vector length. 109 pd_index[0] = pd_length[0]; 111 pd_index[0] = problem->pd_length[0]; 112 110 113 111 114 // need product of weights at every Iq calc, so keep product of … … 120 123 for (int loop_index=pd_start; loop_index < pd_stop; loop_index++) { 121 124 // check if indices need to be updated 122 if (pd_index[0] >= p d_length[0]) {125 if (pd_index[0] >= problem->pd_length[0]) { 123 126 124 127 // RESET INDICES 125 pd_index[0] = loop_index%p d_length[0];128 pd_index[0] = loop_index%problem->pd_length[0]; 126 129 partial_weight = 1.0; 127 130 partial_volweight = 1.0; 128 131 for (int k=1; k < MAX_PD; k++) { 129 pd_index[k] = (loop_index%p d_length[k])/pd_stride[k];130 const double wi = weights[p d_offset[0]+pd_index[0]];132 pd_index[k] = (loop_index%problem->pd_length[k])/problem->pd_stride[k]; 133 const double wi = weights[problem->pd_offset[0]+pd_index[0]]; 131 134 partial_weight *= wi; 132 if (p d_isvol[k]) partial_volweight *= wi;135 if (problem->pd_isvol[k]) partial_volweight *= wi; 133 136 } 134 137 for (int k=0; k < NPARS; k++) { 135 int coord = p ar_coord[k];136 int this_offset = p ar_offset[k];138 int coord = problem->par_coord[k]; 139 int this_offset = problem->par_offset[k]; 137 140 int block_size = 1; 138 141 for (int bit=0; bit < MAX_PD && coord != 0; bit++) { 139 142 if (coord&1) { 140 143 this_offset += block_size * pd_index[bit]; 141 block_size *= p d_length[bit];144 block_size *= problem->pd_length[bit]; 142 145 } 143 146 coord /= 2; 144 147 } 145 148 offset[k] = this_offset; 146 parvec[k] = pars[this_offset]; 147 } 148 weight = partial_weight * weights[pd_offset[0]+pd_index[0]] 149 if (theta_var >= 0) { 150 spherical_correction = fabs(cos(M_PI_180*parvec[theta_var])); 151 } 152 if (!fast_theta) weight *= spherical_correction; 149 pvec[k] = pars[this_offset]; 150 } 151 weight = partial_weight * weights[problem->pd_offset[0]+pd_index[0]]; 152 if (problem->theta_var >= 0) { 153 spherical_correction = fabs(cos(M_PI_180*pvec[problem->theta_var])); 154 } 155 if (!problem->fast_theta) { 156 weight *= spherical_correction; 157 } 153 158 154 159 } else { … … 156 161 // INCREMENT INDICES 157 162 pd_index[0] += 1; 158 const double wi = weights[p d_offset[0]+pd_index[0]];163 const double wi = weights[problem->pd_offset[0]+pd_index[0]]; 159 164 weight = partial_weight*wi; 160 if (p d_isvol[0]) vol_weight *= wi;165 if (problem->pd_isvol[0]) vol_weight *= wi; 161 166 for (int k=0; k < problem->fast_coord_count; k++) { 162 parvec[ fast_coord_index[k]] 163 = pars[offset[fast_coord_index[k]] + pd_index[0]]; 164 } 165 if (fast_theta) weight *= fabs(cos(M_PI_180*parvec[theta_var])); 166 167 pvec[problem->fast_coord_index[k]] 168 = pars[offset[problem->fast_coord_index[k]]++]; 169 } 170 if (problem->fast_theta) { 171 weight *= fabs(cos(M_PI_180*pvec[problem->theta_var])); 172 } 167 173 } 168 174 … … 180 186 #endif 181 187 for (int i=0; i < nq; i++) { 182 { 183 const double scattering = CALL_IQ(q, nq, i, local_pars); 188 const double scattering = CALL_IQ(q, i, local_pars); 184 189 result[i] += weight*scattering; 185 190 } 191 } 186 192 } 187 193 //Makes a normalization avialable for the next round … … 191 197 192 198 //End of the PD loop we can normalize 193 if (pd_stop == pd_stride[MAX_PD-1]) {}199 if (pd_stop >= problem->pd_stride[MAX_PD-1]) { 194 200 #ifdef USE_OPENMP 195 201 #pragma omp parallel for -
sasmodels/kerneldll.py
r17bbadd r03cac08 61 61 if sys.platform == 'darwin': 62 62 #COMPILE = "gcc-mp-4.7 -shared -fPIC -std=c99 -fopenmp -O2 -Wall %s -o %s -lm -lgomp" 63 COMPILE = "gcc -shared -fPIC -std=c99 -O2 -Wall %(source)s -o %(output)s -lm "63 COMPILE = "gcc -shared -fPIC -std=c99 -O2 -Wall %(source)s -o %(output)s -lm -fno-unknown-pragmas" 64 64 elif os.name == 'nt': 65 65 # call vcvarsall.bat before compiling to set path, headers, libs, etc. … … 80 80 COMPILE = "gcc -shared -fPIC -std=c99 -O2 -Wall %(source)s -o %(output)s -lm" 81 81 if "SAS_OPENMP" in os.environ: 82 COMPILE = COMPILE + " -fopenmp" 82 COMPILE += " -fopenmp" 83 else: 84 COMPILE += " -fWno-unknown-pragmas" 83 85 else: 84 86 COMPILE = "cc -shared -fPIC -fopenmp -std=c99 -O2 -Wall %(source)s -o %(output)s -lm" -
sasmodels/models/cylinder.c
r50e1e40 r03cac08 3 3 double Iqxy(double qx, double qy, double sld, double solvent_sld, 4 4 double radius, double length, double theta, double phi); 5 6 #define INVALID(v) (v.radius<0 || v.length<0) 5 7 6 8 double form_volume(double radius, double length) … … 15 17 double length) 16 18 { 17 // TODO: return NaN if radius<0 or length<0?18 19 // precompute qr and qh to save time in the loop 19 20 const double qr = q*radius; … … 47 48 double phi) 48 49 { 49 // TODO: return NaN if radius<0 or length<0?50 50 double sn, cn; // slots to hold sincos function output 51 51 -
sasmodels/models/gel_fit.c
r30b4ddf r03cac08 1 double form_volume(void); 2 3 double Iq(double q, 4 double guinier_scale, 5 double lorentzian_scale, 6 double gyration_radius, 7 double fractal_exp, 8 double cor_length); 9 10 double Iqxy(double qx, double qy, 11 double guinier_scale, 12 double lorentzian_scale, 13 double gyration_radius, 14 double fractal_exp, 15 double cor_length); 16 17 static double _gel_fit_kernel(double q, 1 static double Iq(double q, 18 2 double guinier_scale, 19 3 double lorentzian_scale, … … 24 8 // Lorentzian Term 25 9 ////////////////////////double a(x[i]*x[i]*zeta*zeta); 26 double lorentzian_term = q*q*cor_length*cor_length;10 double lorentzian_term = square(q*cor_length); 27 11 lorentzian_term = 1.0 + ((fractal_exp + 1.0)/3.0)*lorentzian_term; 28 12 lorentzian_term = pow(lorentzian_term, (fractal_exp/2.0) ); … … 30 14 // Exponential Term 31 15 ////////////////////////double d(x[i]*x[i]*rg*rg); 32 double exp_term = q*q*gyration_radius*gyration_radius;16 double exp_term = square(q*gyration_radius); 33 17 exp_term = exp(-1.0*(exp_term/3.0)); 34 18 … … 37 21 return result; 38 22 } 39 double form_volume(void){40 // Unused, so free to return garbage.41 return NAN;42 }43 44 double Iq(double q,45 double guinier_scale,46 double lorentzian_scale,47 double gyration_radius,48 double fractal_exp,49 double cor_length)50 {51 return _gel_fit_kernel(q,52 guinier_scale,53 lorentzian_scale,54 gyration_radius,55 fractal_exp,56 cor_length);57 }58 59 // Iqxy is never called since no orientation or magnetic parameters.60 double Iqxy(double qx, double qy,61 double guinier_scale,62 double lorentzian_scale,63 double gyration_radius,64 double fractal_exp,65 double cor_length)66 {67 double q = sqrt(qx*qx + qy*qy);68 return _gel_fit_kernel(q,69 guinier_scale,70 lorentzian_scale,71 gyration_radius,72 fractal_exp,73 cor_length);74 }75
Note: See TracChangeset
for help on using the changeset viewer.