@mat3ra/mode 2025.12.25-0 → 2026.5.28-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.
@@ -1,9 +1,9 @@
1
1
  import { Model } from "../model";
2
- import type { ModelConfig } from "../types";
2
+ import type { ModelConfig, RequireFields } from "../types";
3
3
  import { DFTModel } from "./dft";
4
4
  export declare class ModelFactory {
5
5
  static DFTModel: typeof DFTModel;
6
6
  static Model: typeof Model;
7
7
  static create(config: ModelConfig): Model;
8
- static createFromApplication(config: ModelConfig): Model;
8
+ static createFromApplication(config: RequireFields<ModelConfig, "application">): Model;
9
9
  }
@@ -19,12 +19,11 @@ class ModelFactory {
19
19
  throw new Error("ModelFactory.createFromApplication: application is required");
20
20
  }
21
21
  const tree = (0, tree_1.getTreeByApplicationNameAndVersion)(application);
22
- if (Object.keys(tree).length === 0) {
22
+ if (!tree || Object.keys(tree).length === 0) {
23
23
  return this.create({ ...config, type: "unknown", subtype: "unknown" });
24
24
  }
25
- const type = (0, tree_1.getDefaultModelTypeForApplication)(application);
26
- const subtype = (0, tree_1.getDefaultModelSubtypeForApplicationAndType)(application, type) || "unknown";
27
- return this.create({ ...config, type, subtype });
25
+ const typeSubtype = (0, tree_1.getDefaultModelTypeSubtypeForApplication)(application);
26
+ return this.create({ ...config, ...typeSubtype });
28
27
  }
29
28
  }
30
29
  exports.ModelFactory = ModelFactory;
package/dist/js/tree.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ApplicationSchemaBase, SlugifiedEntry } from "@mat3ra/esse/dist/js/types";
1
+ import { type DFTModelSchema, type MLModelSchema, type UnknownModelSchema, ApplicationSchema } from "@mat3ra/esse/dist/js/types";
2
2
  import type { ModelTree } from "./types";
3
3
  export declare const MODEL_TREE: {
4
4
  dft: {
@@ -69,8 +69,10 @@ export declare const METHODS: {
69
69
  };
70
70
  export declare const getPseudopotentialTypesFromTree: () => string[];
71
71
  export declare const getDFTFunctionalsFromTree: () => string[];
72
- export declare const getDFTFunctionalsByApproximation: (approximation: string) => string[] | undefined;
73
- export declare const treeSlugToNamedObject: (modelSlug: string) => SlugifiedEntry;
74
- export declare const getTreeByApplicationNameAndVersion: ({ name, }: Pick<ApplicationSchemaBase, "name" | "version">) => ModelTree;
75
- export declare const getDefaultModelTypeForApplication: (application: ApplicationSchemaBase) => string;
76
- export declare const getDefaultModelSubtypeForApplicationAndType: (application: ApplicationSchemaBase, type: string) => string | undefined;
72
+ export declare const getDFTFunctionalsByApproximation: (approximation: "gga" | "lda" | "hybrid" | "other") => string[] | undefined;
73
+ export declare function treeSlugToNamedObject<T extends string>(modelSlug: T): {
74
+ readonly slug: T;
75
+ readonly name: string;
76
+ };
77
+ export declare const getTreeByApplicationNameAndVersion: ({ name, }: Pick<ApplicationSchema, "name" | "version">) => ModelTree | undefined;
78
+ export declare function getDefaultModelTypeSubtypeForApplication(application: Pick<ApplicationSchema, "name" | "version">): Pick<DFTModelSchema, "type" | "subtype"> | Pick<MLModelSchema, "type" | "subtype"> | Pick<UnknownModelSchema, "type" | "subtype">;
package/dist/js/tree.js CHANGED
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getDefaultModelSubtypeForApplicationAndType = exports.getDefaultModelTypeForApplication = exports.getTreeByApplicationNameAndVersion = exports.treeSlugToNamedObject = exports.getDFTFunctionalsByApproximation = exports.getDFTFunctionalsFromTree = exports.getPseudopotentialTypesFromTree = exports.METHODS = exports.MODEL_NAMES = exports.MODEL_TREE = void 0;
6
+ exports.getTreeByApplicationNameAndVersion = exports.getDFTFunctionalsByApproximation = exports.getDFTFunctionalsFromTree = exports.getPseudopotentialTypesFromTree = exports.METHODS = exports.MODEL_NAMES = exports.MODEL_TREE = void 0;
7
+ exports.treeSlugToNamedObject = treeSlugToNamedObject;
8
+ exports.getDefaultModelTypeSubtypeForApplication = getDefaultModelTypeSubtypeForApplication;
7
9
  const modelsTreeConfigByApplication_json_1 = __importDefault(require("@mat3ra/standata/dist/js/runtime_data/models/modelsTreeConfigByApplication.json"));
8
10
  const modelTree_json_1 = __importDefault(require("@mat3ra/standata/dist/js/runtime_data/models/modelTree.json"));
9
11
  const lodash_1 = __importDefault(require("lodash"));
@@ -30,26 +32,26 @@ const getDFTFunctionalsByApproximation = (approximation) => {
30
32
  return branch === null || branch === void 0 ? void 0 : branch.functionals;
31
33
  };
32
34
  exports.getDFTFunctionalsByApproximation = getDFTFunctionalsByApproximation;
33
- const treeSlugToNamedObject = (modelSlug) => {
35
+ function treeSlugToNamedObject(modelSlug) {
34
36
  return {
35
37
  slug: modelSlug,
36
38
  name: lodash_1.default.get(exports.MODEL_NAMES, modelSlug, modelSlug),
37
39
  };
38
- };
39
- exports.treeSlugToNamedObject = treeSlugToNamedObject;
40
+ }
40
41
  const getTreeByApplicationNameAndVersion = ({ name, }) => {
41
42
  // TODO: add logic to filter by version when necessary
42
- // @ts-ignore
43
- return modelsTreeConfigByApplication_json_1.default[name] || {};
43
+ if (!(name in modelsTreeConfigByApplication_json_1.default)) {
44
+ return undefined;
45
+ }
46
+ return modelsTreeConfigByApplication_json_1.default[name];
44
47
  };
45
48
  exports.getTreeByApplicationNameAndVersion = getTreeByApplicationNameAndVersion;
46
- const getDefaultModelTypeForApplication = (application) => {
47
- return Object.keys((0, exports.getTreeByApplicationNameAndVersion)(application))[0];
48
- };
49
- exports.getDefaultModelTypeForApplication = getDefaultModelTypeForApplication;
50
- const getDefaultModelSubtypeForApplicationAndType = (application, type) => {
49
+ function getDefaultModelTypeSubtypeForApplication(application) {
51
50
  const tree = (0, exports.getTreeByApplicationNameAndVersion)(application);
52
- const subtypes = Object.keys(tree[type] || {});
53
- return subtypes[0];
54
- };
55
- exports.getDefaultModelSubtypeForApplicationAndType = getDefaultModelSubtypeForApplicationAndType;
51
+ if (!tree) {
52
+ throw new Error(`getDefaultModelTypeForApplication: tree not found for application ${application.name}`);
53
+ }
54
+ const type = Object.keys(tree)[0];
55
+ const subtype = Object.keys(tree[type] || {})[0] || "unknown";
56
+ return { type, subtype };
57
+ }
@@ -1,16 +1,20 @@
1
- import type { ApplicationSchemaBase, BaseModel, CategorizedMethod, CategorizedModel, CategorizedUnitMethod } from "@mat3ra/esse/dist/js/types";
2
- export type ModelConfig = Pick<BaseModel, "type" | "subtype"> & Partial<Omit<BaseModel, "type" | "subtype">> & {
3
- application?: ApplicationSchemaBase;
1
+ import type { ApplicationSchema, CategorizedMethod, CategorizedModel, CategorizedUnitMethod, DFTModelSchema, MLModelSchema, UnknownModelSchema } from "@mat3ra/esse/dist/js/types";
2
+ /**
3
+ * Makes specified fields required and all others optional
4
+ * TODO: consider moving to code.js
5
+ */
6
+ export type RequireFields<T, K extends keyof T> = Required<Pick<T, K>> & Partial<Omit<T, K>>;
7
+ type ModelRequiredFields = "type" | "subtype";
8
+ export type DFTModelConfig = RequireFields<DFTModelSchema, ModelRequiredFields>;
9
+ export type MLModelConfig = RequireFields<MLModelSchema, ModelRequiredFields>;
10
+ export type UnknownModelConfig = RequireFields<UnknownModelSchema, ModelRequiredFields>;
11
+ export type ModelConfig = (DFTModelConfig | MLModelConfig | UnknownModelConfig) & {
12
+ application?: ApplicationSchema;
4
13
  };
5
14
  export type SimplifiedCategorizedModel = Pick<CategorizedModel, "name" | "path" | "categories" | "parameters">;
6
15
  export type SimplifiedCategorizedMethod = Pick<CategorizedMethod, "name" | "path"> & {
7
16
  units: CategorizedUnitMethod[];
8
17
  };
9
- export interface PseudopotentialLike {
10
- element?: string;
11
- toJSON(): Record<string, unknown>;
12
- }
13
- export type PseudopotentialCtor = new (config: Record<string, unknown>) => PseudopotentialLike;
14
18
  export interface MethodTreeBranch {
15
19
  methods: Record<string, string[]>;
16
20
  functionals?: string[];
@@ -18,3 +22,4 @@ export interface MethodTreeBranch {
18
22
  modifiers?: string[];
19
23
  }
20
24
  export type ModelTree = Record<string, Record<string, MethodTreeBranch>>;
25
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mat3ra/mode",
3
- "version": "2025.12.25-0",
3
+ "version": "2026.5.28-0",
4
4
  "description": "MOdel and method DEfinitions",
5
5
  "scripts": {
6
6
  "test": "nyc --reporter=text mocha --recursive --bail",
@@ -31,6 +31,7 @@
31
31
  "license": "Apache-2.0",
32
32
  "homepage": "https://github.com/Exabyte-io/mode",
33
33
  "dependencies": {
34
+ "@mat3ra/utils": "^2026.3.2-0",
34
35
  "@babel/cli": "7.16.0",
35
36
  "@babel/core": "7.16.0",
36
37
  "@babel/eslint-parser": "7.16.3",
@@ -53,9 +54,10 @@
53
54
  },
54
55
  "devDependencies": {
55
56
  "@exabyte-io/eslint-config": "2025.5.13-0",
56
- "@mat3ra/esse": "2025.10.8-0",
57
+ "@mat3ra/code": "2026.5.27-0",
58
+ "@mat3ra/esse": "2026.5.27-0",
59
+ "@mat3ra/prode": "2026.5.28-0",
57
60
  "@mat3ra/standata": "2025.11.12-0",
58
- "@mat3ra/code": "2025.10.8-0",
59
61
  "@mat3ra/tsconfig": "2024.6.3-0",
60
62
  "@types/chai": "^4.3.11",
61
63
  "@types/mocha": "^10.0.6",
@@ -81,8 +83,8 @@
81
83
  },
82
84
  "peerDependencies": {
83
85
  "@mat3ra/esse": "*",
84
- "@mat3ra/standata": "*",
85
- "@mat3ra/code": "*"
86
+ "@mat3ra/code": "*",
87
+ "@mat3ra/prode": "*"
86
88
  },
87
89
  "engines": {
88
90
  "node": ">20.0.0"
@@ -1,22 +1,28 @@
1
- import { BaseMethod, BaseModel, SlugifiedEntry } from "@mat3ra/esse/dist/js/types";
1
+ import { BaseModel, SlugifiedEntry } from "@mat3ra/esse/dist/js/types";
2
2
  import lodash from "lodash";
3
3
 
4
4
  import { MODEL_NAMES, MODEL_TREE } from "./tree";
5
5
 
6
- export const PseudopotentialMethodConfig: BaseMethod = {
6
+ export const PseudopotentialMethodConfig = {
7
7
  type: "pseudopotential",
8
8
  subtype: "us",
9
- };
9
+ } as const;
10
10
 
11
- export const LocalOrbitalMethodConfig: BaseMethod = {
11
+ export const LocalOrbitalMethodConfig = {
12
12
  type: "localorbital",
13
13
  subtype: "pople",
14
- };
14
+ } as const;
15
15
 
16
- export const UnknownMethodConfig: BaseMethod = {
16
+ export const UnknownMethodConfig = {
17
17
  type: "unknown",
18
18
  subtype: "unknown",
19
- };
19
+ } as const;
20
+
21
+ export const methodConfigs = {
22
+ pseudopotential: PseudopotentialMethodConfig,
23
+ localorbital: LocalOrbitalMethodConfig,
24
+ unknown: UnknownMethodConfig,
25
+ } as const;
20
26
 
21
27
  const mapSlugToNamedObject = (slug: string): SlugifiedEntry => {
22
28
  return {
@@ -30,7 +36,10 @@ export function allowedTypes(model: Pick<BaseModel, "type" | "subtype">): Slugif
30
36
  return lodash.keys(branch).map(mapSlugToNamedObject);
31
37
  }
32
38
 
33
- export function allowedSubtypes(model: Pick<BaseModel, "type" | "subtype">, type: string): SlugifiedEntry[] {
39
+ export function allowedSubtypes(
40
+ model: Pick<BaseModel, "type" | "subtype">,
41
+ type: string,
42
+ ): SlugifiedEntry[] {
34
43
  const branch = lodash.get(MODEL_TREE, `${model.type}.${model.subtype}.methods.${type}`, []);
35
44
  return (branch as string[]).map(mapSlugToNamedObject);
36
45
  }
@@ -1,11 +1,9 @@
1
- import type { ModelConfig } from "./types";
2
-
3
- export const DFTModelConfig: ModelConfig = {
1
+ export const DFTModelConfig = {
4
2
  type: "dft",
5
3
  subtype: "gga",
6
- };
4
+ } as const;
7
5
 
8
- export const UnknownModelConfig: ModelConfig = {
6
+ export const UnknownModelConfig = {
9
7
  type: "unknown",
10
8
  subtype: "unknown",
11
- };
9
+ } as const;
@@ -5,21 +5,35 @@ export type MethodSchemaMixin = BaseMethod;
5
5
 
6
6
  export type MethodInMemoryEntity = InMemoryEntity & MethodSchemaMixin;
7
7
 
8
- export function methodSchemaMixin(item: InMemoryEntity) {
8
+ export function methodSchemaMixin<T extends InMemoryEntity>(
9
+ item: InMemoryEntity,
10
+ ): asserts item is T & MethodSchemaMixin {
9
11
  // @ts-expect-error
10
12
  const properties: InMemoryEntity & MethodSchemaMixin = {
11
13
  get type() {
12
14
  return this.requiredProp<BaseMethod["type"]>("type");
13
15
  },
16
+ set type(value: BaseMethod["type"]) {
17
+ this.setProp("type", value);
18
+ },
14
19
  get subtype() {
15
20
  return this.requiredProp<BaseMethod["subtype"]>("subtype");
16
21
  },
22
+ set subtype(value: BaseMethod["subtype"]) {
23
+ this.setProp("subtype", value);
24
+ },
17
25
  get precision() {
18
26
  return this.prop<BaseMethod["precision"]>("precision");
19
27
  },
28
+ set precision(value: BaseMethod["precision"]) {
29
+ this.setProp("precision", value);
30
+ },
20
31
  get data() {
21
32
  return this.prop<BaseMethod["data"]>("data");
22
33
  },
34
+ set data(value: BaseMethod["data"]) {
35
+ this.setProp("data", value);
36
+ },
23
37
  };
24
38
 
25
39
  Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties));
@@ -5,18 +5,29 @@ export type ModelSchemaMixin = BaseModel;
5
5
 
6
6
  export type ModelInMemoryEntity = InMemoryEntity & ModelSchemaMixin;
7
7
 
8
- export function modelSchemaMixin(item: InMemoryEntity) {
8
+ export function modelSchemaMixin<T extends InMemoryEntity>(
9
+ item: InMemoryEntity,
10
+ ): asserts item is T & ModelSchemaMixin {
9
11
  // @ts-expect-error
10
12
  const properties: InMemoryEntity & ModelSchemaMixin = {
11
13
  get type() {
12
14
  return this.requiredProp<BaseModel["type"]>("type");
13
15
  },
16
+ set type(value: BaseModel["type"]) {
17
+ this.setProp("type", value);
18
+ },
14
19
  get subtype() {
15
20
  return this.requiredProp<BaseModel["subtype"]>("subtype");
16
21
  },
22
+ set subtype(value: BaseModel["subtype"]) {
23
+ this.setProp("subtype", value);
24
+ },
17
25
  get method() {
18
26
  return this.requiredProp<BaseModel["method"]>("method");
19
27
  },
28
+ set method(value: BaseModel["method"]) {
29
+ this.setProp("method", value);
30
+ },
20
31
  };
21
32
 
22
33
  Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties));
package/src/js/index.ts CHANGED
@@ -23,4 +23,3 @@ export {
23
23
  default_models,
24
24
  default_methods,
25
25
  };
26
-
package/src/js/method.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
2
2
  import { deepClone } from "@mat3ra/code/dist/js/utils";
3
3
  import type { Constructor } from "@mat3ra/code/dist/js/utils/types";
4
+ import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types";
4
5
  import type { BaseMethod, SlugifiedEntry } from "@mat3ra/esse/dist/js/types";
5
6
  import lodash from "lodash";
6
7
 
@@ -19,6 +20,8 @@ export class Method extends (InMemoryEntity as Base) implements BaseMethod {
19
20
  super({ ...config, data });
20
21
  }
21
22
 
23
+ declare toJSON: () => BaseMethod & AnyObject;
24
+
22
25
  cloneWithoutData(): Method {
23
26
  const clone = this.clone() as Method;
24
27
  clone.setData({});
@@ -29,7 +32,7 @@ export class Method extends (InMemoryEntity as Base) implements BaseMethod {
29
32
  this.setProp("subtype", subtype);
30
33
  }
31
34
 
32
- static get defaultConfig(): BaseMethod {
35
+ static get defaultConfig() {
33
36
  return PseudopotentialMethodConfig;
34
37
  }
35
38
 
@@ -1,79 +1,61 @@
1
- import { safeMakeArray } from "@mat3ra/code/dist/js/utils";
2
- import { BaseMethod } from "@mat3ra/esse/dist/js/types";
1
+ import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types";
2
+ import { type BaseMethod, type FileDataItem } from "@mat3ra/esse/dist/js/types";
3
+ import { PseudopotentialFilter, PseudopotentialMetaProperty } from "@mat3ra/prode";
3
4
  import _ from "underscore";
4
5
 
5
6
  import { Method } from "../method";
6
- import type { PseudopotentialCtor, PseudopotentialLike } from "../types";
7
7
 
8
- export class PseudopotentialMethod extends Method {
9
- PseudopotentialCls: PseudopotentialCtor | null;
10
-
11
- constructor(config: BaseMethod) {
12
- super(config);
13
- this.PseudopotentialCls = null;
14
- }
8
+ export type ExchangeCorrelation = {
9
+ approximation: string;
10
+ functional: string;
11
+ };
15
12
 
16
- get pseudo(): Record<string, unknown>[] {
17
- return this.prop<Record<string, unknown>[]>("data.pseudo", []);
18
- }
13
+ export class PseudopotentialMethod extends Method {
14
+ declare toJSON: () => BaseMethod & AnyObject;
19
15
 
20
- get allPseudo(): Record<string, unknown>[] {
21
- return this.prop<Record<string, unknown>[]>("data.allPseudo", []);
16
+ get pseudo() {
17
+ return this.prop<FileDataItem[]>("data.pseudo", []);
22
18
  }
23
19
 
24
- get pseudopotentials(): PseudopotentialLike[] {
25
- if (!this.PseudopotentialCls) return [];
26
- return this.pseudo.map((config) => new this.PseudopotentialCls!(config));
20
+ get allPseudo() {
21
+ return this.prop<FileDataItem[]>("data.allPseudo", []);
27
22
  }
28
23
 
29
- get allPseudopotentials(): PseudopotentialLike[] {
30
- if (!this.PseudopotentialCls) return [];
31
- return this.allPseudo.map((config) => new this.PseudopotentialCls!(config));
24
+ get pseudopotentials() {
25
+ return this.pseudo.map((config) => new PseudopotentialMetaProperty(config));
32
26
  }
33
27
 
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
- };
28
+ get allPseudopotentials() {
29
+ return this.allPseudo.map((config) => new PseudopotentialMetaProperty(config));
46
30
  }
47
31
 
48
32
  hasPseudopotentialFor(element: string): boolean {
49
33
  return Boolean(this.pseudopotentials.find((pseudo) => pseudo.element === element));
50
34
  }
51
35
 
52
- setPseudopotentialPerElement(pseudo: PseudopotentialLike | undefined): void {
36
+ setPseudopotentialPerElement(pseudo?: PseudopotentialMetaProperty) {
53
37
  if (!pseudo) {
54
38
  this.setPseudopotentials([]);
55
39
  return;
56
40
  }
57
41
  const filtered = this.pseudopotentials.filter((item) => item.element !== pseudo.element);
58
- filtered.push(pseudo);
59
- this.setPseudopotentials(filtered);
42
+
43
+ this.setPseudopotentials([...filtered, pseudo]);
60
44
  }
61
45
 
62
- addToAllPseudos(pseudos: PseudopotentialLike | PseudopotentialLike[]): void {
63
- const list = safeMakeArray(pseudos);
64
- const all = this.allPseudopotentials;
65
- all.push(...list);
66
- this.setAllPseudopotentials(all);
46
+ addToAllPseudos(pseudos: PseudopotentialMetaProperty | PseudopotentialMetaProperty[]) {
47
+ const list = Array.isArray(pseudos) ? pseudos : [pseudos];
48
+ this.setAllPseudopotentials([...this.allPseudopotentials, ...list]);
67
49
  }
68
50
 
69
- setPseudopotentials(pseudopotentials: PseudopotentialLike[]): void {
51
+ setPseudopotentials(pseudopotentials: PseudopotentialMetaProperty[]) {
70
52
  this.setData({
71
53
  ...this.data,
72
54
  pseudo: _.sortBy(pseudopotentials, "element").map((item) => item.toJSON()),
73
55
  });
74
56
  }
75
57
 
76
- setAllPseudopotentials(pseudopotentials: PseudopotentialLike[]): void {
58
+ setAllPseudopotentials(pseudopotentials: PseudopotentialMetaProperty[]) {
77
59
  this.setData({
78
60
  ...this.data,
79
61
  allPseudo: _.sortBy(pseudopotentials, "element").map((item) => item.toJSON()),
@@ -83,4 +65,58 @@ export class PseudopotentialMethod extends Method {
83
65
  toJSONWithCleanData(exclude: string[] = []): BaseMethod {
84
66
  return super.toJSONWithCleanData(exclude.concat(["allPseudo"]));
85
67
  }
68
+
69
+ updateMethodDataByApplicationAndMaterials(
70
+ methodDataItems: PseudopotentialMetaProperty[],
71
+ pseudoFilter: Pick<PseudopotentialFilter, "elements" | "appName" | "exchangeCorrelation">,
72
+ ) {
73
+ const typeFilter = { type: this.subtype };
74
+ let pseudos = PseudopotentialMetaProperty.applyPseudoFilters(methodDataItems, {
75
+ ...pseudoFilter,
76
+ ...typeFilter,
77
+ });
78
+
79
+ // sorting pseudos, this is very hacky! TODO: find better approach for default pseudos per application
80
+ if (this.subtype === "us") {
81
+ pseudos = PseudopotentialMetaProperty.sortPseudosByPattern(pseudos);
82
+ }
83
+ pseudos = PseudopotentialMetaProperty.sortByPathApplicationSpecific(
84
+ pseudos,
85
+ pseudoFilter.appName,
86
+ );
87
+ pseudos = PseudopotentialMetaProperty.filterUnique(pseudos);
88
+
89
+ this.setAllPseudopotentials(pseudos);
90
+ this.setSearchText(this.searchText);
91
+
92
+ // if searchText is present => use it to filter the pseudos before selecting one per element
93
+ pseudos = PseudopotentialMetaProperty.safelyFilterRawDataBySearchText(
94
+ pseudos,
95
+ this.searchText,
96
+ );
97
+
98
+ const newFilter = {
99
+ elements: pseudoFilter.elements,
100
+ appName: pseudoFilter.appName,
101
+ exchangeCorrelation: pseudoFilter.exchangeCorrelation,
102
+ searchText: this.searchText,
103
+ ...typeFilter,
104
+ };
105
+
106
+ // try to keep previously selected pseudos
107
+ // TODO: rework creating/updating method data items once methodData has been removed from store
108
+ const filteredSelected = PseudopotentialMetaProperty.applyPseudoFilters(
109
+ this.pseudopotentials,
110
+ newFilter,
111
+ );
112
+
113
+ // set first pseudopotentials as selected per element, prioritize already selected
114
+ pseudoFilter.elements?.forEach((el) => {
115
+ const selected = filteredSelected.find((p) => p.element === el);
116
+ const pseudo = selected || pseudos.find((p) => p.element === el);
117
+ this.setPseudopotentialPerElement(pseudo);
118
+ });
119
+
120
+ return this;
121
+ }
86
122
  }
package/src/js/model.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  import { InMemoryEntity } from "@mat3ra/code/dist/js/entity";
2
2
  import type { Constructor } from "@mat3ra/code/dist/js/utils/types";
3
+ import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types";
3
4
  import type {
4
- ApplicationSchemaBase,
5
+ AnyModelSchema,
6
+ ApplicationSchema,
5
7
  BaseMethod,
6
8
  BaseModel,
7
9
  SlugifiedEntry,
8
10
  SlugifiedEntryOrSlug,
9
11
  } from "@mat3ra/esse/dist/js/types";
12
+ import { Utils } from "@mat3ra/utils";
10
13
  import lodash from "lodash";
11
14
 
12
15
  import { DFTModelConfig } from "./default_models";
@@ -21,7 +24,7 @@ const EMPTY_BRANCH: MethodTreeBranch = { methods: {} };
21
24
  type Base = typeof InMemoryEntity & Constructor<ModelSchemaMixin>;
22
25
 
23
26
  export class Model extends (InMemoryEntity as Base) implements BaseModel {
24
- protected _application?: ApplicationSchemaBase;
27
+ protected _application?: ApplicationSchema;
25
28
 
26
29
  protected _MethodFactory: typeof MethodFactory;
27
30
 
@@ -30,14 +33,13 @@ export class Model extends (InMemoryEntity as Base) implements BaseModel {
30
33
  constructor(config: ModelConfig) {
31
34
  const { application, method = Method.defaultConfig, ...entityConfig } = config;
32
35
  super(entityConfig);
33
- this._application = application as ApplicationSchemaBase | undefined;
36
+ this._application = application;
34
37
  this._MethodFactory = MethodFactory;
35
- if (method) {
36
- this.setProp("method", method);
37
- }
38
+ this.method = method || this.method;
38
39
  }
39
40
 
40
41
  setSubtype(subtype: SlugifiedEntryOrSlug): void {
42
+ // TODO-question: subtype is a string, but we're setting it to a SlugifiedEntryOrSlug
41
43
  this.setProp("subtype", subtype);
42
44
  this.setMethod(this._MethodFactory.create(this.defaultMethodConfig));
43
45
  }
@@ -121,7 +123,7 @@ export class Model extends (InMemoryEntity as Base) implements BaseModel {
121
123
  return { type, subtype };
122
124
  }
123
125
 
124
- static get defaultConfig(): ModelConfig {
126
+ static get defaultConfig() {
125
127
  return {
126
128
  ...DFTModelConfig,
127
129
  method: Method.defaultConfig,
@@ -132,16 +134,18 @@ export class Model extends (InMemoryEntity as Base) implements BaseModel {
132
134
  return Object.keys(MODEL_TREE).map((modelSlug) => treeSlugToNamedObject(modelSlug));
133
135
  }
134
136
 
135
- toJSON(): Record<string, unknown> {
136
- const json = super.toJSON();
137
+ declare _json: AnyModelSchema & AnyObject;
138
+
139
+ toJSON(): AnyModelSchema & AnyObject {
137
140
  return {
138
- ...json,
141
+ ...super.toJSON(),
139
142
  type: this.type,
140
143
  subtype: this.subtype,
141
144
  method: this.Method.toJSONWithCleanData(),
142
- };
145
+ } as AnyModelSchema & AnyObject;
143
146
  }
144
147
 
148
+ // eslint-disable-next-line class-methods-use-this
145
149
  protected _stringToSlugifiedObject(slug: SlugifiedEntryOrSlug): SlugifiedEntry {
146
150
  if (lodash.isString(slug)) {
147
151
  return { slug } as SlugifiedEntry;
@@ -157,6 +161,16 @@ export class Model extends (InMemoryEntity as Base) implements BaseModel {
157
161
  const subtype = this.subtype as SlugifiedEntryOrSlug;
158
162
  return typeof subtype === "string" ? subtype : subtype.slug;
159
163
  }
164
+
165
+ calculateHash(): string {
166
+ const json = this.toJSON() as Record<string, unknown> & {
167
+ method?: { data?: unknown };
168
+ };
169
+ if (this.Method.omitInHashCalculation) {
170
+ delete json.method?.data;
171
+ }
172
+ return Utils.hash.calculateHashFromObject(json as Record<string, unknown>);
173
+ }
160
174
  }
161
175
 
162
176
  modelSchemaMixin(Model.prototype);