Skip to content

Extend yambo spectra#158

Open
Jajar26 wants to merge 15 commits into
FAIRmat-NFDI:extend-yambofrom
Jajar26:extend-yambo
Open

Extend yambo spectra#158
Jajar26 wants to merge 15 commits into
FAIRmat-NFDI:extend-yambofrom
Jajar26:extend-yambo

Conversation

@Jajar26

@Jajar26 Jajar26 commented Mar 17, 2026

Copy link
Copy Markdown

Work in progress to share

l275-304
#start HB
def get_spectra(self) -> dict[str, Any]:
data = []
names = []

    with open(self.filepath) as f:
        for line in f:
            line = line.strip()

            if line.startswith('#') and 'E/ev' in line:
                names = [k.strip() for k in line.split() if k != '#']
                continue

            if names and not line.startswith('#') and line:
                data.append(line.split())

    if not data:
        return {}

    data = np.array(data, dtype=np.float64)

    if data.shape[1] < 2:
        return {}

    return dict(
        excitation_energies=data[:, 0] * ureg.eV,
        intensities=data[:, 1]
    )

    #end HB

l345-373

#start HB
SPECTRA_TYPE_MAP = {
'Absorption': 'dielectric_function',
'EELS': 'energy_loss_spectrum',
}

    for spectra_file in spectra_files:
        spectra_parser.filepath = spectra_file

        sp_type = mainfile_parser.data.get('sp_type')
        if sp_type is None:
            continue

        absorption_spectra_parser.data_object = yambo.outputs.AbsorptionSpectrum()

        spectra_parser.convert(absorption_spectra_parser)

        spectra_obj = absorption_spectra_parser.data_object
        spectra_obj.label = sp_type
        spectra_obj.type = SPECTRA_TYPE_MAP.get(sp_type, 'unknown')

        outputs = (
            data.outputs[-1] if data.outputs else data.m_create(yambo.outputs.Outputs)
        )
        outputs.m_append(
            yambo.outputs.AbsorptionSpectrum.m_def,
            spectra_obj,
        )
        #end HB

Jajar26 added 3 commits March 17, 2026 15:03
Refactor get_spectra method to parse data for EM and update spectra type based on sp_type.
Removed unnecessary initialization of AbsorptionSpectrum.
data = []
names = []

with open(self.filepath) as f:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should introduce a new file parser class for the spectra file, we do not want to append the data to the mainfile parser.

@emolteni emolteni Apr 8, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, maybe I'm missing something.... By "introducing a new file parser class for the spectra file" do you mean adding something to the definition of the class SpectraParser in file_parsers.py? Apart from that, in parser.py we indeed have a class YamboSpectraParser (into which my colleague Hajar and I have added some lines..). Moreover, are we really appending spectra data to the mainfile parser?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes indeed this is what I meant. We should have a file parser and a mapping parser. What you are trying to do at the moment is parsing the spectra file and appending it to a function call within the mainfile parser. Although this could work, I would like to as much as possible separate the auxiliary files.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so, if I understand correctly, what you suggest may mean handling spectra files similarly to how netcdf files are already handled, i.e. we should 1) "populate" the SpectraParser class definition in file_parser.py, possibly putting there some parts that currently are in the YamboSpectraParser class in parser.py, 2) making the YamboSpectraParser class (in parser.py) of MappingParser type, instead of TestParser type.

@ladinesa ladinesa Apr 9, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes indeed. You should put the part that search for spectra files in YamboArchiveWriter. You then create a YamboSpectraParser (mapping parser) in the archive writer similar to the net cdf case. You should add the corresponding annotations in the schema file and use a different annotation key e.g. yambo_spectra

# add to simulation outputs.absorption_spectra

spectra_obj = absorption_spectra_parser.data_object
spectra_obj.label = sp_type

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not do this here but instead add this in the annotation

else data.m_create(yambo.outputs.Outputs)
data.outputs[-1] if data.outputs else data.m_create(yambo.outputs.Outputs)
)
outputs.m_append(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should also add this to the Outputs annotation inorder to automate this

absorption_spectra_parser.annotation_key = yambo.SPECTRA_KEY

#start HB
SPECTRA_TYPE_MAP = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add this to init

@ladinesa

ladinesa commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Can you please add some test data with the spectra files?

def get_spectra(self, data: np.ndarray) -> dict[str, Any]:
return dict(excitation_energies=data[:, 0], intensities=data[:, 1])
#start HB
def get_spectra(self) -> dict[str, Any]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is already covered by the file parser I believe. DataTextParser will simply use np.loadtxt to read the file.

for spectra_file in spectra_files:
spectra_parser.filepath = spectra_file

sp_type = mainfile_parser.data.get('sp_type')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be spectra_parser.get('sp_type') as you defined it there.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

outputs.AbsorptionSpectrum.sp_type, SPECTRA_KEY, 'sp_type'
)
add_mapping_annotation(
outputs.AbsorptionSpectrum.n_energies, SPECTRA_KEY, 'n_energies'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n_energies is not defined in the spectra parser.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, indeed. I wish to define it in the SpectraParser class in yambo/file_parsers.py, but in fact I am not sure how to define it, since it is a derived quantity (it is shape[0] of data.outputs, or anyway of the object that contains all the (energy,intensity) pairs of values of a spectrum), not defined by matching a specific regular expression (at a difference with sp_type and many other quantities in that or other file_parsers.py).

There might be an alternative way of defining n_energies, by looking for the line containing the expression "Energy steps" in the o* file(s).

class Outputs(outputs.Outputs):
# TODO add description
sp_type = Quantity(type=str)
# sp_type = Quantity(type=str) # EM: commented, 6 Jul, 2026

@ladinesa ladinesa Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is sp_type already in the nomad-simulations Outputs?

@emolteni emolteni Jul 8, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it isn't. So, here in /schema_packages/yambo.py, should I uncomment it in the class Outputs or rather put it in the class AbsorptionSpectra?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah i get it now, sorry it is already in AbsorptionSpectra.

@ladinesa ladinesa Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adsorption_spectra is not in nomad-simulation Outputs. so maybe add

 adsorption_spectra = SubSection(sub_section=AbsorptionSpectra.m_def, repeats=True)

under class Outputs in yambo.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, in fact we do have a line:
absorption_spectra = SubSection(sub_section=AbsorptionSpectrum.m_def, repeats=True)

in nomad_simulations/schema_packages/outputs.py.

But it seems we never use this "absorption_spectra" anywhere, am I wrong? I'll see if I can understand this while I fix the other issues you mentioned.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I see it there, at line 148.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my bad, I was searching for adsorption_spectra

@emolteni emolteni Jul 8, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, perfect. About the misspell, I had noticed it in your messages but forgot to point it out. In this context, it is always absorption.

@ladinesa

ladinesa commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

With the added test data, can you please also add the tests for the yambo parser?

@emolteni

emolteni commented Jul 8, 2026

Copy link
Copy Markdown

With the added test data, can you please also add the tests for the yambo parser?

I have just created a tentative version of a test_yambo_parser.py file for testing spectra parsing, trying to follow the structure of other test parsers in that folder. I am not so confident about it.....

As for my /test/data/yambo folder, instead, I had to upload its /SAVE folder zipped due to file size limits, and for the same reason the system does not allow me to unzip it there on github. The SAVE folder (which contains the ns.db file) should not be needed for spectra parsing, but its absence is expected to lead to missing parsing of atom coordinates, chemical composition, cell parameters, which in "production" parsing is unpleasant. If you think we can ignore this for the tests, then I can just delete the /SAVE folder.

archive = EntryArchive()
parser = YamboArchiveWriter()
parser.parse('tests/data/yambo/r_setup',archive,LOGGER)
assert spectra_files[0] = 'o-R_methylox_TDLDA.alpha_q1_slepc_alda_bse'

@ladinesa ladinesa Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion here should be

spectra = archive.data.outputs[0].adsorption_spectra[0]
assert spectra.sp_type == 'Polarizability'
...

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, i.e. I have put your lines in place of my previous line on checking spectra type.

I expect the previous line, which should check it finds our spectra file, is ok? There I have spectra_files[0] because, in principle, spectra_file is a list, but in the present case it contains 1 file only.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no spectra_file defined under AdsorptionSpectra only: value, energies, sp_typeand n_energies

@@ -114,4 +122,4 @@

@ladinesa ladinesa Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should also add an annotation for Outputs.m_def here with SPECTRA_KEY something like

add_mapping_annotation(Outputs.m_def, SPECTRA_KEY, '.@')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


add_mapping_annotation(general.Simulation.m_def, OUT_KEY, '@')
add_mapping_annotation(general.Simulation.m_def, NETCDF_KEY, '@')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also for general.Simulation.m_def

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done (line 125), but for some reason it does not label it as "outdated" here.


spectra_obj = absorption_spectra_parser.data_object
spectra_obj.label = sp_type
spectra_obj.type = SPECTRA_TYPE_MAP.get(sp_type, 'unknown')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, labeland type are not defined in AdsorptionSpectra

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we would like to use the new definition for AbsorptionSpectrum, this should be: AbsorptionSpectrum.m_def not outputs.AbsorptionSpectrum.m_def

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants