@mat3ra/mode 2025.11.3-0 → 2025.11.5-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +32 -17
- package/src/js/default_methods.ts +36 -0
- package/src/js/default_models.ts +11 -0
- package/src/js/generated/MethodSchemaMixin.ts +26 -0
- package/src/js/generated/ModelSchemaMixin.ts +23 -0
- package/src/{index.js → js/index.ts} +1 -1
- package/src/js/method.ts +67 -0
- package/src/js/methodConversionHandler.ts +142 -0
- package/src/{methods/factory.js → js/methods/factory.ts} +3 -1
- package/src/js/methods/pseudopotential.ts +86 -0
- package/src/js/model.ts +168 -0
- package/src/js/modelConversionHandler.ts +102 -0
- package/src/js/models/dft.ts +110 -0
- package/src/{models/factory.js → js/models/factory.ts} +9 -4
- package/src/{tree.js → js/tree.ts} +26 -20
- package/src/js/types/index.ts +37 -0
- package/tsconfig.json +3 -0
- package/.babelrc +0 -17
- package/dist/data/method_list.js +0 -1132
- package/dist/data/model_list.js +0 -786
- package/dist/data/model_method_map.js +0 -82
- package/dist/default_methods.js +0 -39
- package/dist/default_models.js +0 -14
- package/dist/index.js +0 -69
- package/dist/method.js +0 -84
- package/dist/methodConversionHandler.js +0 -128
- package/dist/methods/factory.js +0 -24
- package/dist/methods/pseudopotential.js +0 -100
- package/dist/model.js +0 -123
- package/dist/modelConversionHandler.js +0 -102
- package/dist/models/dft.js +0 -102
- package/dist/models/factory.js +0 -36
- package/dist/tree.js +0 -147
- package/src/data/method_list.js +0 -2
- package/src/data/model_list.js +0 -2
- package/src/data/model_method_map.js +0 -2
- package/src/default_methods.js +0 -38
- package/src/default_models.js +0 -9
- package/src/method.js +0 -77
- package/src/methodConversionHandler.js +0 -125
- package/src/methods/pseudopotential.js +0 -99
- package/src/model.js +0 -127
- package/src/modelConversionHandler.js +0 -91
- package/src/models/dft.js +0 -115
package/package.json
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mat3ra/mode",
|
|
3
|
-
"version": "2025.11.
|
|
3
|
+
"version": "2025.11.5-0",
|
|
4
4
|
"description": "MOdel and method DEfinitions",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"test": "nyc --reporter=text mocha --recursive --bail --require
|
|
6
|
+
"test": "nyc --reporter=text mocha --extension ts --recursive --bail --require ts-node/register/transpile-only \"tests/**/*.test.ts\"",
|
|
7
|
+
"pretest": "npm run transpile",
|
|
7
8
|
"lint": "eslint src tests && prettier --write src tests",
|
|
8
9
|
"lint:fix": "eslint --fix --cache src tests && prettier --write src tests",
|
|
9
|
-
"transpile": "
|
|
10
|
-
"
|
|
10
|
+
"transpile": "npm run transpile:js && npm run transpile:ts",
|
|
11
|
+
"transpile:js": "babel --out-dir dist src",
|
|
12
|
+
"transpile:ts": "tsc --project tsconfig.json",
|
|
11
13
|
"prettier": "prettier --check src tests",
|
|
12
14
|
"prepare": "husky install || exit 0",
|
|
13
|
-
"prepublishOnly": "rm -rf dist; npm run transpile"
|
|
15
|
+
"prepublishOnly": "rm -rf dist; npm run transpile",
|
|
16
|
+
"generate-mixins": "ts-node scripts/generate-mixins.ts"
|
|
14
17
|
},
|
|
15
18
|
"repository": {
|
|
16
19
|
"type": "git",
|
|
17
20
|
"url": "https://github.com/Exabyte-io/mode.git"
|
|
18
21
|
},
|
|
19
22
|
"main": "dist/index.js",
|
|
23
|
+
"types": "dist/js/index.d.ts",
|
|
20
24
|
"files": [
|
|
21
25
|
"/dist",
|
|
22
26
|
"/src",
|
|
23
|
-
".
|
|
27
|
+
"tsconfig.json"
|
|
24
28
|
],
|
|
25
29
|
"author": "Exabyte Inc.",
|
|
26
30
|
"bugs": {
|
|
@@ -37,29 +41,40 @@
|
|
|
37
41
|
"@babel/preset-react": "7.16.7",
|
|
38
42
|
"@babel/register": "^7.16.0",
|
|
39
43
|
"@babel/runtime-corejs3": "7.16.8",
|
|
44
|
+
"@types/lodash": "^4.14.202",
|
|
45
|
+
"@types/underscore": "^1.11.14",
|
|
46
|
+
"@types/node": "^20.11.30",
|
|
40
47
|
"ajv": "^8.12.0",
|
|
41
48
|
"js-yaml": "^4.1.0",
|
|
42
49
|
"lodash": "^4.17.21",
|
|
43
50
|
"mixwith": "^0.1.1",
|
|
51
|
+
"ts-node": "^10.9.2",
|
|
52
|
+
"typescript": "^5.4.0",
|
|
44
53
|
"underscore": "^1.13.3",
|
|
45
54
|
"underscore.string": "^3.3.4"
|
|
46
55
|
},
|
|
47
56
|
"devDependencies": {
|
|
48
|
-
"@exabyte-io/eslint-config": "
|
|
49
|
-
"@mat3ra/esse": "
|
|
57
|
+
"@exabyte-io/eslint-config": "2025.5.13-0",
|
|
58
|
+
"@mat3ra/esse": "2025.10.8-0",
|
|
50
59
|
"@mat3ra/standata": "2025.10.2-0",
|
|
51
|
-
"@mat3ra/code": "
|
|
60
|
+
"@mat3ra/code": "2025.10.8-0",
|
|
61
|
+
"@mat3ra/tsconfig": "2024.6.3-0",
|
|
62
|
+
"@types/chai": "^4.3.11",
|
|
63
|
+
"@types/mocha": "^10.0.6",
|
|
52
64
|
"chai": "^4.3.4",
|
|
53
|
-
"eslint": "7.32.0",
|
|
54
|
-
"eslint-config-airbnb": "19.0.2",
|
|
65
|
+
"eslint": "^7.32.0",
|
|
66
|
+
"eslint-config-airbnb": "^19.0.2",
|
|
55
67
|
"eslint-config-prettier": "^8.5.0",
|
|
56
|
-
"eslint-import-resolver-exports": "^1.0.0-beta.
|
|
57
|
-
"eslint-
|
|
58
|
-
"eslint-
|
|
59
|
-
"eslint-plugin-
|
|
68
|
+
"eslint-import-resolver-exports": "^1.0.0-beta.5",
|
|
69
|
+
"eslint-import-resolver-meteor": "^0.4.0",
|
|
70
|
+
"eslint-import-resolver-node": "^0.3.9",
|
|
71
|
+
"eslint-plugin-import": "^2.25.3",
|
|
72
|
+
"eslint-plugin-jsdoc": "^37.1.0",
|
|
73
|
+
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
74
|
+
"eslint-plugin-mui-path-imports": "0.0.15",
|
|
60
75
|
"eslint-plugin-prettier": "^4.2.1",
|
|
61
|
-
"eslint-plugin-react": "7.30.0",
|
|
62
|
-
"eslint-plugin-simple-import-sort": "7.0.0",
|
|
76
|
+
"eslint-plugin-react": "^7.30.0",
|
|
77
|
+
"eslint-plugin-simple-import-sort": "^7.0.0",
|
|
63
78
|
"husky": "^7.0.4",
|
|
64
79
|
"lint-staged": "^12.1.2",
|
|
65
80
|
"mocha": "^9.1.3",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseMethod, BaseModel, SlugifiedEntry } from "@mat3ra/esse/dist/js/types";
|
|
2
|
+
import lodash from "lodash";
|
|
3
|
+
|
|
4
|
+
import { MODEL_NAMES, MODEL_TREE } from "./tree";
|
|
5
|
+
|
|
6
|
+
export const PseudopotentialMethodConfig: BaseMethod = {
|
|
7
|
+
type: "pseudopotential",
|
|
8
|
+
subtype: "us",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const LocalOrbitalMethodConfig: BaseMethod = {
|
|
12
|
+
type: "localorbital",
|
|
13
|
+
subtype: "pople",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const UnknownMethodConfig: BaseMethod = {
|
|
17
|
+
type: "unknown",
|
|
18
|
+
subtype: "unknown",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const mapSlugToNamedObject = (slug: string): SlugifiedEntry => {
|
|
22
|
+
return {
|
|
23
|
+
slug,
|
|
24
|
+
name: lodash.get(MODEL_NAMES, slug, slug),
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function allowedTypes(model: Pick<BaseModel, "type" | "subtype">): SlugifiedEntry[] {
|
|
29
|
+
const branch = lodash.get(MODEL_TREE, `${model.type}.${model.subtype}.methods`, {});
|
|
30
|
+
return lodash.keys(branch).map(mapSlugToNamedObject);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function allowedSubtypes(model: Pick<BaseModel, "type" | "subtype">, type: string): SlugifiedEntry[] {
|
|
34
|
+
const branch = lodash.get(MODEL_TREE, `${model.type}.${model.subtype}.methods.${type}`, []);
|
|
35
|
+
return (branch as string[]).map(mapSlugToNamedObject);
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
|
|
2
|
+
import type { BaseMethod } from "@mat3ra/esse/dist/js/types";
|
|
3
|
+
|
|
4
|
+
export type MethodSchemaMixin = BaseMethod;
|
|
5
|
+
|
|
6
|
+
export type MethodInMemoryEntity = InMemoryEntity & MethodSchemaMixin;
|
|
7
|
+
|
|
8
|
+
export function methodSchemaMixin(item: InMemoryEntity) {
|
|
9
|
+
// @ts-expect-error
|
|
10
|
+
const properties: InMemoryEntity & MethodSchemaMixin = {
|
|
11
|
+
get type() {
|
|
12
|
+
return this.requiredProp<BaseMethod["type"]>("type");
|
|
13
|
+
},
|
|
14
|
+
get subtype() {
|
|
15
|
+
return this.requiredProp<BaseMethod["subtype"]>("subtype");
|
|
16
|
+
},
|
|
17
|
+
get precision() {
|
|
18
|
+
return this.prop<BaseMethod["precision"]>("precision");
|
|
19
|
+
},
|
|
20
|
+
get data() {
|
|
21
|
+
return this.prop<BaseMethod["data"]>("data");
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties));
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
|
|
2
|
+
import type { BaseModel } from "@mat3ra/esse/dist/js/types";
|
|
3
|
+
|
|
4
|
+
export type ModelSchemaMixin = BaseModel;
|
|
5
|
+
|
|
6
|
+
export type ModelInMemoryEntity = InMemoryEntity & ModelSchemaMixin;
|
|
7
|
+
|
|
8
|
+
export function modelSchemaMixin(item: InMemoryEntity) {
|
|
9
|
+
// @ts-expect-error
|
|
10
|
+
const properties: InMemoryEntity & ModelSchemaMixin = {
|
|
11
|
+
get type() {
|
|
12
|
+
return this.requiredProp<BaseModel["type"]>("type");
|
|
13
|
+
},
|
|
14
|
+
get subtype() {
|
|
15
|
+
return this.requiredProp<BaseModel["subtype"]>("subtype");
|
|
16
|
+
},
|
|
17
|
+
get method() {
|
|
18
|
+
return this.requiredProp<BaseModel["method"]>("method");
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties));
|
|
23
|
+
}
|
|
@@ -8,7 +8,6 @@ import { Model } from "./model";
|
|
|
8
8
|
import { ModelConversionHandler } from "./modelConversionHandler";
|
|
9
9
|
import { DFTModel } from "./models/dft";
|
|
10
10
|
import { ModelFactory } from "./models/factory";
|
|
11
|
-
// TODO : can replace these with subpackages in exports in package.json
|
|
12
11
|
import * as tree from "./tree";
|
|
13
12
|
|
|
14
13
|
export {
|
|
@@ -24,3 +23,4 @@ export {
|
|
|
24
23
|
default_models,
|
|
25
24
|
default_methods,
|
|
26
25
|
};
|
|
26
|
+
|
package/src/js/method.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
|
|
2
|
+
import { deepClone } from "@mat3ra/code/dist/js/utils";
|
|
3
|
+
import type { Constructor } from "@mat3ra/code/dist/js/utils/types";
|
|
4
|
+
import type { BaseMethod, SlugifiedEntry } from "@mat3ra/esse/dist/js/types";
|
|
5
|
+
import lodash from "lodash";
|
|
6
|
+
|
|
7
|
+
import { PseudopotentialMethodConfig } from "./default_methods";
|
|
8
|
+
import { type MethodSchemaMixin, methodSchemaMixin } from "./generated/MethodSchemaMixin";
|
|
9
|
+
|
|
10
|
+
type Base = typeof InMemoryEntity & Constructor<MethodSchemaMixin>;
|
|
11
|
+
|
|
12
|
+
interface MethodData extends Record<string, unknown> {
|
|
13
|
+
searchText?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Method extends (InMemoryEntity as Base) implements BaseMethod {
|
|
17
|
+
constructor(config: BaseMethod) {
|
|
18
|
+
const data = config.data || {};
|
|
19
|
+
super({ ...config, data });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
cloneWithoutData(): Method {
|
|
23
|
+
const clone = this.clone() as Method;
|
|
24
|
+
clone.setData({});
|
|
25
|
+
return clone;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setSubtype(subtype: SlugifiedEntry): void {
|
|
29
|
+
this.setProp("subtype", subtype);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static get defaultConfig(): BaseMethod {
|
|
33
|
+
return PseudopotentialMethodConfig;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get searchText(): string {
|
|
37
|
+
return this.prop<string>("data.searchText", "");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setSearchText(searchText: string): void {
|
|
41
|
+
this.setData({ ...this.data, searchText });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setData(data: MethodData = {}): void {
|
|
45
|
+
this.setProp("data", data);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get omitInHashCalculation(): boolean {
|
|
49
|
+
const data = this.data as MethodData;
|
|
50
|
+
return !data?.searchText && lodash.isEmpty(lodash.omit(data, "searchText"));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
cleanData(fieldsToExclude: string[] = []): MethodData {
|
|
54
|
+
const filteredData = { ...(this.data as MethodData) };
|
|
55
|
+
fieldsToExclude.forEach((field) => {
|
|
56
|
+
delete filteredData[field];
|
|
57
|
+
});
|
|
58
|
+
return filteredData;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
toJSONWithCleanData(fieldsToExclude: string[] = []): BaseMethod {
|
|
62
|
+
const json = { ...this._json, data: this.cleanData(fieldsToExclude) };
|
|
63
|
+
return deepClone(json);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
methodSchemaMixin(Method.prototype);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseMethod,
|
|
3
|
+
CategorizedMethod,
|
|
4
|
+
CategorizedUnitMethod,
|
|
5
|
+
SlugifiedEntry,
|
|
6
|
+
} from "@mat3ra/esse/dist/js/types";
|
|
7
|
+
|
|
8
|
+
import { LocalOrbitalMethodConfig, UnknownMethodConfig } from "./default_methods";
|
|
9
|
+
import type { SimplifiedCategorizedMethod } from "./types";
|
|
10
|
+
|
|
11
|
+
export function safelyGetSlug(slugObj: SlugifiedEntry | string): SlugifiedEntry["slug"] {
|
|
12
|
+
return typeof slugObj === "string" ? slugObj : slugObj.slug;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class MethodConversionHandler {
|
|
16
|
+
static convertToSimple(categorizedMethod: CategorizedMethod | undefined): BaseMethod {
|
|
17
|
+
if (!categorizedMethod) return this.convertUnknownToSimple();
|
|
18
|
+
const pspUnits = categorizedMethod.units.filter((unit) => unit.categories?.type === "psp");
|
|
19
|
+
const aoUnit = categorizedMethod.units.find((unit) => unit.categories?.type === "ao");
|
|
20
|
+
const regressionUnit = categorizedMethod.units.find((unit) => {
|
|
21
|
+
return unit.name && unit.name.includes("regression");
|
|
22
|
+
});
|
|
23
|
+
if (pspUnits.length) return this.convertPspUnitsToSimple(pspUnits);
|
|
24
|
+
if (aoUnit) return this.convertAoUnitToSimple();
|
|
25
|
+
if (regressionUnit) return this.convertRegressionUnitToSimple(regressionUnit);
|
|
26
|
+
return this.convertUnknownToSimple();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static convertUnknownToSimple(): BaseMethod {
|
|
30
|
+
return UnknownMethodConfig;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static convertPspUnitsToSimple(units: CategorizedUnitMethod[]): BaseMethod {
|
|
34
|
+
const [firstUnit, ...otherUnits] = units;
|
|
35
|
+
if (!firstUnit || !firstUnit.categories?.subtype) return this.convertUnknownToSimple();
|
|
36
|
+
const subtype = otherUnits.length ? "any" : safelyGetSlug(firstUnit.categories.subtype);
|
|
37
|
+
return {
|
|
38
|
+
type: "pseudopotential",
|
|
39
|
+
subtype,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static convertAoUnitToSimple(): BaseMethod {
|
|
44
|
+
return LocalOrbitalMethodConfig;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static convertRegressionUnitToSimple(unit: CategorizedUnitMethod): BaseMethod {
|
|
48
|
+
const type = unit.categories?.type || "linear";
|
|
49
|
+
const subtype = unit.categories?.subtype || "least_squares";
|
|
50
|
+
return {
|
|
51
|
+
type: safelyGetSlug(type),
|
|
52
|
+
subtype: safelyGetSlug(subtype),
|
|
53
|
+
precision: unit.precision as number | undefined,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static convertToCategorized(
|
|
58
|
+
simpleMethod: BaseMethod | undefined,
|
|
59
|
+
allMethods: CategorizedMethod[] = [],
|
|
60
|
+
): SimplifiedCategorizedMethod | undefined {
|
|
61
|
+
switch (simpleMethod?.type) {
|
|
62
|
+
case "pseudopotential":
|
|
63
|
+
return this.convertPspToCategorized(simpleMethod, allMethods);
|
|
64
|
+
case "localorbital":
|
|
65
|
+
return this.convertAoToCategorized(simpleMethod);
|
|
66
|
+
case "linear":
|
|
67
|
+
case "kernel_ridge":
|
|
68
|
+
return this.convertRegressionToCategorized(simpleMethod);
|
|
69
|
+
default:
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static convertPspToCategorized(
|
|
75
|
+
simpleMethod: BaseMethod,
|
|
76
|
+
allMethods: CategorizedMethod[] = [],
|
|
77
|
+
): SimplifiedCategorizedMethod | undefined {
|
|
78
|
+
const subtype = safelyGetSlug(simpleMethod.subtype);
|
|
79
|
+
// the "any" subtype is equivalent to the method representing all planewave-pseudopotential
|
|
80
|
+
// methods. All other subtypes are equivalent to using a specific PW-PSP method.
|
|
81
|
+
const allPath =
|
|
82
|
+
"/qm/wf/none/psp/us::/qm/wf/none/psp/nc::/qm/wf/none/psp/nc-fr::/qm/wf/none/psp/paw::/qm/wf/none/pw/none";
|
|
83
|
+
const path =
|
|
84
|
+
subtype === "any"
|
|
85
|
+
? allPath
|
|
86
|
+
: `/qm/wf/none/smearing/gaussian::/linalg/diag/none/davidson/none::/qm/wf/none/psp/${subtype}::/qm/wf/none/pw/none`;
|
|
87
|
+
return allMethods.find((categorized) => categorized.path === path);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static convertAoToCategorized(simpleMethod: BaseMethod): SimplifiedCategorizedMethod {
|
|
91
|
+
const subtype = safelyGetSlug(simpleMethod.subtype);
|
|
92
|
+
return {
|
|
93
|
+
units: [
|
|
94
|
+
{
|
|
95
|
+
parameters: {
|
|
96
|
+
basisSlug: "6-31G",
|
|
97
|
+
},
|
|
98
|
+
categories: {
|
|
99
|
+
tier1: "qm",
|
|
100
|
+
tier2: "wf",
|
|
101
|
+
type: "ao",
|
|
102
|
+
subtype,
|
|
103
|
+
},
|
|
104
|
+
tags: ["atomic orbital"],
|
|
105
|
+
name: "Wave function: LCAO - Pople basis set (6-31G)",
|
|
106
|
+
path: "/qm/wf/none/ao/pople?basisSlug=6-31G",
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
name: "Wave function: LCAO - Pople basis set (6-31G)",
|
|
110
|
+
path: "/qm/wf/none/ao/pople?basisSlug=6-31G",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static convertRegressionToCategorized(simpleMethod: BaseMethod): SimplifiedCategorizedMethod {
|
|
115
|
+
const type = safelyGetSlug(simpleMethod.type);
|
|
116
|
+
const subtype = safelyGetSlug(simpleMethod.subtype);
|
|
117
|
+
const precision = simpleMethod.precision as number | undefined;
|
|
118
|
+
const path = `/none/none/none/${type}/${subtype}`;
|
|
119
|
+
const nameMap: Record<string, string> = {
|
|
120
|
+
kernel_ridge: "Kernel ridge",
|
|
121
|
+
linear: "Linear",
|
|
122
|
+
least_squares: "least squares",
|
|
123
|
+
ridge: "ridge",
|
|
124
|
+
};
|
|
125
|
+
const name = `${nameMap[type] || type} ${nameMap[subtype] || subtype} regression`;
|
|
126
|
+
return {
|
|
127
|
+
units: [
|
|
128
|
+
{
|
|
129
|
+
categories: {
|
|
130
|
+
type,
|
|
131
|
+
subtype,
|
|
132
|
+
},
|
|
133
|
+
name,
|
|
134
|
+
path,
|
|
135
|
+
precision,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
name,
|
|
139
|
+
path,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { BaseMethod } from "@mat3ra/esse/dist/js/types";
|
|
2
|
+
|
|
1
3
|
import { Method } from "../method";
|
|
2
4
|
import { PseudopotentialMethod } from "./pseudopotential";
|
|
3
5
|
|
|
@@ -6,7 +8,7 @@ export class MethodFactory {
|
|
|
6
8
|
|
|
7
9
|
static PseudopotentialMethod = PseudopotentialMethod;
|
|
8
10
|
|
|
9
|
-
static create(config) {
|
|
11
|
+
static create(config: BaseMethod): Method {
|
|
10
12
|
switch (config.type) {
|
|
11
13
|
case "pseudopotential":
|
|
12
14
|
return new this.PseudopotentialMethod(config);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { safeMakeArray } from "@mat3ra/code/dist/js/utils";
|
|
2
|
+
import { BaseMethod } from "@mat3ra/esse/dist/js/types";
|
|
3
|
+
import _ from "underscore";
|
|
4
|
+
|
|
5
|
+
import { Method } from "../method";
|
|
6
|
+
import type { PseudopotentialCtor, PseudopotentialLike } from "../types";
|
|
7
|
+
|
|
8
|
+
export class PseudopotentialMethod extends Method {
|
|
9
|
+
PseudopotentialCls: PseudopotentialCtor | null;
|
|
10
|
+
|
|
11
|
+
constructor(config: BaseMethod) {
|
|
12
|
+
super(config);
|
|
13
|
+
this.PseudopotentialCls = null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get pseudo(): Record<string, unknown>[] {
|
|
17
|
+
return this.prop<Record<string, unknown>[]>("data.pseudo", []);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get allPseudo(): Record<string, unknown>[] {
|
|
21
|
+
return this.prop<Record<string, unknown>[]>("data.allPseudo", []);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get pseudopotentials(): PseudopotentialLike[] {
|
|
25
|
+
if (!this.PseudopotentialCls) return [];
|
|
26
|
+
return this.pseudo.map((config) => new this.PseudopotentialCls!(config));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get allPseudopotentials(): PseudopotentialLike[] {
|
|
30
|
+
if (!this.PseudopotentialCls) return [];
|
|
31
|
+
return this.allPseudo.map((config) => new this.PseudopotentialCls!(config));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static extractExchangeCorrelationFromSubworkflow(subworkflow: any): {
|
|
35
|
+
approximation: string;
|
|
36
|
+
functional: string;
|
|
37
|
+
} {
|
|
38
|
+
const { model } = subworkflow;
|
|
39
|
+
const approximation = model.subtype;
|
|
40
|
+
const functionalValue = model.functional;
|
|
41
|
+
const functional = functionalValue && (functionalValue.slug || functionalValue);
|
|
42
|
+
return {
|
|
43
|
+
approximation,
|
|
44
|
+
functional: functional || "",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
hasPseudopotentialFor(element: string): boolean {
|
|
49
|
+
return Boolean(this.pseudopotentials.find((pseudo) => pseudo.element === element));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setPseudopotentialPerElement(pseudo: PseudopotentialLike | undefined): void {
|
|
53
|
+
if (!pseudo) {
|
|
54
|
+
this.setPseudopotentials([]);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const filtered = this.pseudopotentials.filter((item) => item.element !== pseudo.element);
|
|
58
|
+
filtered.push(pseudo);
|
|
59
|
+
this.setPseudopotentials(filtered);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
addToAllPseudos(pseudos: PseudopotentialLike | PseudopotentialLike[]): void {
|
|
63
|
+
const list = safeMakeArray(pseudos);
|
|
64
|
+
const all = this.allPseudopotentials;
|
|
65
|
+
all.push(...list);
|
|
66
|
+
this.setAllPseudopotentials(all);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setPseudopotentials(pseudopotentials: PseudopotentialLike[]): void {
|
|
70
|
+
this.setData({
|
|
71
|
+
...this.data,
|
|
72
|
+
pseudo: _.sortBy(pseudopotentials, "element").map((item) => item.toJSON()),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
setAllPseudopotentials(pseudopotentials: PseudopotentialLike[]): void {
|
|
77
|
+
this.setData({
|
|
78
|
+
...this.data,
|
|
79
|
+
allPseudo: _.sortBy(pseudopotentials, "element").map((item) => item.toJSON()),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
toJSONWithCleanData(exclude: string[] = []): BaseMethod {
|
|
84
|
+
return super.toJSONWithCleanData(exclude.concat(["allPseudo"]));
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/js/model.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
|
|
2
|
+
import type { Constructor } from "@mat3ra/code/dist/js/utils/types";
|
|
3
|
+
import type {
|
|
4
|
+
ApplicationSchemaBase,
|
|
5
|
+
BaseMethod,
|
|
6
|
+
BaseModel,
|
|
7
|
+
SlugifiedEntry,
|
|
8
|
+
SlugifiedEntryOrSlug,
|
|
9
|
+
} from "@mat3ra/esse/dist/js/types";
|
|
10
|
+
import lodash from "lodash";
|
|
11
|
+
|
|
12
|
+
import { DFTModelConfig } from "./default_models";
|
|
13
|
+
import { type ModelSchemaMixin, modelSchemaMixin } from "./generated/ModelSchemaMixin";
|
|
14
|
+
import { Method } from "./method";
|
|
15
|
+
import { MethodFactory } from "./methods/factory";
|
|
16
|
+
import { getTreeByApplicationNameAndVersion, MODEL_TREE, treeSlugToNamedObject } from "./tree";
|
|
17
|
+
import type { ModelConfig, MethodTreeBranch, ModelTree } from "./types";
|
|
18
|
+
|
|
19
|
+
const EMPTY_BRANCH: MethodTreeBranch = { methods: {} };
|
|
20
|
+
|
|
21
|
+
type Base = typeof InMemoryEntity & Constructor<ModelSchemaMixin>;
|
|
22
|
+
|
|
23
|
+
export class Model extends (InMemoryEntity as Base) implements BaseModel {
|
|
24
|
+
protected _application?: ApplicationSchemaBase;
|
|
25
|
+
|
|
26
|
+
protected _MethodFactory: typeof MethodFactory;
|
|
27
|
+
|
|
28
|
+
protected _method?: Method;
|
|
29
|
+
|
|
30
|
+
constructor(config: ModelConfig) {
|
|
31
|
+
const { application, ...entityConfig } = config as any;
|
|
32
|
+
super(entityConfig);
|
|
33
|
+
this._application = application as ApplicationSchemaBase | undefined;
|
|
34
|
+
this._MethodFactory = MethodFactory;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// get type(): string {
|
|
38
|
+
// return this.prop<string>("type", this.defaultType);
|
|
39
|
+
// }
|
|
40
|
+
|
|
41
|
+
// get subtype(): StringOrNamedSlug {
|
|
42
|
+
// return this.prop<StringOrNamedSlug>("subtype", this.defaultSubtype);
|
|
43
|
+
// }
|
|
44
|
+
|
|
45
|
+
setSubtype(subtype: SlugifiedEntryOrSlug): void {
|
|
46
|
+
this.setProp("subtype", subtype);
|
|
47
|
+
this.setMethod(this._MethodFactory.create(this.defaultMethodConfig));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get allowedTypes(): SlugifiedEntry[] {
|
|
51
|
+
return Object.keys(this.tree).map((modelSlug) => treeSlugToNamedObject(modelSlug));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get allowedSubtypes(): SlugifiedEntry[] {
|
|
55
|
+
return Object.keys(this.treeBranchForType).map((slug) => treeSlugToNamedObject(slug));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get defaultType(): string {
|
|
59
|
+
return this.allowedTypes[0]?.slug || "";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get defaultSubtype(): string {
|
|
63
|
+
return this.allowedSubtypes[0]?.slug || "";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get tree(): ModelTree {
|
|
67
|
+
if (this._application) {
|
|
68
|
+
const treeByApplication = this.treeByApplicationNameAndVersion;
|
|
69
|
+
if (treeByApplication) return treeByApplication;
|
|
70
|
+
}
|
|
71
|
+
return MODEL_TREE;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get treeBranchForType(): Record<string, MethodTreeBranch> {
|
|
75
|
+
return this.tree[this.type] || {};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get treeBranchForSubType(): MethodTreeBranch {
|
|
79
|
+
return this.treeBranchForType[this.subtypeSlug] || EMPTY_BRANCH;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get treeByApplicationNameAndVersion(): ModelTree | undefined {
|
|
83
|
+
if (!this._application) return undefined;
|
|
84
|
+
const { name, version } = this._application;
|
|
85
|
+
return getTreeByApplicationNameAndVersion({ name, version });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get groupSlug(): string {
|
|
89
|
+
const subtype = this.subtypeSlug;
|
|
90
|
+
if (!this._application) return `${this.type}:${subtype}`;
|
|
91
|
+
return `${this._application.shortName}:${this.type}:${subtype}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get Method(): Method {
|
|
95
|
+
if (!this._method) {
|
|
96
|
+
const methodOrConfig = this.method;
|
|
97
|
+
const config = methodOrConfig || this.defaultMethodConfig;
|
|
98
|
+
this._method = this._MethodFactory.create(config);
|
|
99
|
+
}
|
|
100
|
+
return this._method;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setMethod(method: Method): void {
|
|
104
|
+
this._method = method;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get methodsFromTree(): Record<string, string[]> {
|
|
108
|
+
return this.treeBranchForSubType.methods || {};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get methodTypes(): SlugifiedEntry[] {
|
|
112
|
+
return Object.keys(this.methodsFromTree).map((type) => treeSlugToNamedObject(type));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get methodSubtypes(): SlugifiedEntry[] {
|
|
116
|
+
const { type } = this.method;
|
|
117
|
+
const subtypes = this.methodsFromTree[type] || [];
|
|
118
|
+
return subtypes.map((slug) => treeSlugToNamedObject(slug));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get defaultMethodConfig(): BaseMethod {
|
|
122
|
+
const methodTypes = Object.keys(this.methodsFromTree);
|
|
123
|
+
const type = methodTypes[0];
|
|
124
|
+
if (!type) return Method.defaultConfig;
|
|
125
|
+
const subtype = this.methodsFromTree[type]?.[0];
|
|
126
|
+
if (!subtype) return Method.defaultConfig;
|
|
127
|
+
return { type, subtype };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static get defaultConfig(): ModelConfig {
|
|
131
|
+
return {
|
|
132
|
+
...DFTModelConfig,
|
|
133
|
+
method: Method.defaultConfig,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static get allTypes(): SlugifiedEntry[] {
|
|
138
|
+
return Object.keys(MODEL_TREE).map((modelSlug) => treeSlugToNamedObject(modelSlug));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
toJSON(): Record<string, unknown> {
|
|
142
|
+
const json = super.toJSON();
|
|
143
|
+
return {
|
|
144
|
+
...json,
|
|
145
|
+
type: this.type,
|
|
146
|
+
subtype: this.subtype,
|
|
147
|
+
method: (this.method as any).toJSONWithCleanData(),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
protected _stringToSlugifiedObject(slug: SlugifiedEntryOrSlug): SlugifiedEntry {
|
|
152
|
+
if (lodash.isString(slug)) {
|
|
153
|
+
return { slug } as SlugifiedEntry;
|
|
154
|
+
}
|
|
155
|
+
return slug;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get isUnknown(): boolean {
|
|
159
|
+
return this.type === "unknown";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
protected get subtypeSlug(): string {
|
|
163
|
+
const subtype = this.subtype as SlugifiedEntryOrSlug;
|
|
164
|
+
return typeof subtype === "string" ? subtype : subtype.slug;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
modelSchemaMixin(Model.prototype);
|