@mat3ra/mode 2026.3.4-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,14 +1,19 @@
1
- import { CategorizedModel, SlugifiedEntryOrSlug } from "@mat3ra/esse/dist/js/types";
1
+ import {
2
+ type AnyModelSchema,
3
+ type DFTModelSchema,
4
+ type MLModelSchema,
5
+ CategorizedModel,
6
+ SlugifiedEntryOrSlug,
7
+ } from "@mat3ra/esse/dist/js/types";
2
8
 
3
- import * as tree from "./tree";
4
- import type { ModelConfig, SimplifiedCategorizedModel } from "./types";
9
+ import type { DFTModelConfig, SimplifiedCategorizedModel, UnknownModelConfig } from "./types";
5
10
 
6
11
  export function safelyGetSlug(slugObj: SlugifiedEntryOrSlug): string {
7
12
  return typeof slugObj === "string" ? slugObj : slugObj.slug;
8
13
  }
9
14
 
10
15
  export class ModelConversionHandler {
11
- static convertToSimple(categorizedModel: CategorizedModel | undefined): ModelConfig {
16
+ static convertToSimple(categorizedModel?: CategorizedModel) {
12
17
  if (!categorizedModel) return this.convertUnknownToSimple();
13
18
  switch (categorizedModel.categories.tier3) {
14
19
  case "dft":
@@ -20,39 +25,46 @@ export class ModelConversionHandler {
20
25
  }
21
26
  }
22
27
 
23
- static convertDftToSimple(categorizedModel: CategorizedModel): ModelConfig {
24
- if (!categorizedModel.categories?.subtype) return this.convertUnknownToSimple();
25
- const subtypeCategory = categorizedModel.categories.subtype as SlugifiedEntryOrSlug;
26
- const subtype = safelyGetSlug(subtypeCategory);
27
- const functionalParam = (categorizedModel.parameters as any)?.functional;
28
- const functionalSlug = functionalParam
29
- ? safelyGetSlug(functionalParam as SlugifiedEntryOrSlug)
30
- : "";
28
+ static convertDftToSimple(
29
+ categorizedModel: CategorizedModel,
30
+ ): DFTModelConfig | UnknownModelConfig {
31
+ if (!categorizedModel.categories?.subtype) {
32
+ return this.convertUnknownToSimple();
33
+ }
34
+
35
+ const model = categorizedModel as {
36
+ categories: { subtype: SlugifiedEntryOrSlug };
37
+ parameters: { functional?: SlugifiedEntryOrSlug };
38
+ };
39
+
40
+ const subtype = safelyGetSlug(model.categories.subtype) as DFTModelConfig["subtype"];
41
+ const functionalParam = model.parameters.functional;
42
+ const functional = functionalParam
43
+ ? (safelyGetSlug(functionalParam) as DFTModelConfig["functional"])
44
+ : undefined;
45
+
31
46
  return {
32
47
  type: "dft",
33
48
  subtype,
34
- functional: tree.treeSlugToNamedObject(functionalSlug),
35
- };
49
+ functional, // old: tree.treeSlugToNamedObject(functional),
50
+ } as const;
36
51
  }
37
52
 
38
- static convertMlToSimple(): ModelConfig {
53
+ static convertMlToSimple() {
39
54
  return {
40
55
  type: "ml",
41
56
  subtype: "re",
42
- };
57
+ } as const;
43
58
  }
44
59
 
45
- static convertUnknownToSimple(): ModelConfig {
60
+ static convertUnknownToSimple() {
46
61
  return {
47
62
  type: "unknown",
48
63
  subtype: "unknown",
49
- };
64
+ } as const;
50
65
  }
51
66
 
52
- static convertToCategorized(
53
- simpleModel: ModelConfig | undefined,
54
- allModels: CategorizedModel[] = [],
55
- ): SimplifiedCategorizedModel | undefined {
67
+ static convertToCategorized(simpleModel?: AnyModelSchema, allModels?: CategorizedModel[]) {
56
68
  switch (simpleModel?.type) {
57
69
  case "dft":
58
70
  return this.convertDftToCategorized(simpleModel, allModels);
@@ -66,7 +78,7 @@ export class ModelConversionHandler {
66
78
  }
67
79
 
68
80
  static convertDftToCategorized(
69
- simpleModel: ModelConfig,
81
+ simpleModel: DFTModelSchema,
70
82
  allModels: CategorizedModel[] = [],
71
83
  ): SimplifiedCategorizedModel | undefined {
72
84
  const { subtype, functional: functionalStringOrObject } = simpleModel;
@@ -79,14 +91,16 @@ export class ModelConversionHandler {
79
91
  if (!functionalStringOrObject) {
80
92
  functional = defaultFunctionals[subtype as string];
81
93
  } else {
82
- functional = safelyGetSlug(functionalStringOrObject as SlugifiedEntryOrSlug);
94
+ functional = safelyGetSlug(functionalStringOrObject);
83
95
  }
84
96
  const path = `/pb/qm/dft/ksdft/${subtype}?functional=${functional}`;
97
+
85
98
  return allModels.find((categorized) => categorized.path === path);
86
99
  }
87
100
 
88
- static convertMlToCategorized(simpleModel: ModelConfig): SimplifiedCategorizedModel {
89
- const subtype = safelyGetSlug(simpleModel.subtype as SlugifiedEntryOrSlug);
101
+ static convertMlToCategorized(simpleModel: MLModelSchema) {
102
+ const subtype = safelyGetSlug(simpleModel.subtype);
103
+
90
104
  return {
91
105
  name: "Regression",
92
106
  path: "/st/det/ml/re/none",
@@ -97,6 +111,6 @@ export class ModelConversionHandler {
97
111
  type: subtype,
98
112
  },
99
113
  parameters: {},
100
- };
114
+ } as const;
101
115
  }
102
116
  }
@@ -1,6 +1,10 @@
1
1
  import { safeMakeArray } from "@mat3ra/code/dist/js/utils";
2
- import { SlugifiedEntry, SlugifiedEntryOrSlug } from "@mat3ra/esse/dist/js/types";
3
- import _ from "underscore";
2
+ import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types";
3
+ import {
4
+ type DFTModelSchema,
5
+ SlugifiedEntry,
6
+ SlugifiedEntryOrSlug,
7
+ } from "@mat3ra/esse/dist/js/types";
4
8
 
5
9
  import { MethodFactory } from "../methods/factory";
6
10
  import { Model } from "../model";
@@ -11,57 +15,64 @@ export class DFTModel extends Model {
11
15
  constructor(config: ModelConfig & { MethodFactory?: typeof MethodFactory }) {
12
16
  super(config);
13
17
  this._MethodFactory = config.MethodFactory || MethodFactory;
18
+ this.functional =
19
+ this.prop<DFTModelSchema["functional"]>("functional") || this.defaultFunctional.slug;
14
20
  }
15
21
 
22
+ declare type: DFTModelSchema["type"];
23
+
24
+ declare subtype: DFTModelSchema["subtype"];
25
+
16
26
  get groupSlug(): string {
17
- const functionalSlug = this.functional.slug;
18
27
  const refinersSlug = this.refiners.map((o) => o.slug).join("+");
19
28
  const modifiersSlug = this.modifiers.map((o) => o.slug).join("+");
20
29
  const slugs = [
21
30
  this._application?.shortName,
22
31
  this.type,
23
32
  this.subtype,
24
- functionalSlug,
33
+ this.functional,
25
34
  refinersSlug,
26
35
  modifiersSlug,
27
36
  ].filter(Boolean);
28
37
  return slugs.join(":");
29
38
  }
30
39
 
31
- get defaultFunctional(): SlugifiedEntry {
40
+ private get defaultFunctional() {
32
41
  const [slug] = this.treeBranchForSubType.functionals || [];
33
- return treeSlugToNamedObject(slug);
42
+ return treeSlugToNamedObject(slug as DFTModelSchema["functional"]);
34
43
  }
35
44
 
36
- // eslint-disable-next-line class-methods-use-this
37
- get defaultRefiners(): SlugifiedEntry[] {
38
- return [];
45
+ readonly defaultRefiners: SlugifiedEntry[] = [];
46
+
47
+ readonly defaultModifiers: SlugifiedEntry[] = [];
48
+
49
+ get slugifiedFunctional() {
50
+ return this._stringToSlugifiedObject(this.functional);
39
51
  }
40
52
 
41
- // eslint-disable-next-line class-methods-use-this
42
- get defaultModifiers(): SlugifiedEntry[] {
43
- return [];
53
+ get functional() {
54
+ return this.requiredProp<DFTModelSchema["functional"]>("functional");
44
55
  }
45
56
 
46
- get functional(): SlugifiedEntry {
47
- return this.prop<SlugifiedEntry>("functional", this.defaultFunctional);
57
+ set functional(functional) {
58
+ this.setProp("functional", functional);
48
59
  }
49
60
 
50
- get refiners(): SlugifiedEntry[] {
61
+ get refiners() {
51
62
  return this.prop<SlugifiedEntry[]>("refiners", this.defaultRefiners);
52
63
  }
53
64
 
54
- get modifiers(): SlugifiedEntry[] {
65
+ get modifiers() {
55
66
  return this.prop<SlugifiedEntry[]>("modifiers", this.defaultModifiers);
56
67
  }
57
68
 
58
69
  setSubtype(subtype: SlugifiedEntryOrSlug): void {
59
70
  this.setProp("subtype", subtype);
60
- this.setFunctional(this.defaultFunctional);
71
+ this.setFunctional(this.defaultFunctional.slug);
61
72
  }
62
73
 
63
- setFunctional(functional: SlugifiedEntryOrSlug): void {
64
- this.setProp("functional", this._stringToSlugifiedObject(functional));
74
+ setFunctional(functional: string): void {
75
+ this.setProp("functional", functional);
65
76
  this.setMethod(this._MethodFactory.create(this.defaultMethodConfig));
66
77
  }
67
78
 
@@ -82,22 +93,24 @@ export class DFTModel extends Model {
82
93
  this._setArrayProp("modifiers", modifiers);
83
94
  }
84
95
 
85
- toJSON(): Record<string, unknown> {
86
- const pickSlugFromObject = (item: SlugifiedEntry) => _.pick(item, "slug");
96
+ declare _json: DFTModelSchema & AnyObject;
97
+
98
+ toJSON(): DFTModelSchema & AnyObject {
87
99
  const baseJson = super.toJSON();
88
100
  const keysToExclude = ["type", "subtype", "functional", "refiners", "modifiers", "method"];
89
101
  const restJson = Object.fromEntries(
90
102
  Object.entries(baseJson).filter(([key]) => !keysToExclude.includes(key)),
91
103
  );
104
+
92
105
  return {
93
106
  type: this.type,
94
107
  subtype: this.subtype,
95
108
  method: this.Method.toJSONWithCleanData(),
96
- functional: pickSlugFromObject(this.functional),
109
+ functional: this.functional,
97
110
  refiners: this.refiners,
98
111
  modifiers: this.modifiers,
99
112
  ...restJson,
100
- };
113
+ } as DFTModelSchema;
101
114
  }
102
115
 
103
116
  get allFunctionals(): SlugifiedEntry[] {
@@ -1,10 +1,9 @@
1
1
  import { Model } from "../model";
2
2
  import {
3
- getDefaultModelSubtypeForApplicationAndType,
4
- getDefaultModelTypeForApplication,
3
+ getDefaultModelTypeSubtypeForApplication,
5
4
  getTreeByApplicationNameAndVersion,
6
5
  } from "../tree";
7
- import type { ModelConfig } from "../types";
6
+ import type { ModelConfig, RequireFields } from "../types";
8
7
  import { DFTModel } from "./dft";
9
8
 
10
9
  export class ModelFactory {
@@ -21,20 +20,19 @@ export class ModelFactory {
21
20
  }
22
21
  }
23
22
 
24
- static createFromApplication(config: ModelConfig): Model {
23
+ static createFromApplication(config: RequireFields<ModelConfig, "application">): Model {
25
24
  const { application } = config;
26
25
  if (!application) {
27
26
  throw new Error("ModelFactory.createFromApplication: application is required");
28
27
  }
29
28
 
30
29
  const tree = getTreeByApplicationNameAndVersion(application);
31
- if (Object.keys(tree).length === 0) {
30
+ if (!tree || Object.keys(tree).length === 0) {
32
31
  return this.create({ ...config, type: "unknown", subtype: "unknown" });
33
32
  }
34
33
 
35
- const type = getDefaultModelTypeForApplication(application);
36
- const subtype = getDefaultModelSubtypeForApplicationAndType(application, type) || "unknown";
34
+ const typeSubtype = getDefaultModelTypeSubtypeForApplication(application);
37
35
 
38
- return this.create({ ...config, type, subtype });
36
+ return this.create({ ...config, ...typeSubtype });
39
37
  }
40
38
  }
package/src/js/tree.ts CHANGED
@@ -1,4 +1,9 @@
1
- import { ApplicationSchemaBase, SlugifiedEntry } from "@mat3ra/esse/dist/js/types";
1
+ import {
2
+ type DFTModelSchema,
3
+ type MLModelSchema,
4
+ type UnknownModelSchema,
5
+ ApplicationSchema,
6
+ } from "@mat3ra/esse/dist/js/types";
2
7
  import MODELS_TREE_CONFIG_BY_APPLICATION from "@mat3ra/standata/dist/js/runtime_data/models/modelsTreeConfigByApplication.json";
3
8
  import MODEL_TREE_DATA from "@mat3ra/standata/dist/js/runtime_data/models/modelTree.json";
4
9
  import lodash from "lodash";
@@ -14,7 +19,7 @@ export const METHODS = {
14
19
  } as const;
15
20
 
16
21
  export const getPseudopotentialTypesFromTree = (): string[] => {
17
- const dftTree = MODEL_TREE.dft as Record<string, any>;
22
+ const dftTree = MODEL_TREE.dft;
18
23
  const firstBranch = Object.values(dftTree)[0];
19
24
  return firstBranch?.methods?.pseudopotential || [];
20
25
  };
@@ -23,36 +28,49 @@ export const getDFTFunctionalsFromTree = (): string[] => {
23
28
  return Object.keys(MODEL_TREE.dft);
24
29
  };
25
30
 
26
- export const getDFTFunctionalsByApproximation = (approximation: string): string[] | undefined => {
27
- const dftTree = MODEL_TREE.dft as Record<string, any>;
31
+ export const getDFTFunctionalsByApproximation = (
32
+ approximation: "gga" | "lda" | "hybrid" | "other",
33
+ ): string[] | undefined => {
34
+ const dftTree = MODEL_TREE.dft;
28
35
  const branch = dftTree[approximation];
29
36
  return branch?.functionals;
30
37
  };
31
38
 
32
- export const treeSlugToNamedObject = (modelSlug: string): SlugifiedEntry => {
39
+ export function treeSlugToNamedObject<T extends string>(modelSlug: T) {
33
40
  return {
34
41
  slug: modelSlug,
35
- name: lodash.get(MODEL_NAMES, modelSlug, modelSlug),
36
- };
37
- };
42
+ name: lodash.get(MODEL_NAMES, modelSlug, modelSlug) as string,
43
+ } as const;
44
+ }
38
45
 
39
46
  export const getTreeByApplicationNameAndVersion = ({
40
47
  name,
41
- }: Pick<ApplicationSchemaBase, "name" | "version">): ModelTree => {
48
+ }: Pick<ApplicationSchema, "name" | "version">): ModelTree | undefined => {
42
49
  // TODO: add logic to filter by version when necessary
43
- // @ts-ignore
44
- return MODELS_TREE_CONFIG_BY_APPLICATION[name] || {};
45
- };
46
-
47
- export const getDefaultModelTypeForApplication = (application: ApplicationSchemaBase): string => {
48
- return Object.keys(getTreeByApplicationNameAndVersion(application))[0];
50
+ if (!(name in MODELS_TREE_CONFIG_BY_APPLICATION)) {
51
+ return undefined;
52
+ }
53
+ return MODELS_TREE_CONFIG_BY_APPLICATION[
54
+ name as keyof typeof MODELS_TREE_CONFIG_BY_APPLICATION
55
+ ];
49
56
  };
50
57
 
51
- export const getDefaultModelSubtypeForApplicationAndType = (
52
- application: ApplicationSchemaBase,
53
- type: string,
54
- ): string | undefined => {
58
+ export function getDefaultModelTypeSubtypeForApplication(
59
+ application: Pick<ApplicationSchema, "name" | "version">,
60
+ ) {
55
61
  const tree = getTreeByApplicationNameAndVersion(application);
56
- const subtypes = Object.keys(tree[type] || {});
57
- return subtypes[0];
58
- };
62
+
63
+ if (!tree) {
64
+ throw new Error(
65
+ `getDefaultModelTypeForApplication: tree not found for application ${application.name}`,
66
+ );
67
+ }
68
+
69
+ const type = Object.keys(tree)[0];
70
+ const subtype = Object.keys(tree[type] || {})[0] || "unknown";
71
+
72
+ return { type, subtype } as
73
+ | Pick<DFTModelSchema, "type" | "subtype">
74
+ | Pick<MLModelSchema, "type" | "subtype">
75
+ | Pick<UnknownModelSchema, "type" | "subtype">;
76
+ }
@@ -1,15 +1,28 @@
1
1
  import type {
2
- ApplicationSchemaBase,
3
- BaseModel,
2
+ ApplicationSchema,
4
3
  CategorizedMethod,
5
4
  CategorizedModel,
6
5
  CategorizedUnitMethod,
6
+ DFTModelSchema,
7
+ MLModelSchema,
8
+ UnknownModelSchema,
7
9
  } from "@mat3ra/esse/dist/js/types";
8
10
 
9
- export type ModelConfig = Pick<BaseModel, "type" | "subtype"> &
10
- Partial<Omit<BaseModel, "type" | "subtype">> & {
11
- application?: ApplicationSchemaBase;
12
- };
11
+ /**
12
+ * Makes specified fields required and all others optional
13
+ * TODO: consider moving to code.js
14
+ */
15
+ export type RequireFields<T, K extends keyof T> = Required<Pick<T, K>> & Partial<Omit<T, K>>;
16
+
17
+ type ModelRequiredFields = "type" | "subtype";
18
+
19
+ export type DFTModelConfig = RequireFields<DFTModelSchema, ModelRequiredFields>;
20
+ export type MLModelConfig = RequireFields<MLModelSchema, ModelRequiredFields>;
21
+ export type UnknownModelConfig = RequireFields<UnknownModelSchema, ModelRequiredFields>;
22
+
23
+ export type ModelConfig = (DFTModelConfig | MLModelConfig | UnknownModelConfig) & {
24
+ application?: ApplicationSchema;
25
+ };
13
26
 
14
27
  export type SimplifiedCategorizedModel = Pick<
15
28
  CategorizedModel,
@@ -20,13 +33,6 @@ export type SimplifiedCategorizedMethod = Pick<CategorizedMethod, "name" | "path
20
33
  units: CategorizedUnitMethod[];
21
34
  };
22
35
 
23
- export interface PseudopotentialLike {
24
- element?: string;
25
- toJSON(): Record<string, unknown>;
26
- }
27
-
28
- export type PseudopotentialCtor = new (config: Record<string, unknown>) => PseudopotentialLike;
29
-
30
36
  export interface MethodTreeBranch {
31
37
  methods: Record<string, string[]>;
32
38
  functionals?: string[];