Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore/SOF-6505 #15

Merged
merged 31 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9d52142
chore: add js-yaml package
azech-hqs Apr 25, 2023
8605b48
chore: add ESSE as dependency
azech-hqs Apr 26, 2023
a85ce9b
chore: add MWE for asset generation
azech-hqs Apr 26, 2023
28aab2b
refactor: move yaml types to code.js + cleanup
azech-hqs Apr 28, 2023
19163f6
chore: generate name based on template
azech-hqs Apr 28, 2023
0c12993
chore: update code.js
azech-hqs Apr 29, 2023
ccddce1
chore: validate configs upon creation
azech-hqs Apr 29, 2023
40e28d5
chore: use esse YAML tag to retrieve parameter values
azech-hqs May 8, 2023
5b67e62
chore: use same object path notation as JSON schema
azech-hqs May 15, 2023
b3242a2
chore: use nunjucks to generate name from template
azech-hqs May 15, 2023
b7c4942
chore: code.js++: allow null parameters
azech-hqs May 16, 2023
fcb361e
chore: move generateName to codeJS + cleanup
azech-hqs May 16, 2023
568e6e2
chore: use PBE example for asset generation
azech-hqs May 16, 2023
2fb51f7
chore: add asset for short-term methods
azech-hqs May 16, 2023
9c27073
chore: first draft of build_methods script
azech-hqs May 16, 2023
a27dac6
chore: move pw and psp assets to separate dir
azech-hqs May 17, 2023
c467902
chore: rename + use isOptional key
azech-hqs May 17, 2023
8c2a9f7
chore: first draft of GW configs
azech-hqs May 17, 2023
21afb45
chore: add hybrid functional asset + cleanup other assets
azech-hqs May 17, 2023
c6b8ddb
chore: adjust build script to use all assets
azech-hqs May 17, 2023
e95860c
chore: move asset creation to single script
azech-hqs May 19, 2023
a813fcc
chore: use include tag to load units
azech-hqs May 19, 2023
f4f6700
chore: update codeJS
azech-hqs May 19, 2023
07930ee
chore: rename build script
azech-hqs May 19, 2023
87dc2d3
chore: use slugs instead of slugified objects
azech-hqs May 25, 2023
018d68f
style: use variable for logs + improve readability
azech-hqs May 25, 2023
a6f5270
chore: add fn to encode data as URL
azech-hqs May 25, 2023
837a1b3
chore: add build script for assets
azech-hqs May 25, 2023
6514438
docs: add docstrings to build script
azech-hqs May 25, 2023
91fb849
chore: update code.js
azech-hqs May 31, 2023
8d7dd69
chore: update package*.json
azech-hqs Jun 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions assets/methods/methods.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
!combine
name:
# note the order of units is reversed as compared to the list below, i.e. units[3] is the plane wave unit
template: "{{ units[3]['categories']['type'] | upper }}-{{ units[2]['categories']['subtype'] | upper + 'PP' }} ({{ units[1]['name'] }}, {{ units[0]['categories']['subtype'] | title }} {{'Tetrahedron Method' if units[0]['categories']['type'] == 'tetrahedron' else 'Smearing'}})"
substitutions:
pw: PW
nc: NC
paw: PAW
us: US
forEach:
- key: units
action: push
values: !include assets/methods/units/pw.yml
- key: units
action: push
values: !include assets/methods/units/psp.yml
- key: units
action: push
values: !include assets/methods/units/diagonalization.yml
- key: units
action: push
values: !include assets/methods/units/occupations.yml
config:
schema: !esse method
25 changes: 25 additions & 0 deletions assets/methods/units/diagonalization.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
!combine
name:
template: "{{ categories.type }} Diagonalization"
substitutions:
cg: Conjugate Gradient
config:
categories:
tier1: opt
tier2: diff
tier3: ordern
type: cg
tags:
- diagonalization
schema: !esse "methods-directory/mathematical/cg"
extraConfigs: !combine
name:
template: "{{ categories.type | title }} Diagonalization"
config:
categories:
tier1: linalg
tier2: diag
type: davidson
tags:
- diagonalization
schema: !esse "methods-directory/mathematical/davidson"
37 changes: 37 additions & 0 deletions assets/methods/units/occupations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
!combine
name:
template: "{{ categories.subtype }} Smearing"
substitutions:
gaussian: Gaussian
marzari-vanderbilt: Marzari-Vanderbilt
methfessel-paxton: Methfessel-Paxton
fermi-dirac: Fermi-Dirac
forEach:
- !parameter
key: categories.subtype
values: !esse "methods-category/physical/qm/wf/enum-options#/smearingSubtypes/enum"
exclude: "^(marzari|fermi)"
config:
categories:
tier1: qm
tier2: wf
type: smearing
tags:
- occupation number
schema: !esse "methods-directory/physical/smearing"
extraConfigs: !combine
name:
template: "{{ categories.subtype | title }} Tetrahedron Method"
forEach:
- !parameter
key: categories.subtype
values: !esse "methods-category/physical/qm/wf/enum-options#/tetrahedronSubtypes/enum"
exclude: "^(bloechl|optimized)"
config:
categories:
tier1: qm
tier2: wf
type: tetrahedron
tags:
- occupation number
schema: !esse "methods-directory/physical/tetrahedron"
23 changes: 23 additions & 0 deletions assets/methods/units/psp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# Pseudopotential method units
#
!combine
name:
template: "{{ categories.subtype }} Pseudopotential"
substitutions:
us: Ultra-soft
nc: Norm-conserving
paw: Projector-augmented wave
forEach:
- !parameter
key: categories.subtype
values: !esse "methods-category/physical/qm/wf/enum-options#/pseudoSubtypes/enum"
exclude: "^coulomb"
config:
categories:
tier1: qm
tier2: wf
type: psp
tags:
- pseudopotential
schema: !esse "methods-directory/physical/psp"
13 changes: 13 additions & 0 deletions assets/methods/units/pw.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# Planewave method unit
#
!combine
name: "Wave function: Plane wave"
config:
categories:
tier1: qm
tier2: wf
type: pw
tags:
- plane wave
schema: !esse "methods-directory/physical/pw"
42 changes: 42 additions & 0 deletions assets/models/gga.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
ldaConfigs: !combine
name:
template: "{{ parameters.functional }}{{ '-' + parameters.dispersionCorrection if parameters.dispersionCorrection }}{{ '+' + parameters.hubbardType if parameters.hubbardType}}{{ ' (SOC)' if parameters.spinOrbitCoupling }}{{ ' (' + parameters.spinPolarization + ')' if parameters.spinPolarization }}"
substitutions:
pbe: PBE
dft-d3: D3
u: U
forEach:
- !parameter
key: parameters.functional
values: !esse "model/mixins/dft/enum-options#/gga/enum"
- !parameter
key: parameters.dispersionCorrection
values: !esse "model/mixins/enum-options#/dispersionCorrection/enum"
exclude: "^(?!.*dft-d3).*$"
isOptional: true
- !parameter
key: parameters.spinOrbitCoupling
values: [true]
isOptional: true
- !parameter
key: parameters.hubbardType
values: !esse "model/mixins/enum-options#/hubbardType/enum"
isOptional: true
- !parameter
key: parameters.spinPolarization
values: !esse "model/mixins/enum-options#/spinPolarization/enum"
exclude: "^non-collinear"
isOptional: true
exclusions:
- [parameters.spinPolarization, parameters.spinOrbitCoupling]
- [parameters.hubbardType, parameters.dispersionCorrection]
config:
categories:
tier1: pb
tier2: qm
tier3: dft
type: ksdft
subtype: gga
tags:
- density functional theory
schema: !esse "models-directory/gga"
53 changes: 53 additions & 0 deletions assets/models/gw.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
- !combine
name:
template: "{{ categories.subtype }}@{{ parameters.functional }}"
substitutions:
pbe: PBE
g0w0: G0W0
evgw0: evGW0
evgw: evGW
forEach:
- !parameter
key: categories.subtype
values: !esse "models-category/pb/qm/abin/gw#/properties/subtype/enum"
- !parameter
key: parameters.functional
values: !esse "model/mixins/dft/enum-options#/gga/enum"

config:
categories:
tier1: pb
tier2: qm
tier3: abin
type: gw
parameters:
require: "pb/qm/dft/ksdft/gga?functional=pbe"
schema: !esse "models-directory/gw"

- !combine
name:
template: "{{ categories.subtype }}@{{ parameters.functional }}{{ ' (SOC)' if parameters.spinOrbitCoupling }}"
substitutions:
pbe: PBE
g0w0: G0W0
evgw0: evGW0
evgw: evGW
forEach:
- !parameter
key: categories.subtype
values: !esse "models-category/pb/qm/abin/gw#/properties/subtype/enum"
- !parameter
key: parameters.functional
values: !esse "model/mixins/dft/enum-options#/gga/enum"
- !parameter
key: parameters.spinOrbitCoupling
values: [true]
config:
categories:
tier1: pb
tier2: qm
tier3: abin
type: gw
parameters:
require: "pb/qm/dft/ksdft/gga?functional=pbe&spinOrbitCoupling=true"
schema: !esse "models-directory/gw"
36 changes: 36 additions & 0 deletions assets/models/hybrid.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
- !combine
name:
template: "{{ parameters.functional }}{{ '-' + parameters.dispersionCorrection if parameters.dispersionCorrection }}{{ ' (SOC)' if parameters.spinOrbitCoupling }}{{ ' (' + parameters.spinPolarization + ')' if parameters.spinPolarization }}"
substitutions:
hse06: HSE
dft-d3: D3
forEach:
- !parameter
key: parameters.functional
values: !esse "model/mixins/dft/enum-options#/hybrid/enum"
- !parameter
key: parameters.dispersionCorrection
values: !esse "model/mixins/enum-options#/dispersionCorrection/enum"
exclude: "^(?!.*dft-d3).*$"
isOptional: true
- !parameter
key: parameters.spinOrbitCoupling
values: [true]
isOptional: true
- !parameter
key: parameters.spinPolarization
values: !esse "model/mixins/enum-options#/spinPolarization/enum"
exclude: "^non-collinear"
isOptional: true
exclusions:
- [parameters.spinPolarization, parameters.spinOrbitCoupling]
config:
categories:
tier1: pb
tier2: qm
tier3: dft
type: ksdft
subtype: hybrid
tags:
- density functional theory
schema: !esse "models-directory/hybrid"
132 changes: 132 additions & 0 deletions build_entities.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { JsYamlAllSchemas } from "@exabyte-io/code.js/dist/utils";
import Ajv from "ajv";
import fs from "fs";
import yaml from "js-yaml";
import lodash from "lodash";
import path from "path";

const MODEL_ASSETS_PATH = "assets/models"
const METHOD_ASSETS_PATH = "assets/methods"
const LOG_VALIDATION = true;
const LOG_CONFIG_NAMES = true;
const METHOD_PATH_SEPARATOR = "::";

/** Get list of paths for asset files in a directory.
* @param {string} currentPath - Path to current directory, i.e. $PWD
* @param {string} assetExtension - File extension for asset files
* @param {boolean} resolvePath - whether to resolve the paths of asset files
*/
function getAssetFiles(currentPath, assetExtension = ".yml", resolvePath = true) {
const fileNames = fs
.readdirSync(currentPath)
.filter((dirItem) => path.extname(dirItem) === assetExtension);
if (resolvePath) return fileNames.map((fileName) => path.resolve(currentPath, fileName));
return fileNames;
}

/**
* Validate a config containing its schema.
* @param {Object} config - Config containing schema (`config.schema`)
* @param {boolean} debug - Whether to log validation output
*/
function validateConfig(config, debug = false) {
const ajv = new Ajv({allErrors: true, verbose: true});
const validate = ajv.compile(config.schema);
if (debug) console.log(`Validating config for ${config.schema.schemaId}: ...${validate(config) ? "OK" : "ERROR"}`);

if (validate.errors) {
console.error("Validation errors:", validate.errors);
throw new Error(`Validation failed for ${config.schema.schemaId}`)
}
}

/**
* Generates URL path based categories and parameters.
* @param {Object} data - model or unit method config
* @return {string} - entity path
*/
function encodeDataAsURLPath(data) {
const placeholder = 'unknown';

const path = ['tier1', 'tier2', 'tier3', 'type', 'subtype'].map(key => {
return lodash.get(data.categories, key, placeholder);
}).join('/');

const params = new URLSearchParams();
for (let key in data.parameters) {
if (lodash.isObject(data.parameters[key])) {
params.append(key, JSON.stringify(data.parameters[key]));
} else {
params.append(key, data.parameters[key]);
}
}

return params.toString() ? `/${path}?${params.toString()}` : `/${path}`;
}

/**
* Generates one or more model configs from asset and validates against corresponding schema.
* @param {string} assetPath - Path to asset file
* @param {boolean} debug - Whether to log model config name.
* @return {Object[]} - Array of model configs
*/
function createModelConfigs(assetPath, debug = false) {
const testContent = fs.readFileSync(assetPath, "utf-8");
const parsed = yaml.load(testContent, {schema: JsYamlAllSchemas});

// Assume either array of configs or object with array of configs as values
let configs = lodash.isPlainObject(parsed) ? Object.values(parsed).flat() : parsed.flat();

configs.forEach((config) => {
config.path = encodeDataAsURLPath(config);
validateConfig(config, LOG_VALIDATION);
delete config.schema;
});

if (debug) configs.forEach((c) => console.log(`Creating model config: ${c.name}`));
return configs;
}

/**
* Generates one of more method configs and validates against corresponding schema.
* @param {string} assetPath - Path to asset file
* @param {boolean} debug - Whether to log model config name.
* @return {Object[]} - Array of method configs
*/
function createMethodConfigs(assetPath, debug = false) {
const testContent = fs.readFileSync(assetPath, "utf-8");
const parsed = yaml.load(testContent, { schema: JsYamlAllSchemas });

// Iterate over groups of configs and set config-based values
parsed.forEach((config) => {
config.units.forEach((u) => {
u.path = encodeDataAsURLPath(u);
validateConfig(u, LOG_VALIDATION);
delete u.schema;
});
config.path = config.units.map((u) => u.path).join(METHOD_PATH_SEPARATOR);
validateConfig(config, LOG_VALIDATION);
delete config.schema;
});

if (debug) parsed.forEach((c) => console.log(`Creating method config: ${c.name}`));
return parsed;
}

// Build and write MODEL configs
try {
const modelAssetFiles = getAssetFiles(MODEL_ASSETS_PATH, ".yml");
const modelConfigs = modelAssetFiles.flatMap((asset) => createModelConfigs(asset, LOG_CONFIG_NAMES));
fs.writeFileSync("./model_list.js", `module.exports = ${JSON.stringify(modelConfigs)}`, "utf8");
} catch (e) {
console.error(e);
}

// Build and write METHOD configs
try {
const methodAssetFiles = getAssetFiles(METHOD_ASSETS_PATH, ".yml");
const methodConfigs = methodAssetFiles.flatMap((asset) => createMethodConfigs(asset, LOG_CONFIG_NAMES));
fs.writeFileSync("./method_list.js", `module.exports = ${JSON.stringify(methodConfigs)}`, "utf8");
} catch (e) {
console.error(e);
}
Loading
Loading