Skip to content

Commit 6f75cc2

Browse files
committed
feat: migrate ade as is
1 parent 315fb19 commit 6f75cc2

File tree

13 files changed

+751
-1
lines changed

13 files changed

+751
-1
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,25 @@ npm run transpile
4646
npm run test
4747
```
4848

49+
ADe
50+
===
51+
52+
The`ADe` package sits just below the `WoDe` package in the Mat3ra workflow
53+
ecosystem, where `ADe` houses entity definitions for:
54+
55+
- `Application` - uniquely determined by `name, [version], [build]`
56+
- `Executable` - defined for a given application and accessible from application by name
57+
- `Flavor` - defined for a given executable and accessible from executable by name
58+
- `Template` - a jinja template for an application input file
59+
60+
The relevant data parameterizing these entities is housed in
61+
the [Application Flavors](https://github.com/Exabyte-io/exabyte-application-flavors)
62+
repository. This includes the supported applications, executables, flavors,
63+
and defined templates.
64+
65+
Templates themselves are organized by application in a top-level `assets`
66+
directory in `application-flavors` and the API for loading and working with templates can be found in
67+
each application's `assets.js` module.
68+
At build time, all templates are loaded and compiled into a single monolithic
69+
JS file using `build_templates.js` so that it can be used in the client as well as in NodeJS.
70+
This is how templates are consumed from `applicaton-flavors` in `ADe`.

src/application.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import lodash from "lodash";
2+
import { getAppTree, getAppData, allApplications } from "@exabyte-io/application-flavors.js";
3+
import { NamedDefaultableInMemoryEntity } from "@exabyte-io/code.js/dist/entity";
4+
5+
import { Executable } from "./executable";
6+
import { getApplicationConfig, getExecutableConfig } from "./tree";
7+
8+
9+
export class Application extends NamedDefaultableInMemoryEntity {
10+
static Executable = Executable;
11+
12+
constructor(config) {
13+
const staticConfig = getApplicationConfig(config);
14+
super({...staticConfig, ...config});
15+
}
16+
17+
// TODO: extract this from application-flavors "global" default config for espresso 5.4.0
18+
static get defaultConfig() {
19+
return {
20+
name: 'espresso',
21+
shortName: 'qe',
22+
version: '5.4.0',
23+
summary: 'Quantum Espresso',
24+
build: 'Default',
25+
}
26+
}
27+
28+
static create(config) {
29+
return this.createFromNameVersionBuild(config);
30+
}
31+
32+
static createFromNameVersionBuild({name, version = null, build = "Default"}) {
33+
return new Application({name, version, build});
34+
}
35+
36+
getExecutables() {
37+
return this.executables;
38+
}
39+
40+
getBuilds() {
41+
const data = getAppData(this.prop("name"));
42+
const {versions} = data;
43+
const builds = ["Default"];
44+
versions.map((v) => v.build && builds.push(v.build));
45+
return lodash.uniq(builds);
46+
}
47+
48+
getVersions() {
49+
const data = getAppData(this.prop("name"));
50+
const {versions} = data;
51+
const these = versions.map((v) => v.version);
52+
return lodash.uniq(these);
53+
}
54+
55+
static getUniqueAvailableNames() {
56+
return allApplications;
57+
}
58+
59+
getExecutableByName(name = null) {
60+
return new this.constructor.Executable(
61+
getExecutableConfig({
62+
appName: this.prop("name"),
63+
execName: name,
64+
})
65+
);
66+
}
67+
68+
getExecutableByConfig(config) {
69+
return config ? this.getExecutableByName(config.name) : this.defaultExecutable;
70+
}
71+
72+
get defaultExecutable() {
73+
return this.getExecutableByName();
74+
}
75+
76+
// override upon inheritance
77+
get allowedModelTypes() {
78+
return []
79+
}
80+
81+
get summary() {
82+
return this.prop("summary");
83+
}
84+
85+
get version() {
86+
return this.prop("version");
87+
}
88+
89+
get build() {
90+
return this.prop("build");
91+
}
92+
93+
get shortName() {
94+
return this.prop("shortName", this.prop("name"));
95+
}
96+
97+
get executables() {
98+
const tree = getAppTree(this.prop("name"));
99+
return Object.keys(tree).map(key => {
100+
return new this.constructor.Executable(
101+
Object.assign({}, tree[key], {name: key})
102+
)
103+
})
104+
}
105+
106+
get hasAdvancedComputeOptions() {
107+
return this.prop("hasAdvancedComputeOptions");
108+
}
109+
110+
get isLicensed() {
111+
return this.prop("isLicensed");
112+
}
113+
114+
}

src/context.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { NWChemTotalEnergyContextProvider } from "./context/providers/nwchem/providers";
2+
export { QEPWXContextProvider, QENEBContextProvider } from "./context/providers/espresso/providers";
3+
export { VASPContextProvider, VASPNEBContextProvider } from "./context/providers/vasp/providers";
4+
export { ExecutableContextProvider } from "./context/providers"

src/context/providers.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { ContextProvider } from "@exabyte-io/code.js/dist/context";
2+
3+
export class ExecutableContextProvider extends ContextProvider {
4+
constructor(config) {
5+
super({
6+
...config,
7+
domain: "executable"
8+
});
9+
}
10+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import _ from "underscore";
2+
import lodash from "lodash";
3+
import { mix } from "mixwith";
4+
import s from "underscore.string";
5+
6+
import { Made } from "@exabyte-io/made.js";
7+
import { PERIODIC_TABLE } from "@exabyte-io/periodic-table.js";
8+
9+
import {
10+
MaterialContextMixinBuilder,
11+
MaterialsContextMixinBuilder,
12+
MaterialsSetContextMixin,
13+
MethodDataContextMixin,
14+
WorkflowContextMixin,
15+
JobContextMixin
16+
} from "@exabyte-io/code.js/dist/context";
17+
import { ExecutableContextProvider } from "../../providers";
18+
19+
export class QEPWXContextProvider extends mix(ExecutableContextProvider).with(
20+
MaterialContextMixinBuilder(Made.Material),
21+
MethodDataContextMixin,
22+
WorkflowContextMixin,
23+
JobContextMixin,
24+
) {
25+
26+
get atomSymbols() {return this.material.Basis.uniqueElements}
27+
28+
get atomicPositionsWithoutConstraints() {return this.material.Basis.atomicPositions}
29+
30+
get atomicPositions() {return this.material.Basis.atomicPositionsWithConstraints};
31+
32+
/*
33+
* @NOTE: Overriding getData makes this provider "stateless", ie. delivering data from scratch each time and not
34+
* considering the content of `this.data`, and `this.isEdited` field(s).
35+
*/
36+
getData() {
37+
38+
// the below values are read from PlanewaveDataManager instead
39+
// ECUTWFC = 40;
40+
// ECUTRHO = 200;
41+
42+
const IBRAV = 0;
43+
44+
return {
45+
IBRAV,
46+
RESTART_MODE: this.RESTART_MODE,
47+
NAT: this.atomicPositions.length,
48+
NTYP: this.atomSymbols.length,
49+
ATOMIC_POSITIONS: this.atomicPositions.join('\n'),
50+
ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS: this.atomicPositionsWithoutConstraints.join('\n'),
51+
CELL_PARAMETERS: this.CELL_PARAMETERS,
52+
ATOMIC_SPECIES: this.ATOMIC_SPECIES,
53+
}
54+
}
55+
56+
get RESTART_MODE() {
57+
return (this.job.parentJob || this.workflow.hasRelaxation) ? 'restart' : 'from_scratch';
58+
}
59+
60+
getPseudoBySymbol(symbol) {
61+
return (this.methodData.pseudo || []).find(p => p.element === symbol);
62+
}
63+
64+
get ATOMIC_SPECIES() {
65+
// atomic species with pseudopotentials
66+
return _.map(this.atomSymbols, (symbol) => {
67+
const pseudo = this.getPseudoBySymbol(symbol);
68+
return QEPWXContextProvider.symbolToAtomicSpecie(symbol, pseudo);
69+
}).join('\n');
70+
}
71+
72+
get CELL_PARAMETERS() {
73+
return this.material.Lattice.vectorArrays.map(x => {
74+
return x.map(y => {
75+
return s.sprintf('%14.9f', y).trim();
76+
}).join(' ');
77+
}).join('\n');
78+
79+
}
80+
81+
static symbolToAtomicSpecie(symbol, pseudo) {
82+
const el = PERIODIC_TABLE[symbol];
83+
const filename = pseudo ? lodash.get(pseudo, 'filename', s.strRightBack(pseudo.path, '/')) : '';
84+
return el ? s.sprintf('%s %f %s', symbol, el.atomic_mass, filename) : undefined;
85+
}
86+
}
87+
88+
export class QENEBContextProvider extends mix(ExecutableContextProvider).with(
89+
MaterialContextMixinBuilder(Made.Material),
90+
MaterialsContextMixinBuilder(Made.Material),
91+
MaterialsSetContextMixin,
92+
MethodDataContextMixin,
93+
WorkflowContextMixin,
94+
JobContextMixin,
95+
) {
96+
97+
getData() {
98+
const sortedMaterials = this.sortMaterialsByIndexInSet(this.materials);
99+
const PWXContexts = sortedMaterials.map(material => {
100+
const context = Object.assign({}, this.config.context, {material: material});
101+
const config = Object.assign({}, this.config, {context});
102+
return new QEPWXContextProvider(config).getData();
103+
});
104+
105+
return {
106+
..._.omit(PWXContexts[0], ["ATOMIC_POSITIONS", "ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS"]),
107+
FIRST_IMAGE: PWXContexts[0].ATOMIC_POSITIONS,
108+
LAST_IMAGE: PWXContexts[PWXContexts.length - 1].ATOMIC_POSITIONS,
109+
INTERMEDIATE_IMAGES: PWXContexts.slice(1, PWXContexts.length - 1).map(data => data.ATOMIC_POSITIONS),
110+
}
111+
}
112+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import _ from "underscore";
2+
import lodash from "lodash";
3+
import {mix} from "mixwith";
4+
import s from "underscore.string";
5+
import { Made } from "@exabyte-io/made.js";
6+
import { PERIODIC_TABLE } from "@exabyte-io/periodic-table.js";
7+
8+
import {
9+
MaterialContextMixinBuilder,
10+
MethodDataContextMixin,
11+
WorkflowContextMixin,
12+
JobContextMixin
13+
} from "@exabyte-io/code.js/dist/context";
14+
import { ExecutableContextProvider } from "../../providers";
15+
16+
export class NWChemTotalEnergyContextProvider extends mix(ExecutableContextProvider).with(
17+
MaterialContextMixinBuilder(Made.Material),
18+
MethodDataContextMixin,
19+
WorkflowContextMixin,
20+
JobContextMixin,
21+
) {
22+
23+
get atomSymbols() {return this.material.Basis.uniqueElements}
24+
25+
get atomicPositionsWithoutConstraints() {return this.material.Basis.atomicPositions}
26+
27+
get atomicPositions() {return this.material.Basis.atomicPositionsWithConstraints};
28+
29+
get cartesianAtomicPositions() {return this.material.toCartesian()};
30+
31+
/*
32+
* @NOTE: Overriding getData makes this provider "stateless", ie. delivering data from scratch each time and not
33+
* considering the content of `this.data`, and `this.isEdited` field(s).
34+
*/
35+
getData() {
36+
/*
37+
TODO: Create ability for user to define CHARGE, MULT, BASIS and FUNCTIONAL parameters.
38+
*/
39+
const CHARGE = 0;
40+
const MULT = 1;
41+
const BASIS = '6-31G';
42+
const FUNCTIONAL = 'B3LYP';
43+
44+
return {
45+
CHARGE: CHARGE,
46+
MULT: MULT,
47+
BASIS: BASIS,
48+
NAT: this.atomicPositions.length,
49+
NTYP: this.atomSymbols.length,
50+
ATOMIC_POSITIONS: this.atomicPositions.join('\n'),
51+
ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS: this.atomicPositionsWithoutConstraints.join('\n'),
52+
ATOMIC_SPECIES: this.ATOMIC_SPECIES,
53+
FUNCTIONAL: FUNCTIONAL,
54+
CARTESIAN: this.cartesianAtomicPositions,
55+
}
56+
}
57+
58+
get ATOMIC_SPECIES() {
59+
return _.map(this.atomSymbols, (symbol) => {
60+
return NWChemTotalEnergyContextProvider.symbolToAtomicSpecies(symbol);
61+
}).join('\n');
62+
}
63+
64+
static symbolToAtomicSpecies(symbol, pseudo) {
65+
const el = PERIODIC_TABLE[symbol];
66+
const filename = pseudo ? lodash.get(pseudo, 'filename', s.strRightBack(pseudo.path, '/')) : '';
67+
return el ? s.sprintf('%s %f %s', symbol, el.atomic_mass, filename) : undefined;
68+
}
69+
}

0 commit comments

Comments
 (0)