Changeset 2c108a3 in sasmodels
- Timestamp:
- Oct 19, 2017 2:58:57 PM (7 years ago)
- Branches:
- master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 6773b02
- Parents:
- 9ee2756
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/developer/calculator.rst
r9ee2756 r2c108a3 107 107 - MAGNETIC_PARS is a comma separated list of the magnetic SLDs, indicating 108 108 their locations in the values vector. 109 - MAGNETIC_PAR1, ... are the first three magnetic parameter ids so we can110 hard code the setting of magnetic values if there are only a few of them.111 109 - KERNEL_NAME is the name of the function being declared 112 110 - PARAMETER_TABLE is the declaration of the parameters to the kernel: … … 208 206 NUM_MAGNETIC = 2 // two parameters might be magnetic 209 207 MAGNETIC_PARS = 4, 5 // they are sld and sld_solvent 210 MAGNETIC_PAR0 = 4 // sld index211 MAGNETIC_PAR1 = 5 // solvent index212 208 213 209 details { -
doc/guide/magnetism/magnetism.rst
r1f058ea r2c108a3 31 31 to the $x'$ axis, the possible spin states after the sample are then 32 32 33 No spin-flips(+ +) and (- -)33 Non spin-flip (+ +) and (- -) 34 34 35 Spin-flip s(+ -) and (- +)35 Spin-flip (+ -) and (- +) 36 36 37 37 .. figure:: … … 41 41 $\phi$ and $\theta_{up}$, respectively, then, depending on the spin state of the 42 42 neutrons, the scattering length densities, including the nuclear scattering 43 length density ($\beta{_N}$)are43 length density $(\beta{_N})$ are 44 44 45 45 .. math:: 46 46 \beta_{\pm\pm} = \beta_N \mp D_M M_{\perp x'} 47 \text{ when there are no spin-flips}47 \text{ for non spin-flip states} 48 48 49 49 and … … 51 51 .. math:: 52 52 \beta_{\pm\mp} = -D_M (M_{\perp y'} \pm iM_{\perp z'}) 53 \text{ when there are}53 \text{ for spin-flip states} 54 54 55 55 where 56 56 57 57 .. math:: 58 M_{\perp x'} = M_{0q_x}\cos(\theta_{up})+M_{0q_y}\sin(\theta_{up}) \\59 M_{\perp y'} = M_{0q_y}\cos(\theta_{up})-M_{0q_x}\sin(\theta_{up}) \\60 M_{\perp z'} = M_{0z} \\61 M_{0q_x} = (M_{0x}\cos\phi - M_{0y}\sin\phi)\cos\phi \\62 M_{0q_y} = (M_{0y}\sin\phi - M_{0x}\cos\phi)\sin\phi58 M_{\perp x'} &= M_{0q_x}\cos(\theta_{up})+M_{0q_y}\sin(\theta_{up}) \\ 59 M_{\perp y'} &= M_{0q_y}\cos(\theta_{up})-M_{0q_x}\sin(\theta_{up}) \\ 60 M_{\perp z'} &= M_{0z} \\ 61 M_{0q_x} &= (M_{0x}\cos\phi - M_{0y}\sin\phi)\cos\phi \\ 62 M_{0q_y} &= (M_{0y}\sin\phi - M_{0x}\cos\phi)\sin\phi 63 63 64 64 Here, $M_{0x}$, $M_{0x}$, $M_{0z}$ are the x, y and z components … … 66 66 67 67 .. math:: 68 M_{0x} = M_0\cos\theta_M\cos\phi_M \\69 M_{0y} = M_0\sin\theta_M \\70 M_{0z} = -M_0\cos\theta_M\sin\phi_M68 M_{0x} &= M_0\cos\theta_M\cos\phi_M \\ 69 M_{0y} &= M_0\sin\theta_M \\ 70 M_{0z} &= -M_0\cos\theta_M\sin\phi_M 71 71 72 72 and the magnetization angles $\theta_M$ and $\phi_M$ are defined in -
sasmodels/generate.py
r9ee2756 r2c108a3 760 760 source.append("#define NUM_MAGNETIC %d" % partable.nmagnetic) 761 761 source.append("#define MAGNETIC_PARS %s"%",".join(str(k) for k in magpars)) 762 for k, v in enumerate(magpars[:3]):763 source.append("#define MAGNETIC_PAR%d %d"%(k+1, v))764 762 765 763 # TODO: allow mixed python/opencl kernels? -
sasmodels/kernel_iq.c
r9ee2756 r2c108a3 17 17 // NUM_VALUES : the number of values to skip at the start of the 18 18 // values array before you get to the dispersity values. 19 // NUM_MAGNETIC : the number of magnetic parameters20 19 // PARAMETER_TABLE : list of parameter declarations used to create the 21 20 // ParameterTable type. 22 21 // KERNEL_NAME : model_Iq, model_Iqxy or model_Imagnetic. This code is 23 22 // included three times, once for each kernel type. 23 // MAGNETIC : defined when the magnetic kernel is being instantiated 24 // NUM_MAGNETIC : the number of magnetic parameters 24 25 // MAGNETIC_PARS : a comma-separated list of indices to the sld 25 26 // parameters in the parameter table. 26 // MAGNETIC_PAR1, ... : the first few indices of slds in the parameter table.27 // MAGNETIC : defined when the magnetic kernel is being instantiated28 27 // CALL_VOLUME(table) : call the form volume function 29 28 // CALL_IQ(q, table) : call the Iq function for 1D calcs. … … 39 38 typedef struct { 40 39 #if MAX_PD > 0 41 int32_t pd_par[MAX_PD]; // id of the nth polydispersity variable42 int32_t pd_length[MAX_PD]; // length of the nth polydispersity weight vector40 int32_t pd_par[MAX_PD]; // id of the nth dispersity variable 41 int32_t pd_length[MAX_PD]; // length of the nth dispersity weight vector 43 42 int32_t pd_offset[MAX_PD]; // offset of pd weights in the value & weight vector 44 43 int32_t pd_stride[MAX_PD]; // stride to move to the next index at this level … … 73 72 // uu * (sld - m_sigma_x); 74 73 // dd * (sld + m_sigma_x); 75 // ud * (m_sigma_y + 1j*m_sigma_z); 76 // du * (m_sigma_y - 1j*m_sigma_z); 77 static void set_spins(double in_spin, double out_spin, double spins[4]) 74 // ud * (m_sigma_y - 1j*m_sigma_z); 75 // du * (m_sigma_y + 1j*m_sigma_z); 76 // weights for spin crosssections: dd du real, ud real, uu, du imag, ud imag 77 static void set_spin_weights(double in_spin, double out_spin, double spins[4]) 78 78 { 79 79 in_spin = clip(in_spin, 0.0, 1.0); 80 80 out_spin = clip(out_spin, 0.0, 1.0); 81 81 spins[0] = sqrt(sqrt((1.0-in_spin) * (1.0-out_spin))); // dd 82 spins[1] = sqrt(sqrt((1.0-in_spin) * out_spin)); // du 83 spins[2] = sqrt(sqrt(in_spin * (1.0-out_spin))); // ud 82 spins[1] = sqrt(sqrt((1.0-in_spin) * out_spin)); // du real 83 spins[2] = sqrt(sqrt(in_spin * (1.0-out_spin))); // ud real 84 84 spins[3] = sqrt(sqrt(in_spin * out_spin)); // uu 85 spins[4] = spins[1]; // du imag 86 spins[5] = spins[2]; // ud imag 85 87 } 86 88 87 89 // Compute the magnetic sld 88 static double mag_sld(double qx, double qy, double p, 89 double mx, double my, double sld) 90 { 90 static double mag_sld( 91 const int xs, // 0=dd, 1=du real, 2=ud real, 3=uu, 4=du imag, 5=up imag 92 const double qx, const double qy, 93 const double px, const double py, 94 const double sld, 95 const double mx, const double my, const double mz 96 ) 97 { 98 if (xs < 4) { 91 99 const double perp = qy*mx - qx*my; 92 return sld + perp*p; 93 } 100 switch (xs) { 101 case 0: // uu => sld - D M_perpx 102 return sld - px*perp; 103 case 1: // ud real => -D M_perpy 104 return py*perp; 105 case 2: // du real => -D M_perpy 106 return py*perp; 107 case 3: // dd real => sld + D M_perpx 108 return sld + px*perp; 109 } 110 } else { 111 if (xs== 4) { 112 return -mz; // ud imag => -D M_perpz 113 } else { // index == 5 114 return mz; // du imag => D M_perpz 115 } 116 } 117 } 118 94 119 95 120 #endif … … 235 260 void KERNEL_NAME( 236 261 int32_t nq, // number of q values 237 const int32_t pd_start, // where we are in the polydispersity loop238 const int32_t pd_stop, // where we are stopping in the polydispersity loop262 const int32_t pd_start, // where we are in the dispersity loop 263 const int32_t pd_stop, // where we are stopping in the dispersity loop 239 264 global const ProblemDetails *details, 240 265 global const double *values, 241 266 global const double *q, // nq q values, with padding to boundary 242 267 global double *result, // nq+1 return values, again with padding 243 const double cutoff // cutoff in the polydispersity weight product268 const double cutoff // cutoff in the dispersity weight product 244 269 ) 245 270 { … … 256 281 257 282 // Storage for the current parameter values. These will be updated as we 258 // walk the polydispersity cube.283 // walk the dispersity mesh. 259 284 ParameterBlock local_values; 260 285 … … 262 287 // Location of the sld parameters in the parameter vector. 263 288 // These parameters are updated with the effective sld due to magnetism. 264 #if NUM_MAGNETIC > 3265 289 const int32_t slds[] = { MAGNETIC_PARS }; 266 #endif267 290 268 291 // Interpret polarization cross section. … … 271 294 // up_angle = values[NUM_PARS+4]; 272 295 // TODO: could precompute more magnetism parameters before calling the kernel. 273 double spins[ 4];296 double spins[8]; // uu, ud real, du real, dd, ud imag, du imag, fill, fill 274 297 double cos_mspin, sin_mspin; 275 set_spin s(values[NUM_PARS+2], values[NUM_PARS+3], spins);298 set_spin_weights(values[NUM_PARS+2], values[NUM_PARS+3], spins); 276 299 SINCOS(-values[NUM_PARS+4]*M_PI_180, sin_mspin, cos_mspin); 277 300 #endif // MAGNETIC … … 395 418 int i##_LOOP = (pd_start/details->pd_stride[_LOOP])%n##_LOOP; 396 419 397 // Jump into the middle of the polydispersity loop420 // Jump into the middle of the dispersity loop 398 421 #define PD_OPEN(_LOOP,_OUTER) \ 399 422 while (i##_LOOP < n##_LOOP) { \ … … 427 450 // unoriented 1D 428 451 double qk; 429 #define FETCH_Q do { qk = q[q_index]; } while (0)430 #define BUILD_ROTATION do {} while(0)431 #define APPLY_ROTATION do {} while(0)432 #define CALL_KERNEL CALL_IQ(qk, local_values.table)452 #define FETCH_Q() do { qk = q[q_index]; } while (0) 453 #define BUILD_ROTATION() do {} while(0) 454 #define APPLY_ROTATION() do {} while(0) 455 #define CALL_KERNEL() CALL_IQ(qk, local_values.table) 433 456 434 457 #elif defined(CALL_IQ_A) 435 458 // unoriented 2D 436 459 double qx, qy; 437 #define FETCH_Q do { qx = q[2*q_index]; qy = q[2*q_index+1]; } while (0)438 #define BUILD_ROTATION do {} while(0)439 #define APPLY_ROTATION do {} while(0)440 #define CALL_KERNEL CALL_IQ_A(sqrt(qx*qx+qy*qy), local_values.table)460 #define FETCH_Q() do { qx = q[2*q_index]; qy = q[2*q_index+1]; } while (0) 461 #define BUILD_ROTATION() do {} while(0) 462 #define APPLY_ROTATION() do {} while(0) 463 #define CALL_KERNEL() CALL_IQ_A(sqrt(qx*qx+qy*qy), local_values.table) 441 464 442 465 #elif defined(CALL_IQ_AC) 443 466 // oriented symmetric 2D 444 467 double qx, qy; 445 #define FETCH_Q do { qx = q[2*q_index]; qy = q[2*q_index+1]; } while (0)468 #define FETCH_Q() do { qx = q[2*q_index]; qy = q[2*q_index+1]; } while (0) 446 469 double qa, qc; 447 470 QACRotation rotation; … … 452 475 const double theta = values[details->theta_par+2]; 453 476 const double phi = values[details->theta_par+3]; 454 #define BUILD_ROTATION qac_rotation(&rotation, \477 #define BUILD_ROTATION() qac_rotation(&rotation, \ 455 478 theta, phi, local_values.table.theta, local_values.table.phi) 456 #define APPLY_ROTATION qac_apply(rotation, qx, qy, &qa, &qc)457 #define CALL_KERNEL CALL_IQ_AC(qa, qc, local_values.table)479 #define APPLY_ROTATION() qac_apply(rotation, qx, qy, &qa, &qc) 480 #define CALL_KERNEL() CALL_IQ_AC(qa, qc, local_values.table) 458 481 459 482 #elif defined(CALL_IQ_ABC) 460 483 // oriented asymmetric 2D 461 484 double qx, qy; 462 #define FETCH_Q do { qx = q[2*q_index]; qy = q[2*q_index+1]; } while (0)485 #define FETCH_Q() do { qx = q[2*q_index]; qy = q[2*q_index+1]; } while (0) 463 486 double qa, qb, qc; 464 487 QABCRotation rotation; … … 470 493 const double phi = values[details->theta_par+3]; 471 494 const double psi = values[details->theta_par+4]; 472 #define BUILD_ROTATION qabc_rotation(&rotation, \495 #define BUILD_ROTATION() qabc_rotation(&rotation, \ 473 496 theta, phi, psi, local_values.table.theta, \ 474 497 local_values.table.phi, local_values.table.psi) 475 #define APPLY_ROTATION qabc_apply(rotation, qx, qy, &qa, &qb, &qc)476 #define CALL_KERNEL CALL_IQ_ABC(qa, qb, qc, local_values.table)498 #define APPLY_ROTATION() qabc_apply(rotation, qx, qy, &qa, &qb, &qc) 499 #define CALL_KERNEL() CALL_IQ_ABC(qa, qb, qc, local_values.table) 477 500 478 501 #endif … … 538 561 if (weight0 > cutoff) { 539 562 pd_norm += weight0 * CALL_VOLUME(local_values.table); 540 BUILD_ROTATION ;563 BUILD_ROTATION(); 541 564 542 565 #ifndef USE_OPENCL … … 549 572 { 550 573 551 FETCH_Q ;552 APPLY_ROTATION ;574 FETCH_Q(); 575 APPLY_ROTATION(); 553 576 554 577 // ======= COMPUTE SCATTERING ========== 555 578 #if defined(MAGNETIC) && NUM_MAGNETIC > 0 556 // Constant across orientation, polydispersity for given qx, qy 557 double scattering = 0.0; 558 // TODO: what is the magnetic scattering at q=0 559 const double qsq = qx*qx + qy*qy; 560 if (qsq > 1.e-16) { 561 double p[4]; // dd, du, ud, uu 562 p[0] = (qy*cos_mspin + qx*sin_mspin)/qsq; 563 p[3] = -p[0]; 564 p[1] = p[2] = (qy*sin_mspin - qx*cos_mspin)/qsq; 565 566 for (int index=0; index<4; index++) { 567 const double xs = spins[index]; 568 if (xs > 1.e-8) { 569 const int spin_flip = (index==1) || (index==2); 570 const double pk = p[index]; 571 for (int axis=0; axis<=spin_flip; axis++) { 572 #define SLD(_M_offset, _sld_offset) \ 573 local_values.vector[_sld_offset] = xs * (axis \ 574 ? (index==1 ? -values[_M_offset+2] : values[_M_offset+2]) \ 575 : mag_sld(qx, qy, pk, values[_M_offset], values[_M_offset+1], \ 576 (spin_flip ? 0.0 : values[_sld_offset+2]))) 577 #define M1 NUM_PARS+5 578 #if NUM_MAGNETIC==1 579 SLD(M1, MAGNETIC_PAR1); 580 #elif NUM_MAGNETIC==2 581 SLD(M1, MAGNETIC_PAR1); 582 SLD(M1+3, MAGNETIC_PAR2); 583 #elif NUM_MAGNETIC==3 584 SLD(M1, MAGNETIC_PAR1); 585 SLD(M1+3, MAGNETIC_PAR2); 586 SLD(M1+6, MAGNETIC_PAR3); 587 #else 588 for (int sk=0; sk<NUM_MAGNETIC; sk++) { 589 SLD(M1+3*sk, slds[sk]); 590 } 591 #endif 592 #undef SLD 593 scattering += CALL_KERNEL; 579 // Compute the scattering from the magnetic cross sections. 580 double scattering = 0.0; 581 const double qsq = qx*qx + qy*qy; 582 if (qsq > 1.e-16) { 583 // TODO: what is the magnetic scattering at q=0 584 const double px = (qy*cos_mspin + qx*sin_mspin)/qsq; 585 const double py = (qy*sin_mspin - qx*cos_mspin)/qsq; 586 587 // loop over uu, ud real, du real, dd, ud imag, du imag 588 for (int xs=0; xs<6; xs++) { 589 const double xs_weight = spins[xs]; 590 if (xs_weight > 1.e-8) { 591 // Since the cross section weight is significant, set the slds 592 // to the effective slds for this cross section, call the 593 // kernel, and add according to weight. 594 for (int sk=0; sk<NUM_MAGNETIC; sk++) { 595 const int32_t mag_index = NUM_PARS+5 + 3*sk; 596 const int32_t sld_index = slds[sk]; 597 const double mx = values[mag_index]; 598 const double my = values[mag_index+1]; 599 const double mz = values[mag_index+2]; 600 local_values.vector[sld_index] = 601 mag_sld(xs, qx, qy, px, py, values[sld_index+2], mx, my, mz); 602 } 603 scattering += xs_weight * CALL_KERNEL(); 594 604 } 595 605 } 596 606 } 597 }598 607 #else // !MAGNETIC 599 const double scattering = CALL_KERNEL;608 const double scattering = CALL_KERNEL(); 600 609 #endif // !MAGNETIC 601 610 //printf("q_index:%d %g %g %g %g\n", q_index, scattering, weight, weight0); 602 611 603 612 #ifdef USE_OPENCL 604 this_result += weight0 * scattering;613 this_result += weight0 * scattering; 605 614 #else // !USE_OPENCL 606 result[q_index] += weight0 * scattering;615 result[q_index] += weight0 * scattering; 607 616 #endif // !USE_OPENCL 608 617 } … … 627 636 PD_CLOSE(4) 628 637 #endif 629 630 // clear the macros in preparation for the next kernel631 #undef PD_INIT632 #undef PD_OPEN633 #undef PD_CLOSE634 #undef FETCH_Q635 #undef BUILD_ROTATION636 #undef APPLY_ROTATION637 #undef CALL_KERNEL638 638 639 639 // Remember the current result and the updated norm. … … 646 646 //printf("res: %g/%g\n", result[0], pd_norm); 647 647 #endif // !USE_OPENCL 648 } 648 649 // clear the macros in preparation for the next kernel 650 #undef PD_INIT 651 #undef PD_OPEN 652 #undef PD_CLOSE 653 #undef FETCH_Q 654 #undef BUILD_ROTATION 655 #undef APPLY_ROTATION 656 #undef CALL_KERNEL 657 }
Note: See TracChangeset
for help on using the changeset viewer.