Great, thanks for the hard work. Adopting the entry points will pay off later down the road.
So I think you are missing installing the runschema and nomad_simulations. For that, you will need to add them. For adding them, it is as simple as adding these lines to the pyproject.toml in your plugin:
dependencies = [
"nomad-lab>=1.3.6.dev1", # import using `from nomad...`
"nomad-schema-plugin-run>=1.0.1", # import using `from runschema...`
"nomad-simulations>0.0.7", # import using `from nomad_simulations...`
]
And instead of pip installing nomad-lab in your environment using the first command, you can do:
This command will read the pyproject.toml and install the packages defined in dependencies and the optional ones in otherflags that you can define in the pyproject as well (see e.g. dev in this pyproject.toml).
Can you try this and let us know?
And in short as an explanation: you basically need to add as many dependencies as packages you are going to use. Like NOMAD uses heavily plugins, that includes nomad-lab, runschema and nomad-simulations.
Thanks @JosePizarro , importing from runschema works now. But how do I create custom quantities/subsections? For example I’m trying to create a quantity called current_density in the custom subsection run.calculation.currents. Since there’s no metainfo folder in the parser repo anymore, I changed schema_package.py into something like this:
from nomad.metainfo import Quantity, SchemaPackage, Section, MSection, SubSection
from runschema.calculation import Calculation
configuration = config.get_plugin_entry_point(
'lightforge_v2.schema_packages:schema_package_entry_point'
)
m_package = SchemaPackage()
class Currents(MSection):
m_def = Section(Validate=False)
current_density = Quantity(type=np.float64)
class LightforgeCalculation(runschema.calculation.Calculation):
m_def = Section(validate=False)
currents = SubSection(sub_section=Currents.m_def, repeats=False)
m_package.__init_metainfo__()
And then in parser.py:
from runschema.run import Run
from runschema.calculation import Calculation
from lightforge_v2.schema_packages.schema_package import Currents
sec_run = archive.m_create(Run)
sec_calc = sec_run.m_create(Calculation)
sec_currents = sec_calc.m_create(Currents) # error: There's no subsection to hold a schema_package.Currents section in runschema.calculation.Calculation section
But this throws the error 1 line above. How do I fix this? Thank you in advance.
Best
Fabian
So the error is trying to create a Currents section under Calculation. You should do it under LightforgeCalculation instead:
from runschema.run import Run
from lightforge_v2.schema_packages.schema_package import (
Currents,
LightforgeCalculation,
)
sec_run = archive.m_create(Run)
sec_calc = sec_run.m_create(LightforgeCalculation)
sec_currents = sec_calc.m_create(Currents)
This is because the class which has the definition of currents is LightforgeCalculation (runschema.Calculation does not have this attribute defined).
I also have some suggestions for you (you can consider them or just keep doing what you feel more comfortable, this is entirely up to you ):
No need to add m_def = Section(validate=False). In the m_def you can add certain “definitions” (in the NOMAD sense, “quantities that do not change at parsing time”), but turning off validation should not be one of them. Actually, I am not 100% sure that definition is working as intended (i.e., I think it just validates it, and it does not matter if you put validate=False or True). So it might be a deprecated feature already.
You can directly instantiate classes and assigns them to the attribute of a parent class, instead of using m_create. This is more appealing if you are used to work with Python and let’s you avoid using a criptic method very NOMAD-specific (so if someone takes this later, they will probably understand better if you don’t use such methods), so it could look like:
from runschema.run import Run
from lightforge_v2.schema_packages.schema_package import (
Currents,
LightforgeCalculation,
)
run = Run()
archive.run.append(run)
currents = Currents()
# populate currents here
calculation = LightforgeCalculation(currents=currents)
Note you can assign directly (calculation.currents = currents) or append (archive.run.append(Run())) depending whether the sub-section repeats or not (you can also assign lists directly, like archive.run = [Run()]).
And also some suggestions that I found out after working a lot with schemas, so from a personal experience (and I do not want to impose my style into yours, so feel free to accept them or not at will):
3. I would keep singular/plurals naming a bit more consistent. Using singular attribute names for sub-sections that repeats=False while plural when repeats=True.
4. A similar thing applies for attributes of a sub-section. E.g., if a class is called Currents and has an attribute for the density, you can simply call that attribute density, instead of current_density. You can imagine that at the end you will access data like ...current.density instead of ...current.current_density. Just a small detail, but it might also help you identifying common patterns (sections or quantities) across your sections/classes.
This gives me the error: "no subsection to hold schema_package.LightforgeCalculation section in runschema.run.Run section. So intuitively to solve this I introduce a LightforgeRun class in schema_package.py like this:
from runschema.run import Run
from runschema.calculation import Calculation
class Currents(MSection):
current_density = Quantity(type=np.float64)
class LightforgeCalculation(Calculation):
currents = SubSection(sub_section=Currents, repeats=False)
class LightforgeRun(Run):
lightforge_calculation = SubSection(sub_section=LightforgeCalculation, repeats=False)
and then import the new class LightforgeRun into parser.py and do this:
sec_run = archive.m_create(LightforgeRun)
sec_calc = sec_run.m_create(LightforgeCalculation)
# etc.
then I just get the similiar error: no subsection to hold schema_package.LightforgeRun section in nomad.datamodel.datamodel.EntryArchive section. How do I solve this error (or the first error)?
Best
Fabian
Weird… Might be an issue of m_create. Can you try with instantiating and appending classes as I suggested?
The underlying concept here is that we can use polymorphism to assign classes to attributes when they inherit from a more abstract class. I.e., if a class has a sub_section(sub_section=AbstractClass), you can directly assing other classes which inherit from that AbstractClass.
however the archive doesn’t show current_density = 9 anywhere
Ok, maybe, can you try doing nomad parse <path-to-the-file> --show-archive > test.json in a virtual environment where you installed your parser? This will save the archive in a test.json, and we can see whether the section Currents(current_density=9) was indeed created.
If you are trying it out in an OASIS, it might be that the GUI artifacts are not being generated. You can try reloading the page pressing F5. Otherwise, I defer to @laurih to help you with the OASIS in case the issue is there.
and also there are 2 warning messages:
These 2 warnings are completely normal, I’d say: they relate with the fact that you don’t have the System information under archive.run[0].system. So you can safely forget about them, or try to parse the System information if you have access to it. The warnings are coming from normalizers, i.e., a layer applied after parsing and responsible to apply logic to a bunch of different parsers.
I order to end up in the final archive, your instance of LightForgeCalculation must be assigned as a subsection somewhere.
I’m not familiar with your schema, but I would guess that it should be a part of the Run section instance, so something like:
run = Run()
archive.run.append(run)
currents = Currents()
calculation = LightforgeCalculation(currents=currents)
currents.current_density = 9
# Here we add the calculation to 'run'
run.calculations.append(calculation)
Indeed, you need to append LightforgrCalculation to run.
It is the line Lauri shared, but in singular (this is what I said before as a recommendation, a repeated subsection should be plural, but in this case is not and it feels a bit unnatural):