1
+ import { units as UNITS } from "@exabyte-io/code.js/dist/constants" ;
1
2
import { JSONSchemaFormDataProvider , MaterialContextMixin } from "@exabyte-io/code.js/dist/context" ;
2
3
import { math as codeJSMath } from "@exabyte-io/code.js/dist/math" ;
3
4
import { Made } from "@exabyte-io/made.js" ;
@@ -13,13 +14,22 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
13
14
constructor ( config ) {
14
15
super ( config ) ;
15
16
this . _divisor = config . divisor || 1 ; // KPPRA will be divided by this number
17
+ this . reciprocalLattice = new Made . ReciprocalLattice ( this . material . lattice ) ;
16
18
17
19
this . dimensions = lodash . get ( this . data , "dimensions" ) || this . _defaultDimensions ;
18
20
this . shifts = lodash . get ( this . data , "shifts" ) || this . _defaultShifts ;
19
21
20
22
// init class fields from data (as constructed from context in parent)
21
- this . KPPRA = lodash . get ( this . data , "KPPRA" ) || this . _defaultKPPRA ;
22
- this . preferKPPRA = lodash . get ( this . data , "preferKPPRA" , false ) ;
23
+ this . gridMetricType = lodash . get ( this . data , "gridMetricType" ) || "KPPRA" ;
24
+ this . gridMetricValue =
25
+ lodash . get ( this . data , "gridMetricValue" ) || this . _getDefaultGridMetricValue ( "KPPRA" ) ;
26
+ this . preferGridMetric = lodash . get ( this . data , "preferGridMetric" , false ) ;
27
+
28
+ this . _metricDescription = {
29
+ KPPRA : `${ this . name [ 0 ] . toUpperCase ( ) } PPRA (${ this . name [ 0 ] } pt per reciprocal atom)` , // KPPRA or QPPRA
30
+ spacing : "grid spacing" ,
31
+ } ;
32
+ this . defaultClassNames = "col-xs-12 col-sm-6 col-md-3 col-lg-2" ;
23
33
}
24
34
25
35
// eslint-disable-next-line class-methods-use-this
@@ -28,26 +38,61 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
28
38
}
29
39
30
40
get _defaultDimensions ( ) {
31
- return this . _getGridFromKPPRA ( this . _defaultKPPRA ) . dimensions ;
41
+ return this . calculateDimensions ( {
42
+ gridMetricType : "KPPRA" ,
43
+ gridMetricValue : this . _getDefaultGridMetricValue ( "KPPRA" ) ,
44
+ } ) ;
32
45
}
33
46
34
47
get _defaultShifts ( ) {
35
48
return Array ( 3 ) . fill ( this . getDefaultShift ( ) ) ;
36
49
}
37
50
38
- get _defaultKPPRA ( ) {
39
- return Math . floor ( 5 / this . _divisor ) ;
51
+ _getDefaultGridMetricValue ( metric ) {
52
+ switch ( metric ) {
53
+ case "KPPRA" :
54
+ return Math . floor ( 5 / this . _divisor ) ;
55
+ case "spacing" :
56
+ return 0.3 ;
57
+ default :
58
+ console . error ( "Metric type not recognized!" ) ;
59
+ return 1 ;
60
+ }
61
+ }
62
+
63
+ get _defaultData ( ) {
64
+ return {
65
+ dimensions : this . _defaultDimensions ,
66
+ shifts : this . _defaultShifts ,
67
+ gridMetricType : "KPPRA" ,
68
+ gridMetricValue : this . _getDefaultGridMetricValue ( "KPPRA" ) ,
69
+ preferGridMetric : false ,
70
+ reciprocalVectorRatios : this . reciprocalVectorRatios ,
71
+ } ;
72
+ }
73
+
74
+ get _defaultDataWithMaterial ( ) {
75
+ const { gridMetricType, gridMetricValue } = this ;
76
+ // if `data` is present and material is updated, prioritize `data` when `preferGridMetric` is not set
77
+ return this . preferGridMetric
78
+ ? {
79
+ dimensions : this . calculateDimensions ( { gridMetricType, gridMetricValue } ) ,
80
+ shifts : this . _defaultShifts ,
81
+ }
82
+ : this . data || this . _defaultData ;
83
+ }
84
+
85
+ get defaultData ( ) {
86
+ return this . material ? this . _defaultDataWithMaterial : this . _defaultData ;
40
87
}
41
88
42
89
get reciprocalVectorRatios ( ) {
43
- const lattice = new Made . ReciprocalLattice ( this . material . lattice ) ;
44
- return lattice . reciprocalVectorRatios . map ( ( r ) =>
90
+ return this . reciprocalLattice . reciprocalVectorRatios . map ( ( r ) =>
45
91
Number ( codeJSMath . numberToPrecision ( r , 3 ) ) ,
46
92
) ;
47
93
}
48
94
49
95
get jsonSchema ( ) {
50
- const kOrQ = this . name [ 0 ] ;
51
96
const vector = {
52
97
type : "array" ,
53
98
items : {
@@ -71,55 +116,103 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
71
116
72
117
return {
73
118
$schema : "http://json-schema.org/draft-04/schema#" ,
74
- description : `3D grid with shifts. Default min value for ${ kOrQ . toUpperCase ( ) } PPRA ( ${ kOrQ } pt per reciprocal atom) is ${
75
- this . _defaultKPPRA
76
- } .`,
119
+ description : `3D grid with shifts. Default min value for ${
120
+ this . _metricDescription [ this . gridMetricType ]
121
+ } is ${ this . _getDefaultGridMetricValue ( this . gridMetricType ) } .`,
77
122
type : "object" ,
78
123
properties : {
79
124
dimensions : vector_ ( this . _defaultDimensions , this . isUsingJinjaVariables ) ,
80
125
shifts : vector_ ( this . getDefaultShift ( ) ) ,
81
126
reciprocalVectorRatios : vector_ ( this . reciprocalVectorRatios ) ,
82
- KPPRA : {
83
- type : "integer" ,
84
- minimum : 1 ,
85
- default : this . KPPRA ,
127
+ gridMetricType : {
128
+ type : "string" ,
129
+ enum : [ "KPPRA" , "spacing" ] ,
130
+ default : "KPPRA" ,
131
+ } ,
132
+ gridMetricValue : {
133
+ type : "number" ,
86
134
} ,
87
- preferKPPRA : {
135
+ preferGridMetric : {
88
136
type : "boolean" ,
89
- default : this . preferKPPRA ,
137
+ } ,
138
+ } ,
139
+ dependencies : {
140
+ gridMetricType : {
141
+ oneOf : [
142
+ {
143
+ properties : {
144
+ gridMetricType : {
145
+ enum : [ "KPPRA" ] ,
146
+ } ,
147
+ gridMetricValue : {
148
+ type : "integer" ,
149
+ minimum : 1 ,
150
+ title : "Value" ,
151
+ default : this . gridMetricValue ,
152
+ } ,
153
+ preferGridMetric : {
154
+ type : "boolean" ,
155
+ title : "prefer KPPRA" ,
156
+ default : this . preferGridMetric ,
157
+ } ,
158
+ } ,
159
+ } ,
160
+ {
161
+ properties : {
162
+ gridMetricType : {
163
+ enum : [ "spacing" ] ,
164
+ } ,
165
+ gridMetricValue : {
166
+ type : "number" ,
167
+ minimum : 0 ,
168
+ title : "Value [1/Å]" ,
169
+ default : this . gridMetricValue ,
170
+ } ,
171
+ preferGridMetric : {
172
+ type : "boolean" ,
173
+ title : "prefer spacing" ,
174
+ default : this . preferGridMetric ,
175
+ } ,
176
+ } ,
177
+ } ,
178
+ ] ,
90
179
} ,
91
180
} ,
92
181
required : [ "dimensions" , "shifts" ] ,
93
182
} ;
94
183
}
95
184
96
- _arraySubStyle ( emptyValue = 0 ) {
97
- return {
98
- "ui:options" : {
99
- addable : false ,
100
- orderable : false ,
101
- removable : false ,
102
- } ,
103
- items : {
104
- "ui:disabled" : this . preferKPPRA ,
105
- // TODO: extract the actual current values from context
106
- "ui:placeholder" : "1" ,
107
- "ui:emptyValue" : emptyValue ,
108
- "ui:label" : false ,
109
- } ,
185
+ get uiSchema ( ) {
186
+ const _arraySubStyle = ( emptyValue = 0 ) => {
187
+ return {
188
+ "ui:options" : {
189
+ addable : false ,
190
+ orderable : false ,
191
+ removable : false ,
192
+ } ,
193
+ items : {
194
+ "ui:disabled" : this . preferGridMetric ,
195
+ // TODO: extract the actual current values from context
196
+ "ui:placeholder" : "1" ,
197
+ "ui:emptyValue" : emptyValue ,
198
+ "ui:label" : false ,
199
+ } ,
200
+ } ;
110
201
} ;
111
- }
112
202
113
- get uiSchema ( ) {
114
203
return {
115
- dimensions : this . _arraySubStyle ( 1 ) ,
116
- shifts : this . _arraySubStyle ( 0 ) ,
117
- KPPRA : {
118
- "ui:disabled" : ! this . preferKPPRA ,
119
- "ui:emptyValue" : this . KPPRA ,
120
- "ui:placeholder" : this . KPPRA . toString ( ) , // make string to prevent prop type error
204
+ dimensions : _arraySubStyle ( 1 ) ,
205
+ shifts : _arraySubStyle ( 0 ) ,
206
+ gridMetricType : {
207
+ ...this . fieldStyles ( "rjsf-select" ) ,
208
+ "ui:title" : "Grid Metric" ,
121
209
} ,
122
- preferKPPRA : {
210
+ gridMetricValue : {
211
+ "ui:disabled" : ! this . preferGridMetric ,
212
+ "ui:emptyValue" : this . gridMetricValue ,
213
+ "ui:placeholder" : this . gridMetricValue . toString ( ) , // make string to prevent prop type error
214
+ } ,
215
+ preferGridMetric : {
123
216
...this . fieldStyles ( "p-t-20" ) , // add padding top to level with other elements
124
217
"ui:emptyValue" : true ,
125
218
"ui:disabled" : this . isUsingJinjaVariables ,
@@ -136,59 +229,57 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
136
229
} ;
137
230
}
138
231
139
- get _defaultData ( ) {
140
- return {
141
- dimensions : this . _defaultDimensions ,
142
- shifts : this . _defaultShifts ,
143
- KPPRA : this . _defaultKPPRA ,
144
- preferKPPRA : false ,
145
- reciprocalVectorRatios : this . reciprocalVectorRatios ,
146
- } ;
147
- }
148
-
149
- get _defaultDataWithMaterial ( ) {
150
- // if `data` is present and material is updated, prioritize `data` when `preferKPPRA` is not set
151
- return this . preferKPPRA
152
- ? this . _getGridFromKPPRA ( this . KPPRA )
153
- : this . data || this . _defaultData ;
154
- }
155
-
156
- get defaultData ( ) {
157
- return this . material ? this . _defaultDataWithMaterial : this . _defaultData ;
158
- }
159
-
160
- _getGridFromKPPRA ( KPPRA ) {
161
- const reciprocalLattice = new Made . ReciprocalLattice ( this . material . lattice ) ;
232
+ _getDimensionsFromKPPRA ( KPPRA ) {
162
233
const nAtoms = this . material ? this . material . Basis . nAtoms : 1 ;
163
- return {
164
- dimensions : reciprocalLattice . getDimensionsFromPointsCount ( KPPRA / nAtoms ) ,
165
- shifts : this . _defaultShifts ,
166
- } ;
234
+ return this . reciprocalLattice . getDimensionsFromPointsCount ( KPPRA / nAtoms ) ;
167
235
}
168
236
169
- _getKPPRAFromGrid ( grid = this . defaultData ) {
237
+ _getKPPRAFromDimensions ( dimensions ) {
170
238
const nAtoms = this . material ? this . material . Basis . nAtoms : 1 ;
171
- return grid . dimensions . reduce ( ( a , b ) => a * b ) * nAtoms ;
239
+ return dimensions . reduce ( ( a , b ) => a * b ) * nAtoms ;
172
240
}
173
241
174
242
static _canTransform ( data ) {
175
243
return (
176
- ( data . preferKPPRA && data . KPPRA ) ||
177
- ( ! data . preferKPPRA && data . dimensions . every ( ( d ) => typeof d === "number" ) )
244
+ ( data . preferGridMetric && data . gridMetricType && data . gridMetricValue ) ||
245
+ ( ! data . preferGridMetric && data . dimensions . every ( ( d ) => typeof d === "number" ) )
178
246
) ;
179
247
}
180
248
249
+ calculateDimensions ( { gridMetricType, gridMetricValue, units = UNITS . angstrom } ) {
250
+ switch ( gridMetricType ) {
251
+ case "KPPRA" :
252
+ return this . _getDimensionsFromKPPRA ( gridMetricValue ) ;
253
+ case "spacing" :
254
+ return this . reciprocalLattice . getDimensionsFromSpacing ( gridMetricValue , units ) ;
255
+ default :
256
+ return [ 1 , 1 , 1 ] ;
257
+ }
258
+ }
259
+
260
+ calculateGridMetric ( { gridMetricType, dimensions, units = UNITS . angstrom } ) {
261
+ switch ( gridMetricType ) {
262
+ case "KPPRA" :
263
+ return this . _getKPPRAFromDimensions ( dimensions ) ;
264
+ case "spacing" :
265
+ return lodash . round (
266
+ this . reciprocalLattice . getSpacingFromDimensions ( dimensions , units ) ,
267
+ 3 ,
268
+ ) ;
269
+ default :
270
+ return 1 ;
271
+ }
272
+ }
273
+
181
274
transformData ( data ) {
182
275
if ( ! this . constructor . _canTransform ( data ) ) {
183
276
return data ;
184
277
}
185
- // 1. check if KPPRA is preferred
186
- if ( data . preferKPPRA ) {
187
- // 2. KPPRA is preferred => recalculate grid; NOTE: `data.KPPRA` is undefined at first
188
- data . dimensions = this . _getGridFromKPPRA ( data . KPPRA ) . dimensions ;
278
+ // dimensions are calculated from grid metric or vice versa
279
+ if ( data . preferGridMetric ) {
280
+ data . dimensions = this . calculateDimensions ( data ) ;
189
281
} else {
190
- // 3. KPPRA is not preferred => grid was => recalculate KPPRA
191
- data . KPPRA = this . _getKPPRAFromGrid ( data ) ;
282
+ data . gridMetricValue = this . calculateGridMetric ( data ) ;
192
283
}
193
284
return data ;
194
285
}
0 commit comments