diff --git a/pyproject.toml b/pyproject.toml index 3d6dfd8..f1ad198 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,8 @@ dependencies = [ "fans" = "aiida_fans.calculations:FansCalculation" [project.entry-points."aiida.parsers"] "fans" = "aiida_fans.parsers:FansParser" +[project.entry-points."aiida.data"] +"fans" = "aiida_fans.data:MaterialData" # Build System [build-system] diff --git a/src/aiida_fans/calculations.py b/src/aiida_fans/calculations.py index 8b6311e..95e24ef 100644 --- a/src/aiida_fans/calculations.py +++ b/src/aiida_fans/calculations.py @@ -1,4 +1,4 @@ -"""CalcJob subclasses for aiida-fans calculations.""" +"""Subclasses of CalcJob for aiida-fans calculations.""" from json import dump from pathlib import Path @@ -11,6 +11,7 @@ from aiida.orm import Dict, Float, Int, List, SinglefileData, Str from h5py import File as h5File +from aiida_fans.data import MaterialData from aiida_fans.helpers import make_input_dict @@ -47,7 +48,8 @@ def define(cls, spec: CalcJobProcessSpec) -> None: ## Problem Type and Material Model spec.input("problem_type", valid_type=Str) spec.input("matmodel", valid_type=Str) - spec.input("material_properties", valid_type=Dict) + spec.input("material_phases", valid_type=Dict) + spec.input_namespace("material_properties", valid_type=MaterialData, dynamic=True) ## Solver Settings spec.input("method", valid_type=Str) spec.input("n_it", valid_type=Int) diff --git a/src/aiida_fans/data.py b/src/aiida_fans/data.py new file mode 100644 index 0000000..646b883 --- /dev/null +++ b/src/aiida_fans/data.py @@ -0,0 +1,17 @@ +"""Subclasses of Data for aiida-fans.""" + +from aiida.orm import Data + + +class MaterialData(Data): + """Data class to represent material properties.""" + + def __init__(self, **kwargs): + """Initialize the MaterialData instance.""" + bulk = kwargs.pop("bulk_modulus", None) + shear = kwargs.pop("shear_modulus", None) + super().__init__(**kwargs) + if bulk is not None: + self.base.attributes.set("bulk_modulus", bulk) + if shear is not None: + self.base.attributes.set("shear_modulus", shear) diff --git a/src/aiida_fans/helpers.py b/src/aiida_fans/helpers.py index e5cbd79..bd3c833 100644 --- a/src/aiida_fans/helpers.py +++ b/src/aiida_fans/helpers.py @@ -19,7 +19,10 @@ def make_input_dict(job: CalcJob) -> dict[str, Any]: ## Problem Type and Material Model "problem_type": job.inputs.problem_type.value, "matmodel": job.inputs.matmodel.value, - "material_properties": job.inputs.material_properties.get_dict(), + "material_properties": { + "bulk_modulus": [mat.base.attributes.get("bulk_modulus") for mat in job.inputs.material_properties], + "shear_modulus": [mat.base.attributes.get("shear_modulus") for mat in job.inputs.material_properties], + }, ## Solver Settings "method": job.inputs.method.value, "n_it": job.inputs.n_it.value, diff --git a/src/aiida_fans/parsers.py b/src/aiida_fans/parsers.py index f22b21e..2d35d7a 100644 --- a/src/aiida_fans/parsers.py +++ b/src/aiida_fans/parsers.py @@ -1,4 +1,4 @@ -"""Parser subclass for aiida-fans calculations.""" +"""Subclass of Parser for aiida-fans calculations.""" from pathlib import Path diff --git a/src/aiida_fans/readme_submit.py b/src/aiida_fans/readme_submit.py new file mode 100644 index 0000000..29a61f1 --- /dev/null +++ b/src/aiida_fans/readme_submit.py @@ -0,0 +1,83 @@ +"""This is an example submit script. It should **not** be committed to dev.""" + +from aiida import load_profile # type: ignore +from aiida.orm import load_code, load_node +from aiida.tools import delete_nodes + +from aiida_fans.utils import run_fans + +load_profile() + + +################################################################################ + +inputs = { + "code": load_code("FANS"), #! Code node goes here. + "microstructure": { + "file": load_node(label="microstructure.file"), #! Microstructure node goes here. + "datasetname": "/dset_0/image", + "L": [1.0, 1.0, 1.0] + }, + "results_prefix": "my_results", #? Optional + "problem_type": "mechanical", + "matmodel": "LinearElasticIsotropic", + + ###################################### + # Proposed material properties format: + "material_phases": { + "copper": [0, 2], + "aluminium": [1] + }, + # translates to: phase 0 = copper, phase 1 = aluminium, phase 2 = copper + # + # Under this format, each material would be its own node labelled "copper", + # "aluminium", etc., and they would be of various MaterialData types that + # the plugin defines for each supported matmodel. + # + # Additionally, each job would have a material_phases input which defines + # what materials occupy which phases of the microstructure. If the user were + # to provide materials inconsistent with the provided "matmodel", utils + # could reject the input without ever calling AiiDA or FANS. + # + # If an advanced user wishes to use a custom material, they must create the + # node themselves and provide it a unique label. That label can then simply + # be used in place of "copper" or "alumininum" above. + ###################################### + + "method": "cg", + "error_parameters": { + "measure": "Linfinity", + "type": "absolute", + "tolerance": 1e-10 + }, + "n_it": 100, + "macroscale_loading": [ + { + "strain_indices": [ 2, 3, 4, 5], + "stress_indices": [0, 1 ], + "strain": [[0.005, 0.0, 0.0, 0.0],[0.010, 0.0, 0.0, 0.0]], + "stress": [[0.0, 0.0],[0.0, 0.0]] + }, + { + "strain_indices": [ 4, 5], + "stress_indices": [0, 1, 2, 3 ], + "strain": [[0.001, 0.005],[0.005, 0.001]], + "stress": [[0.01, 0.0, 0.0, 0.0],[0.0, 0.01, 0.0, 0.0]] + } + ], + "results": [ # Optional + "stress", "strain", + "stress_average", "strain_average", + "phase_stress_average", "phase_strain_average", + "microstructure", "displacement", "absolute_error", + ], + + "metadata": { # Optional + # "label": "test calculation 1", + # "dry_run": True + } +} + +################################################################################ + +run_fans(inputs)