Skip to content

Commit d73791a

Browse files
authored
Chore/sof 1549 (#32)
* feat: calculate dimensions from reciprocal lattice * chore: add made.js to peerDependencies * fix: import of ReciprocalLattice * fix: undefined indices * chore: adjust complementary indices * chore: add isUsingJinjaVariable logic * chore: disable preferKPPRA when using Jinja variables * chore: adjust default dimensions * chore: decrease default KPPRA * chore: add ConvergenceParameter classes * chore: add scope variable for non-uniform kgrid * chore: generalize convergence subworkflow * chore: use stringify for initialValue property * refactor: move k-grid related functions to ReciprocalLattice * chore: add reciprocal vector ratios to form * style: adjust precision of ratios + remove array buttons * style: adjust name and position of reciprocalVectorRatios * fix: typo in ui schema directive * chore: add increment units to convergence subworkflow * chore: handle context variables of parameter step unit * fix: increment undefined in factory * chore: adjust order of initializing units * fix: initial value missing in increment * fix: typo * chore: use initial value as string * chore: use parameter instead of destructuring * chore: use context property from local scope * chore: generalize boolean logic for vector type * chore: use lodash for rounding to precision * chore: ensure float value for context variable * chore: rename non-uniform N_k parameter * chore: add names to convergence units * feat: calculate dimension from spacing * chore: round calculated spacing to 3 decimals * refactor: reciprocral lattice functions + reordering use single instance of reciprocal lattice in order to avoid creating an instance every time the function is called. Also functions setting defaults are grouped together. * chore: use closure for uiSchema functions * chore: initialize recLattice before calculating defaults * fix: form description is not shown correctly * style: adjust default classnames * style: add custom classname for select widget * chore: calculate spacing in 1/Ang * chore: use default value for units * chore: made.js++ * chore: made.js++
1 parent 256f023 commit d73791a

File tree

2 files changed

+169
-78
lines changed

2 files changed

+169
-78
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"@exabyte-io/code.js": "2022.11.11-0",
5151
"@exabyte-io/eslint-config": "^2022.11.17-0",
5252
"@exabyte-io/ide.js": "2022.7.28-1",
53-
"@exabyte-io/made.js": "2023.3.6-0",
53+
"@exabyte-io/made.js": "2023.3.8-0",
5454
"@exabyte-io/mode.js": "2022.10.11-0",
5555
"chai": "^4.3.4",
5656
"eslint": "7.32.0",

src/context/providers/PointsGridFormDataProvider.js

Lines changed: 168 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { units as UNITS } from "@exabyte-io/code.js/dist/constants";
12
import { JSONSchemaFormDataProvider, MaterialContextMixin } from "@exabyte-io/code.js/dist/context";
23
import { math as codeJSMath } from "@exabyte-io/code.js/dist/math";
34
import { Made } from "@exabyte-io/made.js";
@@ -13,13 +14,22 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
1314
constructor(config) {
1415
super(config);
1516
this._divisor = config.divisor || 1; // KPPRA will be divided by this number
17+
this.reciprocalLattice = new Made.ReciprocalLattice(this.material.lattice);
1618

1719
this.dimensions = lodash.get(this.data, "dimensions") || this._defaultDimensions;
1820
this.shifts = lodash.get(this.data, "shifts") || this._defaultShifts;
1921

2022
// 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";
2333
}
2434

2535
// eslint-disable-next-line class-methods-use-this
@@ -28,26 +38,61 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
2838
}
2939

3040
get _defaultDimensions() {
31-
return this._getGridFromKPPRA(this._defaultKPPRA).dimensions;
41+
return this.calculateDimensions({
42+
gridMetricType: "KPPRA",
43+
gridMetricValue: this._getDefaultGridMetricValue("KPPRA"),
44+
});
3245
}
3346

3447
get _defaultShifts() {
3548
return Array(3).fill(this.getDefaultShift());
3649
}
3750

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;
4087
}
4188

4289
get reciprocalVectorRatios() {
43-
const lattice = new Made.ReciprocalLattice(this.material.lattice);
44-
return lattice.reciprocalVectorRatios.map((r) =>
90+
return this.reciprocalLattice.reciprocalVectorRatios.map((r) =>
4591
Number(codeJSMath.numberToPrecision(r, 3)),
4692
);
4793
}
4894

4995
get jsonSchema() {
50-
const kOrQ = this.name[0];
5196
const vector = {
5297
type: "array",
5398
items: {
@@ -71,55 +116,103 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
71116

72117
return {
73118
$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)}.`,
77122
type: "object",
78123
properties: {
79124
dimensions: vector_(this._defaultDimensions, this.isUsingJinjaVariables),
80125
shifts: vector_(this.getDefaultShift()),
81126
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",
86134
},
87-
preferKPPRA: {
135+
preferGridMetric: {
88136
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+
],
90179
},
91180
},
92181
required: ["dimensions", "shifts"],
93182
};
94183
}
95184

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+
};
110201
};
111-
}
112202

113-
get uiSchema() {
114203
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",
121209
},
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: {
123216
...this.fieldStyles("p-t-20"), // add padding top to level with other elements
124217
"ui:emptyValue": true,
125218
"ui:disabled": this.isUsingJinjaVariables,
@@ -136,59 +229,57 @@ export class PointsGridFormDataProvider extends mix(JSONSchemaFormDataProvider).
136229
};
137230
}
138231

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) {
162233
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);
167235
}
168236

169-
_getKPPRAFromGrid(grid = this.defaultData) {
237+
_getKPPRAFromDimensions(dimensions) {
170238
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;
172240
}
173241

174242
static _canTransform(data) {
175243
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"))
178246
);
179247
}
180248

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+
181274
transformData(data) {
182275
if (!this.constructor._canTransform(data)) {
183276
return data;
184277
}
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);
189281
} else {
190-
// 3. KPPRA is not preferred => grid was => recalculate KPPRA
191-
data.KPPRA = this._getKPPRAFromGrid(data);
282+
data.gridMetricValue = this.calculateGridMetric(data);
192283
}
193284
return data;
194285
}

0 commit comments

Comments
 (0)