Changeset 6b7e2f7 in sasmodels
- Timestamp:
- Aug 17, 2016 3:59:36 PM (8 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:
- 6dc78e4
- Parents:
- fe496dd (diff), 524e5c4 (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. - Files:
-
- 19 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
doc/ref/magnetism/magnetism.rst
rb1c40bee r524e5c4 17 17 18 18 For magnetic scattering, only the magnetization component $\mathbf{M_\perp}$ 19 perpendicular to the scattering vector $\mathbf{Q}$ contributes to the themagnetic19 perpendicular to the scattering vector $\mathbf{Q}$ contributes to the magnetic 20 20 scattering length. 21 21 22 22 23 23 .. figure:: 24 img/mag_vector.bmp24 mag_img/mag_vector.bmp 25 25 26 26 The magnetic scattering length density is then … … 42 42 43 43 .. figure:: 44 img/M_angles_pic.bmp44 mag_img/M_angles_pic.bmp 45 45 46 46 If the angles of the $Q$ vector and the spin-axis $x'$ to the $x$ - axis are 47 47 $\phi$ and $\theta_{up}$, respectively, then, depending on the spin state of the 48 48 neutrons, the scattering length densities, including the nuclear scattering 49 length density ($\beta _N$) are49 length density ($\beta{_N}$) are 50 50 51 51 .. math:: … … 83 83 =========== ================================================================ 84 84 M0_sld = $D_M M_0$ 85 Up_theta = $\theta_ up$85 Up_theta = $\theta_{up}$ 86 86 M_theta = $\theta_M$ 87 87 M_phi = $\phi_M$ -
sasmodels/models/core_multi_shell.py
rb1c40bee r9a4811a 26 26 27 27 For information about polarised and magnetic scattering, see 28 the : doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.28 the :ref:`magnetism` documentation. 29 29 30 30 Our model uses the form factor calculations implemented in a c-library provided -
sasmodels/models/core_shell_sphere.py
rb1c40bee r9a4811a 6 6 7 7 For information about polarised and magnetic scattering, see 8 the : doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.8 the :ref:`magnetism` documentation. 9 9 10 10 Definition -
sasmodels/models/cylinder.py
rb1c40bee r9a4811a 4 4 The form factor is normalized by the particle volume V = \piR^2L. 5 5 For information about polarised and magnetic scattering, see 6 the : doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.6 the :ref:`magnetism` documentation. 7 7 8 8 Definition -
sasmodels/models/fuzzy_sphere.py
rb1c40bee r9a4811a 1 1 r""" 2 2 For information about polarised and magnetic scattering, see 3 the : doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.3 the :ref:`magnetism` documentation. 4 4 5 5 Definition -
sasmodels/models/multilayer_vesicle.py
rb1c40bee r9a4811a 28 28 29 29 For information about polarised and magnetic scattering, see 30 the : doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.30 the :ref:`magnetism` documentation. 31 31 32 32 This code is based on the form factor calculations implemented in the NIST -
sasmodels/models/parallelepiped.py
rb1c40bee r9a4811a 4 4 The form factor is normalized by the particle volume. 5 5 For information about polarised and magnetic scattering, see 6 the : doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.6 the :ref:`magnetism` documentation. 7 7 8 8 Definition -
sasmodels/models/sphere.py
rb1c40bee r9a4811a 1 1 r""" 2 2 For information about polarised and magnetic scattering, see 3 the : doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.3 the :ref:`magnetism` documentation. 4 4 documentation. 5 5 -
sasmodels/core.py
r672978c r725ee36 33 33 except ImportError: 34 34 pass 35 36 try:37 np.meshgrid([])38 meshgrid = np.meshgrid39 except Exception:40 # CRUFT: np.meshgrid requires multiple vectors41 def meshgrid(*args):42 """Allow meshgrid with a single argument"""43 if len(args) > 1:44 return np.meshgrid(*args)45 else:46 return [np.asarray(v) for v in args]47 35 48 36 # TODO: refactor composite model support -
sasmodels/details.py
r40a87fa r725ee36 20 20 np.meshgrid([]) 21 21 meshgrid = np.meshgrid 22 except ValueError:22 except Exception: 23 23 # CRUFT: np.meshgrid requires multiple vectors 24 24 def meshgrid(*args): … … 71 71 # pd_offset[max_pd] offset of pd values in parameter array 72 72 # pd_stride[max_pd] index of pd value in loop = n//stride[k] 73 # pd_prodtotal length of pd loop74 # pd_sumtotal length of the weight vector73 # num_eval total length of pd loop 74 # num_weights total length of the weight vector 75 75 # num_active number of pd params 76 76 # theta_par parameter number for theta parameter 77 self.buffer = np. zeros(4*max_pd + 4, 'i4')77 self.buffer = np.empty(4*max_pd + 4, 'i4') 78 78 79 79 # generate views on different parts of the array … … 86 86 self.theta_par = parameters.theta_offset 87 87 88 # offset and length are for all parameters, not just pd parameters 89 # They are not sent to the kernel function, though they could be. 90 # They are used by the composite models (sum and product) to 91 # figure out offsets into the combined value list. 92 self.offset = None # type: np.ndarray 93 self.length = None # type: np.ndarray 94 95 # keep hold of ifno show() so we can break a values vector 96 # into the individual components 97 self.info = model_info 98 88 99 @property 89 100 def pd_par(self): … … 107 118 108 119 @property 109 def pd_prod(self):120 def num_eval(self): 110 121 """Total size of the pd mesh""" 111 122 return self.buffer[-4] 112 123 113 @ pd_prod.setter114 def pd_prod(self, v):124 @num_eval.setter 125 def num_eval(self, v): 115 126 """Total size of the pd mesh""" 116 127 self.buffer[-4] = v 117 128 118 129 @property 119 def pd_sum(self):130 def num_weights(self): 120 131 """Total length of all the weight vectors""" 121 132 return self.buffer[-3] 122 133 123 @ pd_sum.setter124 def pd_sum(self, v):134 @num_weights.setter 135 def num_weights(self, v): 125 136 """Total length of all the weight vectors""" 126 137 self.buffer[-3] = v … … 146 157 self.buffer[-1] = v 147 158 148 def show(self ):159 def show(self, values=None): 149 160 """Print the polydispersity call details to the console""" 150 print("num_active", self.num_active) 151 print("pd_prod", self.pd_prod) 152 print("pd_sum", self.pd_sum) 153 print("theta par", self.theta_par) 154 print("pd_par", self.pd_par) 155 print("pd_length", self.pd_length) 156 print("pd_offset", self.pd_offset) 157 print("pd_stride", self.pd_stride) 158 159 160 def mono_details(model_info): 161 # type: (ModelInfo) -> CallDetails 162 """ 163 Return a :class:`CallDetails` object for a monodisperse calculation 164 of the model defined by *model_info*. 165 """ 166 call_details = CallDetails(model_info) 167 call_details.pd_prod = 1 168 call_details.pd_sum = model_info.parameters.nvalues 169 call_details.pd_par[:] = np.arange(0, model_info.parameters.max_pd) 170 call_details.pd_length[:] = 1 171 call_details.pd_offset[:] = np.arange(0, model_info.parameters.max_pd) 172 call_details.pd_stride[:] = 1 173 return call_details 174 175 176 def poly_details(model_info, weights): 161 print("===== %s details ===="%self.info.name) 162 print("num_active:%d num_eval:%d num_weights:%d theta=%d" 163 % (self.num_active, self.num_eval, self.num_weights, self.theta_par)) 164 if self.pd_par.size: 165 print("pd_par", self.pd_par) 166 print("pd_length", self.pd_length) 167 print("pd_offset", self.pd_offset) 168 print("pd_stride", self.pd_stride) 169 if values is not None: 170 nvalues = self.info.parameters.nvalues 171 print("scale, background", values[:2]) 172 print("val", values[2:nvalues]) 173 print("pd", values[nvalues:nvalues+self.num_weights]) 174 print("wt", values[nvalues+self.num_weights:nvalues+2*self.num_weights]) 175 print("offsets", self.offset) 176 177 178 def make_details(model_info, length, offset, num_weights): 177 179 """ 178 180 Return a :class:`CallDetails` object for a polydisperse calculation 179 of the model defined by *model_info* for the given set of *weights*. 180 *weights* is a list of vectors, one for each parameter. Monodisperse 181 parameters should provide a weight vector containing [1.0]. 182 """ 183 # type: (ModelInfo) -> CallDetails 184 #print("weights",weights) 185 #weights = weights[2:] # Skip scale and background 186 187 # Decreasing list of polydispersity lengths 188 #print([p.id for p in model_info.parameters.call_parameters]) 189 pd_length = np.array([len(w) 190 for w in weights[2:2+model_info.parameters.npars]]) 191 num_active = np.sum(pd_length > 1) 181 of the model defined by *model_info*. Polydispersity is defined by 182 the *length* of the polydispersity distribution for each parameter 183 and the *offset* of the distribution in the polydispersity array. 184 Monodisperse parameters should use a polydispersity length of one 185 with weight 1.0. *num_weights* is the total length of the polydispersity 186 array. 187 """ 188 # type: (ModelInfo, np.ndarray, np.ndarray, int) -> CallDetails 189 #pars = model_info.parameters.call_parameters[2:model_info.parameters.npars+2] 190 #print(", ".join(str(i)+"-"+p.id for i,p in enumerate(pars))) 191 #print("len:",length) 192 #print("off:",offset) 193 194 # Check that we arn't using too many polydispersity loops 195 num_active = np.sum(length > 1) 192 196 max_pd = model_info.parameters.max_pd 193 197 if num_active > max_pd: 194 198 raise ValueError("Too many polydisperse parameters") 195 199 196 pd_offset = np.cumsum(np.hstack((0, pd_length))) 197 #print(", ".join(str(i)+"-"+p.id for i,p in enumerate(model_info.parameters.call_parameters))) 198 #print("len:",pd_length) 199 #print("off:",pd_offset) 200 # Decreasing list of polydpersity lengths 200 201 # Note: the reversing view, x[::-1], does not require a copy 201 idx = np.argsort( pd_length)[::-1][:max_pd]202 pd_stride = np.cumprod(np.hstack((1, pd_length[idx])))202 idx = np.argsort(length)[::-1][:max_pd] 203 pd_stride = np.cumprod(np.hstack((1, length[idx]))) 203 204 204 205 call_details = CallDetails(model_info) 205 206 call_details.pd_par[:max_pd] = idx 206 call_details.pd_length[:max_pd] = pd_length[idx]207 call_details.pd_offset[:max_pd] = pd_offset[idx]207 call_details.pd_length[:max_pd] = length[idx] 208 call_details.pd_offset[:max_pd] = offset[idx] 208 209 call_details.pd_stride[:max_pd] = pd_stride[:-1] 209 call_details. pd_prod= pd_stride[-1]210 call_details. pd_sum = sum(len(w) for w in weights)210 call_details.num_eval = pd_stride[-1] 211 call_details.num_weights = num_weights 211 212 call_details.num_active = num_active 213 call_details.length = length 214 call_details.offset = offset 212 215 #call_details.show() 213 216 return call_details 217 218 219 ZEROS = tuple([0.]*31) 220 def make_kernel_args(kernel, pairs): 221 # type: (Kernel, Tuple[List[np.ndarray], List[np.ndarray]]) -> Tuple[CallDetails, np.ndarray, bool] 222 """ 223 Converts (value, weight) pairs into parameters for the kernel call. 224 225 Returns a CallDetails object indicating the polydispersity, a data object 226 containing the different values, and the magnetic flag indicating whether 227 any magnetic magnitudes are non-zero. Magnetic vectors (M0, phi, theta) are 228 converted to rectangular coordinates (mx, my, mz). 229 """ 230 npars = kernel.info.parameters.npars 231 nvalues = kernel.info.parameters.nvalues 232 scalars = [v[0][0] for v in pairs] 233 values, weights = zip(*pairs[2:npars+2]) if npars else ((),()) 234 length = np.array([len(w) for w in weights]) 235 offset = np.cumsum(np.hstack((0, length))) 236 call_details = make_details(kernel.info, length, offset[:-1], offset[-1]) 237 # Pad value array to a 32 value boundaryd 238 data_len = nvalues + 2*sum(len(v) for v in values) 239 extra = (32 - data_len%32)%32 240 data = np.hstack((scalars,) + values + weights + ZEROS[:extra]) 241 data = data.astype(kernel.dtype) 242 is_magnetic = convert_magnetism(kernel.info.parameters, data) 243 #call_details.show() 244 return call_details, data, is_magnetic 245 246 247 def convert_magnetism(parameters, values): 248 """ 249 Convert magnetism values from polar to rectangular coordinates. 250 251 Returns True if any magnetism is present. 252 """ 253 mag = values[parameters.nvalues-3*parameters.nmagnetic:parameters.nvalues] 254 mag = mag.reshape(-1, 3) 255 scale = mag[:,0] 256 if np.any(scale): 257 theta, phi = mag[:, 1]*pi/180., mag[:, 2]*pi/180. 258 cos_theta = cos(theta) 259 mag[:, 0] = scale*cos_theta*cos(phi) # mx 260 mag[:, 1] = scale*sin(theta) # my 261 mag[:, 2] = -scale*cos_theta*sin(phi) # mz 262 return True 263 else: 264 return False 214 265 215 266 … … 239 290 value = pars 240 291 return value, weight 241 242 243 244 def build_details(kernel, pairs):245 # type: (Kernel, Tuple[List[np.ndarray], List[np.ndarray]]) -> Tuple[CallDetails, np.ndarray, bool]246 """247 Converts (value, weight) pairs into parameters for the kernel call.248 249 Returns a CallDetails object indicating the polydispersity, a data object250 containing the different values, and the magnetic flag indicating whether251 any magnetic magnitudes are non-zero. Magnetic vectors (M0, phi, theta) are252 converted to rectangular coordinates (mx, my, mz).253 """254 values, weights = zip(*pairs)255 scalars = [v[0] for v in values]256 if all(len(w) == 1 for w in weights):257 call_details = mono_details(kernel.info)258 # Pad value array to a 32 value boundary259 data_len = 3*len(scalars)260 extra = ((data_len+31)//32)*32 - data_len261 data = np.array(scalars+scalars+[1.]*len(scalars)+[0.]*extra,262 dtype=kernel.dtype)263 else:264 call_details = poly_details(kernel.info, weights)265 # Pad value array to a 32 value boundary266 data_len = len(scalars) + 2*sum(len(v) for v in values)267 extra = ((data_len+31)//32)*32 - data_len268 data = np.hstack(scalars+list(values)+list(weights)+[0.]*extra)269 data = data.astype(kernel.dtype)270 is_magnetic = convert_magnetism(kernel.info.parameters, data)271 #call_details.show()272 return call_details, data, is_magnetic273 274 def convert_magnetism(parameters, values):275 """276 Convert magnetism values from polar to rectangular coordinates.277 278 Returns True if any magnetism is present.279 """280 mag = values[parameters.nvalues-3*parameters.nmagnetic:parameters.nvalues]281 mag = mag.reshape(-1, 3)282 scale = mag[:,0]283 if np.any(scale):284 theta, phi = mag[:, 1]*pi/180., mag[:, 2]*pi/180.285 cos_theta = cos(theta)286 mag[:, 0] = scale*cos_theta*cos(phi) # mx287 mag[:, 1] = scale*sin(theta) # my288 mag[:, 2] = -scale*cos_theta*sin(phi) # mz289 return True290 else:291 return False -
sasmodels/direct_model.py
r40a87fa rbde38b5 30 30 from . import resolution 31 31 from . import resolution2d 32 from .details import build_details, dispersion_mesh32 from .details import make_kernel_args, dispersion_mesh 33 33 34 34 try: … … 70 70 for p in parameters.call_parameters] 71 71 72 call_details, values, is_magnetic = build_details(calculator, vw_pairs)72 call_details, values, is_magnetic = make_kernel_args(calculator, vw_pairs) 73 73 #print("values:", values) 74 74 return calculator(call_details, values, cutoff, is_magnetic) -
sasmodels/kernel.py
r9eb3632 rbde38b5 39 39 info = None # type: ModelInfo 40 40 results = None # type: List[np.ndarray] 41 dtype = None # type: np.dtype 41 42 42 43 def __call__(self, call_details, values, cutoff, magnetic): -
sasmodels/kernel_iq.c
r0f00d95 rbde38b5 22 22 int32_t pd_stride[MAX_PD]; // stride to move to the next index at this level 23 23 #endif // MAX_PD > 0 24 int32_t pd_prod;// total number of voxels in hypercube25 int32_t pd_sum;// total length of the weights vector24 int32_t num_eval; // total number of voxels in hypercube 25 int32_t num_weights; // total length of the weights vector 26 26 int32_t num_active; // number of non-trivial pd loops 27 27 int32_t theta_par; // id of spherical correction variable 28 28 } ProblemDetails; 29 29 30 // Intel HD 4000 needs private arrays to be a multiple of 4 long 30 31 typedef struct { 31 32 PARAMETER_TABLE 33 } ParameterTable; 34 typedef union { 35 ParameterTable table; 36 double vector[4*((NUM_PARS+3)/4)]; 32 37 } ParameterBlock; 33 38 #endif // _PAR_BLOCK_ … … 79 84 ) 80 85 { 81 82 86 // Storage for the current parameter values. These will be updated as we 83 // walk the polydispersity cube. local_values will be aliased to pvec.87 // walk the polydispersity cube. 84 88 ParameterBlock local_values; 85 double *pvec = (double *)&local_values;86 89 87 90 #if defined(MAGNETIC) && NUM_MAGNETIC>0 88 // Location of the sld parameters in the parameter pvec.91 // Location of the sld parameters in the parameter vector. 89 92 // These parameters are updated with the effective sld due to magnetism. 90 93 #if NUM_MAGNETIC > 3 … … 110 113 #endif 111 114 for (int i=0; i < NUM_PARS; i++) { 112 pvec[i] = values[2+i]; 113 //printf("p%d = %g\n",i, pvec[i]); 114 } 115 116 double pd_norm; 117 //printf("start: %d %d\n",pd_start, pd_stop); 115 local_values.vector[i] = values[2+i]; 116 //printf("p%d = %g\n",i, local_values.vector[i]); 117 } 118 //printf("NUM_VALUES:%d NUM_PARS:%d MAX_PD:%d\n", NUM_VALUES, NUM_PARS, MAX_PD); 119 //printf("start:%d stop:%d\n", pd_start, pd_stop); 120 121 double pd_norm = (pd_start == 0 ? 0.0 : result[nq]); 118 122 if (pd_start == 0) { 119 pd_norm = 0.0;120 123 #ifdef USE_OPENMP 121 124 #pragma omp parallel for 122 125 #endif 123 126 for (int q_index=0; q_index < nq; q_index++) result[q_index] = 0.0; 124 //printf("initializing %d\n", nq);125 } else {126 pd_norm = result[nq];127 127 } 128 128 //printf("start %d %g %g\n", pd_start, pd_norm, result[0]); 129 129 130 130 #if MAX_PD>0 131 global const double *pd_value = values + NUM_VALUES + 2;132 global const double *pd_weight = pd_value + details-> pd_sum;131 global const double *pd_value = values + NUM_VALUES; 132 global const double *pd_weight = pd_value + details->num_weights; 133 133 #endif 134 134 … … 169 169 global const double *v0 = pd_value + details->pd_offset[0]; 170 170 global const double *w0 = pd_weight + details->pd_offset[0]; 171 //printf("w0:%p, values:%p, diff:% d, %d\n",w0,values,(w0-values),NUM_VALUES);171 //printf("w0:%p, values:%p, diff:%ld, %d\n",w0,values,(w0-values), NUM_VALUES); 172 172 #endif 173 173 … … 186 186 int step = pd_start; 187 187 188 189 188 #if MAX_PD>4 190 189 const double weight5 = 1.0; 191 190 while (i4 < n4) { 192 pvec[p4] = v4[i4];191 local_values.vector[p4] = v4[i4]; 193 192 double weight4 = w4[i4] * weight5; 194 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 4, p4, i4, n4, pvec[p4], weight4);193 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 4, p4, i4, n4, local_values.vector[p4], weight4); 195 194 #elif MAX_PD>3 196 195 const double weight4 = 1.0; … … 198 197 #if MAX_PD>3 199 198 while (i3 < n3) { 200 pvec[p3] = v3[i3];199 local_values.vector[p3] = v3[i3]; 201 200 double weight3 = w3[i3] * weight4; 202 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 3, p3, i3, n3, pvec[p3], weight3);201 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 3, p3, i3, n3, local_values.vector[p3], weight3); 203 202 #elif MAX_PD>2 204 203 const double weight3 = 1.0; … … 206 205 #if MAX_PD>2 207 206 while (i2 < n2) { 208 pvec[p2] = v2[i2];207 local_values.vector[p2] = v2[i2]; 209 208 double weight2 = w2[i2] * weight3; 210 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 2, p2, i2, n2, pvec[p2], weight2);209 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 2, p2, i2, n2, local_values.vector[p2], weight2); 211 210 #elif MAX_PD>1 212 211 const double weight2 = 1.0; … … 214 213 #if MAX_PD>1 215 214 while (i1 < n1) { 216 pvec[p1] = v1[i1];215 local_values.vector[p1] = v1[i1]; 217 216 double weight1 = w1[i1] * weight2; 218 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 1, p1, i1, n1, pvec[p1], weight1);217 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 1, p1, i1, n1, local_values.vector[p1], weight1); 219 218 #elif MAX_PD>0 220 219 const double weight1 = 1.0; … … 222 221 #if MAX_PD>0 223 222 if (slow_theta) { // Theta is not in inner loop 224 spherical_correction = fmax(fabs(cos(M_PI_180* pvec[theta_par])), 1.e-6);223 spherical_correction = fmax(fabs(cos(M_PI_180*local_values.vector[theta_par])), 1.e-6); 225 224 } 226 225 while(i0 < n0) { 227 pvec[p0] = v0[i0];226 local_values.vector[p0] = v0[i0]; 228 227 double weight0 = w0[i0] * weight1; 229 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 0, p0, i0, n0, pvec[p0], weight0);228 //printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 0, p0, i0, n0, local_values.vector[p0], weight0); 230 229 if (fast_theta) { // Theta is in inner loop 231 spherical_correction = fmax(fabs(cos(M_PI_180* pvec[p0])), 1.e-6);230 spherical_correction = fmax(fabs(cos(M_PI_180*local_values.vector[p0])), 1.e-6); 232 231 } 233 232 #else … … 235 234 #endif 236 235 237 //printf("step:%d of %d, pars:",step,pd_stop); for (int i=0; i < NUM_PARS; i++) printf("p%d=%g ",i, pvec[i]); printf("\n");236 //printf("step:%d of %d, pars:",step,pd_stop); for (int i=0; i < NUM_PARS; i++) printf("p%d=%g ",i, local_values.vector[i]); printf("\n"); 238 237 //printf("sphcor: %g\n", spherical_correction); 239 238 240 239 #ifdef INVALID 241 if (!INVALID(local_values ))240 if (!INVALID(local_values.table)) 242 241 #endif 243 242 { … … 248 247 // would be problems looking at models with theta=90. 249 248 const double weight = weight0 * spherical_correction; 250 pd_norm += weight * CALL_VOLUME(local_values );249 pd_norm += weight * CALL_VOLUME(local_values.table); 251 250 252 251 #ifdef USE_OPENMP … … 263 262 // TODO: what is the magnetic scattering at q=0 264 263 if (qsq > 1.e-16) { 265 double p[4]; 264 double p[4]; // dd, du, ud, uu 266 265 p[0] = (qy*cos_mspin + qx*sin_mspin)/qsq; 267 266 p[3] = -p[0]; … … 278 277 #define M3 NUM_PARS+13 279 278 #define SLD(_M_offset, _sld_offset) \ 280 pvec[_sld_offset] = xs * (axis \279 local_values.vector[_sld_offset] = xs * (axis \ 281 280 ? (index==1 ? -values[_M_offset+2] : values[_M_offset+2]) \ 282 281 : mag_sld(qx, qy, pk, values[_M_offset], values[_M_offset+1], \ … … 296 295 } 297 296 #endif 298 scattering += CALL_IQ(q, q_index, local_values );297 scattering += CALL_IQ(q, q_index, local_values.table); 299 298 } 300 299 } … … 302 301 } 303 302 #else // !MAGNETIC 304 const double scattering = CALL_IQ(q, q_index, local_values );303 const double scattering = CALL_IQ(q, q_index, local_values.table); 305 304 #endif // !MAGNETIC 306 305 //printf("q_index:%d %g %g %g %g\n",q_index, scattering, weight, spherical_correction, weight0); -
sasmodels/kernel_iq.cl
r4f1f876 rbde38b5 22 22 int32_t pd_stride[MAX_PD]; // stride to move to the next index at this level 23 23 #endif // MAX_PD > 0 24 int32_t pd_prod;// total number of voxels in hypercube25 int32_t pd_sum;// total length of the weights vector24 int32_t num_eval; // total number of voxels in hypercube 25 int32_t num_weights; // total length of the weights vector 26 26 int32_t num_active; // number of non-trivial pd loops 27 27 int32_t theta_par; // id of spherical correction variable … … 90 90 91 91 // Storage for the current parameter values. These will be updated as we 92 // walk the polydispersity cube. local_values will be aliased to pvec.92 // walk the polydispersity cube. 93 93 ParameterBlock local_values; 94 95 // Fill in the initial variables96 for (int i=0; i < NUM_PARS; i++) {97 local_values.vector[i] = values[2+i];98 //if (q_index==0) printf("p%d = %g\n",i, local_values.vector[i]);99 }100 94 101 95 #if defined(MAGNETIC) && NUM_MAGNETIC>0 … … 117 111 #endif // MAGNETIC 118 112 119 double pd_norm, this_result; 120 if (pd_start == 0) { 121 pd_norm = this_result = 0.0; 122 } else { 123 pd_norm = result[nq]; 124 this_result = result[q_index]; 125 } 113 // Fill in the initial variables 114 // values[0] is scale 115 // values[1] is background 116 for (int i=0; i < NUM_PARS; i++) { 117 local_values.vector[i] = values[2+i]; 118 //if (q_index==0) printf("p%d = %g\n",i, local_values.vector[i]); 119 } 120 //if (q_index==0) printf("NUM_VALUES:%d NUM_PARS:%d MAX_PD:%d\n", NUM_VALUES, NUM_PARS, MAX_PD); 121 //if (q_index==0) printf("start:%d stop:%d\n", pd_start, pd_stop); 122 123 double pd_norm = (pd_start == 0 ? 0.0 : result[nq]); 124 double this_result = (pd_start == 0 ? 0.0 : result[q_index]); 126 125 //if (q_index==0) printf("start %d %g %g\n", pd_start, pd_norm, this_result); 127 126 128 127 #if MAX_PD>0 129 global const double *pd_value = values + NUM_VALUES + 2;130 global const double *pd_weight = pd_value + details-> pd_sum;128 global const double *pd_value = values + NUM_VALUES; 129 global const double *pd_weight = pd_value + details->num_weights; 131 130 #endif 132 131 … … 256 255 // TODO: what is the magnetic scattering at q=0 257 256 if (qsq > 1.e-16) { 258 double p[4]; // spin_i, spin_f257 double p[4]; // dd, du, ud, uu 259 258 p[0] = (qy*cos_mspin + qx*sin_mspin)/qsq; 260 259 p[3] = -p[0]; -
sasmodels/kernelcl.py
r40a87fa rbde38b5 552 552 ] 553 553 #print("Calling OpenCL") 554 # print("values",values)554 #call_details.show(values) 555 555 # Call kernel and retrieve results 556 556 last_call = None 557 557 step = 100 558 for start in range(0, call_details. pd_prod, step):559 stop = min(start +step, call_details.pd_prod)558 for start in range(0, call_details.num_eval, step): 559 stop = min(start + step, call_details.num_eval) 560 560 #print("queuing",start,stop) 561 561 args[1:3] = [np.int32(start), np.int32(stop)] … … 563 563 None, *args, wait_for=last_call)] 564 564 cl.enqueue_copy(self.queue, self.result, self.result_b) 565 #print("result", self.result) 565 566 566 567 # Free buffers … … 570 571 scale = values[0]/self.result[self.q_input.nq] 571 572 background = values[1] 572 #print("scale",scale, background)573 #print("scale",scale,values[0],self.result[self.q_input.nq]) 573 574 return scale*self.result[:self.q_input.nq] + background 574 575 # return self.result[:self.q_input.nq] -
sasmodels/kerneldll.py
r40a87fa rbde38b5 380 380 self.real(cutoff), # cutoff 381 381 ] 382 #print("kerneldll values", values) 382 #print("Calling DLL") 383 #call_details.show(values) 383 384 step = 100 384 for start in range(0, call_details. pd_prod, step):385 stop = min(start +step, call_details.pd_prod)385 for start in range(0, call_details.num_eval, step): 386 stop = min(start + step, call_details.num_eval) 386 387 args[1:3] = [start, stop] 387 #print("calling DLL")388 388 kernel(*args) # type: ignore 389 389 -
sasmodels/kernelpy.py
r40a87fa rbde38b5 100 100 """ 101 101 def __init__(self, kernel, model_info, q_input): 102 # type: (callable, ModelInfo, List[np.ndarray]) -> None 102 103 self.dtype = np.dtype('d') 103 104 self.info = model_info … … 156 157 157 158 def __call__(self, call_details, values, cutoff, magnetic): 158 assert isinstance(call_details, details.CallDetails) 159 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 160 if magnetic: 161 raise NotImplementedError("Magnetism not implemented for pure python models") 162 #print("Calling python kernel") 163 #call_details.show(values) 159 164 res = _loops(self._parameter_vector, self._form, self._volume, 160 165 self.q_input.nq, call_details, values, cutoff) … … 162 167 163 168 def release(self): 169 # type: () -> None 164 170 """ 165 171 Free resources associated with the kernel. … … 189 195 return np.ones(nq, 'd')*background 190 196 191 pd_value = values[2+n_pars:2+n_pars + call_details. pd_sum]192 pd_weight = values[2+n_pars + call_details. pd_sum:]197 pd_value = values[2+n_pars:2+n_pars + call_details.num_weights] 198 pd_weight = values[2+n_pars + call_details.num_weights:] 193 199 194 200 pd_norm = 0.0 … … 209 215 210 216 total = np.zeros(nq, 'd') 211 for loop_index in range(call_details. pd_prod):217 for loop_index in range(call_details.num_eval): 212 218 # update polydispersity parameter values 213 219 if p0_index == p0_length: -
sasmodels/mixture.py
r7ae2b7f rfe496dd 11 11 *ProductModel(P, S)*. 12 12 """ 13 from __future__ import print_function 14 13 15 from copy import copy 14 16 import numpy as np # type: ignore … … 16 18 from .modelinfo import Parameter, ParameterTable, ModelInfo 17 19 from .kernel import KernelModel, Kernel 20 from .details import make_details 18 21 19 22 try: 20 23 from typing import List 21 from .details import CallDetails22 24 except ImportError: 23 25 pass … … 26 28 # type: (List[ModelInfo]) -> ModelInfo 27 29 """ 28 Create info block for productmodel.30 Create info block for mixture model. 29 31 """ 30 32 flatten = [] … … 38 40 # Build new parameter list 39 41 combined_pars = [] 42 demo = {} 40 43 for k, part in enumerate(parts): 41 44 # Parameter prefix per model, A_, B_, ... … … 43 46 # to support vector parameters 44 47 prefix = chr(ord('A')+k) + '_' 45 combined_pars.append(Parameter(prefix+'scale')) 48 scale = Parameter(prefix+'scale', default=1.0, 49 description="model intensity for " + part.name) 50 combined_pars.append(scale) 46 51 for p in part.parameters.kernel_parameters: 47 52 p = copy(p) … … 51 56 p.length_control = prefix + p.length_control 52 57 combined_pars.append(p) 58 demo.update((prefix+k, v) for k, v in part.demo.items() 59 if k != "background") 60 #print("pars",combined_pars) 53 61 parameters = ParameterTable(combined_pars) 62 parameters.max_pd = sum(part.parameters.max_pd for part in parts) 54 63 55 64 model_info = ModelInfo() … … 70 79 # Remember the component info blocks so we can build the model 71 80 model_info.composition = ('mixture', parts) 81 model_info.demo = demo 82 return model_info 72 83 73 84 … … 78 89 self.parts = parts 79 90 80 def __call__(self, q_vectors):91 def make_kernel(self, q_vectors): 81 92 # type: (List[np.ndarray]) -> MixtureKernel 82 93 # Note: may be sending the q_vectors to the n times even though they … … 104 115 self.info = model_info 105 116 self.kernels = kernels 106 107 def __call__(self, call_details, value, weight, cutoff): 108 # type: (CallDetails, np.ndarray, np.ndarry, float) -> np.ndarray 109 scale, background = value[0:2] 117 self.dtype = self.kernels[0].dtype 118 119 def __call__(self, call_details, values, cutoff, magnetic): 120 # type: (CallDetails, np.ndarray, np.ndarry, float, bool) -> np.ndarray 121 scale, background = values[0:2] 110 122 total = 0.0 111 123 # remember the parts for plotting later 112 124 self.results = [] 113 for kernel, kernel_details in zip(self.kernels, call_details.parts): 114 part_result = kernel(kernel_details, value, weight, cutoff) 115 total += part_result 116 self.results.append(part_result) 125 offset = 2 # skip scale & background 126 parts = MixtureParts(self.info, self.kernels, call_details, values) 127 for kernel, kernel_details, kernel_values in parts: 128 #print("calling kernel", kernel.info.name) 129 result = kernel(kernel_details, kernel_values, cutoff, magnetic) 130 #print(kernel.info.name, result) 131 total += result 132 self.results.append(result) 117 133 118 134 return scale*total + background … … 123 139 k.release() 124 140 141 142 class MixtureParts(object): 143 def __init__(self, model_info, kernels, call_details, values): 144 # type: (ModelInfo, List[Kernel], CallDetails, np.ndarray) -> None 145 self.model_info = model_info 146 self.parts = model_info.composition[1] 147 self.kernels = kernels 148 self.call_details = call_details 149 self.values = values 150 self.spin_index = model_info.parameters.npars + 2 151 #call_details.show(values) 152 153 def __iter__(self): 154 # type: () -> PartIterable 155 self.part_num = 0 156 self.par_index = 2 157 self.mag_index = self.spin_index + 3 158 return self 159 160 def next(self): 161 # type: () -> Tuple[List[Callable], CallDetails, np.ndarray] 162 if self.part_num >= len(self.parts): 163 raise StopIteration() 164 info = self.parts[self.part_num] 165 kernel = self.kernels[self.part_num] 166 call_details = self._part_details(info, self.par_index) 167 values = self._part_values(info, self.par_index, self.mag_index) 168 values = values.astype(kernel.dtype) 169 #call_details.show(values) 170 171 self.part_num += 1 172 self.par_index += info.parameters.npars + 1 173 self.mag_index += 3 * len(info.parameters.magnetism_index) 174 175 return kernel, call_details, values 176 177 def _part_details(self, info, par_index): 178 # type: (ModelInfo, int) -> CallDetails 179 full = self.call_details 180 # par_index is index into values array of the current parameter, 181 # which includes the initial scale and background parameters. 182 # We want the index into the weight length/offset for each parameter. 183 # Exclude the initial scale and background, so subtract two, but each 184 # component has its own scale factor which we need to skip when 185 # constructing the details for the kernel, so add one, giving a 186 # net subtract one. 187 index = slice(par_index - 1, par_index - 1 + info.parameters.npars) 188 length = full.length[index] 189 offset = full.offset[index] 190 # The complete weight vector is being sent to each part so that 191 # offsets don't need to be adjusted. 192 part = make_details(info, length, offset, full.num_weights) 193 return part 194 195 def _part_values(self, info, par_index, mag_index): 196 # type: (ModelInfo, int, int) -> np.ndarray 197 #print(info.name, par_index, self.values[par_index:par_index + info.parameters.npars + 1]) 198 scale = self.values[par_index] 199 pars = self.values[par_index + 1:par_index + info.parameters.npars + 1] 200 nmagnetic = len(info.parameters.magnetism_index) 201 if nmagnetic: 202 spin_state = self.values[self.spin_index:self.spin_index + 3] 203 mag_index = self.values[mag_index:mag_index + 3 * nmagnetic] 204 else: 205 spin_state = [] 206 mag_index = [] 207 nvalues = self.model_info.parameters.nvalues 208 nweights = self.call_details.num_weights 209 weights = self.values[nvalues:nvalues+2*nweights] 210 zero = self.values.dtype.type(0.) 211 values = [[scale, zero], pars, spin_state, mag_index, weights] 212 # Pad value array to a 32 value boundary 213 spacer = (32 - sum(len(v) for v in values)%32)%32 214 values.append([zero]*spacer) 215 values = np.hstack(values).astype(self.kernels[0].dtype) 216 return values -
sasmodels/sasview_model.py
rfd19811 rbde38b5 24 24 from . import weights 25 25 from . import modelinfo 26 from .details import build_details, dispersion_mesh26 from .details import make_kernel_args, dispersion_mesh 27 27 28 28 try: … … 565 565 parameters = self._model_info.parameters 566 566 pairs = [self._get_weights(p) for p in parameters.call_parameters] 567 call_details, values, is_magnetic = build_details(calculator, pairs)567 call_details, values, is_magnetic = make_kernel_args(calculator, pairs) 568 568 #call_details.show() 569 569 #print("pairs", pairs)
Note: See TracChangeset
for help on using the changeset viewer.