Loading...
Searching...
No Matches
Structure File
IO

Provides files and formats for handling structure data. More...

Collaboration diagram for Structure File:

## Classes

class | seqan3::format_vienna
| The Vienna format (dot bracket notation) for RNA sequences with secondary structure. More...
class | seqan3::structure_file_input< traits_type_, selected_field_ids_, valid_formats_ >
| A class for reading structured sequence files, e.g. Stockholm, Connect, Vienna, ViennaRNA bpp matrix ... More...
struct | seqan3::structure_file_input_default_traits_aa
| A traits type that specifies input as amino acids. More...
struct | seqan3::structure_file_input_default_traits_rna
| The default traits for seqan3::structure_file_input. More...
interface | seqan3::structure_file_input_format< t >
| The generic concept for structure file in formats. More...
struct | seqan3::structure_file_input_options< seq_legal_alphabet, structured_seq_combined >
| The options type defines various option members that influence the behaviour of all or some formats. More...
interface | structure_file_input_traits
| The requirements a traits_type for seqan3::structure_file_input must meet. More...
class | seqan3::structure_file_output< selected_field_ids_, valid_formats_ >
| A class for writing structured sequence files, e.g. Stockholm, Connect, Vienna, ViennaRNA bpp matrix ... More...
interface | seqan3::structure_file_output_format< t >
| The generic concept for structure file out formats. More...
struct | seqan3::structure_file_output_options
| The options type defines various option members that influence the behaviour of all or some formats. More...
class | seqan3::structure_record< field_types, field_ids >
| The record type of seqan3::structure_file_input. More...

## Detailed Description

Provides files and formats for handling structure data.

### Reading structure files

Structured sequence files contain intra-molecular interactions of RNA or protein. Usually, but not necessarily, they contain the nucleotide or amino acid sequences and descriptions as well. Interactions can be represented either as fixed secondary structure, where every character is assigned at most one interaction partner (structure of minimum free energy), or an annotated sequence, where every character is assigned a set of interaction partners with specific base pair probabilities.
The structured sequence file abstraction supports reading ten different fields:

1. seqan3::field::seq (sequence)
2. seqan3::field::id (identifier)
3. seqan3::field::bpp (annotated sequence)
4. seqan3::field::structure (secondary structure)
5. seqan3::field::structured_seq (sequence and structure in one range)
6. seqan3::field::energy (minimum free energy)
7. seqan3::field::react (reactivity)
8. seqan3::field::react_err (reactivity error)
9. seqan3::field::comment (free text)
10. seqan3::field::offset (index of first sequence character)

The first three fields are retrieved by default (and in that order). The seqan3::field::structured_seq may be selected to have sequence and structure directly stored in a more memory-efficient combined container. If you select this field you must not select seqan3::field::seq or seqan3::field::structure.

#### Construction and specialisation

This class comes with two constructors, one for construction from a file name and one for construction from an existing stream and a known format. The first one automatically picks the format based on the extension of the file name. The second can be used if you have a non-file stream, like std::cin or std::istringstream, that you want to read from and/or if you cannot use file-extension based detection, but know that your input file has a certain format.
In most cases the template parameters are deduced completely automatically, e.g. reading from a std::istringstream:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <filesystem>
#include <sstream>
#include <seqan3/alphabet/nucleotide/rna4.hpp>
#include <seqan3/alphabet/structure/wuss.hpp>
#include <seqan3/io/structure_file/input.hpp>
#include <seqan3/io/structure_file/output.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA
(((((((..((((........)))).((((.........)))).....(((((.......)))))))))))). (-17.50)
> example
UUGGAGUACACAACCUGUACACUCUUUC
..(((((..(((...)))..)))))... (-3.71))";
int main()
{
auto tmp_file = std::filesystem::temp_directory_path() / "my.dbn";
using namespace seqan3::literals;
// First, make /tmp/input.dbn
{
seqan3::structure_file_output fout{tmp_file};
fout.emplace_back("GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA"_rna4,
"S.cerevisiae_tRNA-PHE M10740/1-73",
"(((((((..((((........)))).((((.........)))).....(((((.......))))))))))))."_wuss51);
fout.emplace_back("UUGGAGUACACAACCUGUACACUCUUUC"_rna4, "example", "..(((((..(((...)))..)))))..."_wuss51);
}
seqan3::structure_file_input sf{tmp_file}; // Vienna with RNA sequences assumed, use regular std::ifstream as stream
seqan3::structure_file_input fin{std::istringstream{input}, seqan3::format_vienna{}};
// ^ no need to specify the template arguments
std::filesystem::remove(tmp_file);
}
std::istringstream
seqan3::format_vienna
The Vienna format (dot bracket notation) for RNA sequences with secondary structure.
Definition format_vienna.hpp:83
seqan3::structure_file_input
A class for reading structured sequence files, e.g. Stockholm, Connect, Vienna, ViennaRNA bpp matrix ...
Definition structure_file/input.hpp:358
seqan3::structure_file_output
A class for writing structured sequence files, e.g. Stockholm, Connect, Vienna, ViennaRNA bpp matrix ...
Definition io/structure_file/output.hpp:60
seqan3::structure_file_output::emplace_back
void emplace_back(arg_t &&arg, arg_types &&... args)
Write a record to the file by passing individual fields.
Definition io/structure_file/output.hpp:363
filesystem
output.hpp
Provides seqan3::structure_file_output and corresponding traits classes.
seqan3::literals
The SeqAn namespace for literals.
std::filesystem::remove
T remove(T... args)
rna4.hpp
Provides seqan3::rna4, container aliases and string literals.
sstream
input.hpp
Provides seqan3::structure_file_input and corresponding traits classes.
std::filesystem::temp_directory_path
T temp_directory_path(T... args)
wuss.hpp
Provides the WUSS format for RNA structure.

Note that this is not the same as writing structure_file_input<> (with angle brackets). In the latter case they are explicitly set to their default values, in the former case automatic deduction happens which chooses different parameters depending on the constructor arguments. For opening from file, structure_file_input<> would have also worked, but for opening from stream it would not have.
In some cases, you do need to specify the arguments, e.g. if you want to read amino acids:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <seqan3/io/structure_file/input.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA
(((((((..((((........)))).((((.........)))).....(((((.......)))))))))))). (-17.50)
> example
UUGGAGUACACAACCUGUACACUCUUUC
..(((((..(((...)))..)))))... (-3.71))";
int main()
{
seqan3::structure_file_input<seqan3::structure_file_input_default_traits_rna> fin{std::istringstream{input},
seqan3::format_vienna{}};
}

You can define your own traits type to further customise the types used by and returned by this class, see seqan3::structure_file_default_traits_rna for more details. As mentioned above, specifying at least one template parameter yourself means that you loose automatic deduction so if you want to read amino acids and want to read from a string stream you need to give all types yourself:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <seqan3/io/structure_file/input.hpp>
#include <seqan3/utility/type_list/type_list.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
ACEWACEW
HGEBHHHH
> example
ACEWACEWACEWACEW
HGEBHHHHHGEBHHHH)";
int main()
{
// ... input had amino acid sequences
seqan3::structure_file_input<seqan3::structure_file_input_default_traits_aa,
seqan3::fields<seqan3::field::seq, seqan3::field::id, seqan3::field::structure>,
seqan3::type_list<seqan3::format_vienna>>
fin{std::istringstream{input}, seqan3::format_vienna{}};
}
seqan3::fields
A class template that holds a choice of seqan3::field.
Definition record.hpp:125
seqan3::structure_file_input_default_traits_aa
A traits type that specifies input as amino acids.
Definition structure_file/input.hpp:318
seqan3::type_list
Type that contains multiple types.
Definition type_list.hpp:26
type_list.hpp
Provides seqan3::type_list.

#### Reading record-wise

You can iterate over this file record-wise:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <seqan3/alphabet/views/to_char.hpp>
#include <seqan3/core/debug_stream.hpp>
#include <seqan3/io/structure_file/input.hpp>
#include <seqan3/utility/type_list/type_list.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
ACEWACEW
HGEBHHHH
> example
ACEWACEWACEWACEW
HGEBHHHHHGEBHHHH)";
int main()
{
using structure_file_input_t =
seqan3::structure_file_input<seqan3::structure_file_input_default_traits_aa,
seqan3::fields<seqan3::field::seq, seqan3::field::id, seqan3::field::structure>,
seqan3::type_list<seqan3::format_vienna>>;
structure_file_input_t fin{std::istringstream{input}, seqan3::format_vienna{}};
for (auto & rec : fin)
{
seqan3::debug_stream << "ID: " << rec.id() << '\n';
// sequence and structure are converted to char on-the-fly
seqan3::debug_stream << "SEQ: " << (rec.sequence() | seqan3::views::to_char) << '\n';
seqan3::debug_stream << "STRUCTURE: " << (rec.sequence_structure() | seqan3::views::to_char) << '\n';
}
}
debug_stream.hpp
Provides seqan3::debug_stream and related types.
seqan3::views::to_char
auto const to_char
A view that calls seqan3::to_char() on each element in the input range.
Definition to_char.hpp:60
seqan3::debug_stream
debug_stream_type debug_stream
A global instance of seqan3::debug_stream_type.
Definition debug_stream.hpp:38
to_char.hpp
Provides seqan3::views::to_char.

In the above example, rec has the type seqan3::structure_file_input::record_type which is a specialisation of seqan3::record and behaves like a std::tuple (that's why we can access it via get). Instead of using the seqan3::field based interface on the record, you could also use std::get<0> or even std::get<rna4_vector> to retrieve the sequence, but it is not recommended, because it is more error-prone.
Note: It is important to write auto & and not just auto, otherwise you will copy the record on every iteration. Since the buffer gets "refilled" on every iteration, you can also move the data out of the record if you want to store it somewhere without copying:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <utility>
#include <vector>
#include <seqan3/io/structure_file/input.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA
(((((((..((((........)))).((((.........)))).....(((((.......)))))))))))). (-17.50)
> example
UUGGAGUACACAACCUGUACACUCUUUC
..(((((..(((...)))..)))))... (-3.71))";
int main()
{
seqan3::structure_file_input fin{std::istringstream{input}, seqan3::format_vienna{}};
using record_type = typename decltype(fin)::record_type;
std::vector<record_type> records;
for (auto & rec : fin)
records.push_back(std::move(rec));
}
std::vector::push_back
T push_back(T... args)
utility
vector

#### Reading record-wise (decomposed records)

Instead of using get on the record, you can also use structured bindings to decompose the record into its elements:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <seqan3/alphabet/views/to_char.hpp>
#include <seqan3/core/debug_stream.hpp>
#include <seqan3/io/structure_file/input.hpp>
#include <seqan3/utility/type_list/type_list.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
ACEWACEW
HGEBHHHH
> example
ACEWACEWACEWACEW
HGEBHHHHHGEBHHHH)";
int main()
{
using seqan3::get;
using structure_file_input_t =
seqan3::structure_file_input<seqan3::structure_file_input_default_traits_aa,
seqan3::fields<seqan3::field::seq, seqan3::field::id, seqan3::field::structure>,
seqan3::type_list<seqan3::format_vienna>>;
structure_file_input_t fin{std::istringstream{input}, seqan3::format_vienna{}};
for (auto & [seq, id, structure] : fin)
{
seqan3::debug_stream << "ID: " << id << '\n';
// sequence and structure are converted to char on-the-fly
seqan3::debug_stream << "SEQ: " << (seq | seqan3::views::to_char) << '\n';
seqan3::debug_stream << "STRUCTURE: " << (structure | seqan3::views::to_char) << '\n';
}
}
seqan3::field::structure
@ structure
Fixed interactions, usually a string of structure alphabet characters.
Definition record.hpp:70
seqan3::field::seq
@ seq
The "sequence", usually a range of nucleotides or amino acids.
Definition record.hpp:62
seqan3::get
constexpr auto const & get(configuration< configs_t... > const &config) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition configuration.hpp:412

In this case you immediately get the three elements of the tuple: seq of seqan3::structure_file_input::seq_type, id of seqan3::structure_file_input::id_type and structure of seqan3::structure_file_input::structure_type. But beware: with structured bindings you do need to get the order of elements correctly!

#### Reading record-wise (custom fields)

If you want to skip specific fields from the record you can pass a non-empty fields trait object to the structure_file_input constructor to select the fields that should be read from the input. For example to choose a combined field for SEQ and STRUCTURE (see above). Or to never actually read the STRUCTURE, if you don't need it. The following snippets demonstrate the usage of such a fields trait object.

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <seqan3/alphabet/views/to_char.hpp>
#include <seqan3/core/debug_stream.hpp>
#include <seqan3/io/structure_file/input.hpp>
#include <seqan3/utility/views/elements.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA
(((((((..((((........)))).((((.........)))).....(((((.......)))))))))))). (-17.50)
> example
UUGGAGUACACAACCUGUACACUCUUUC
..(((((..(((...)))..)))))... (-3.71))";
int main()
{
using seqan3::get;
seqan3::structure_file_input fin{std::istringstream{input},
seqan3::format_vienna{},
seqan3::fields<seqan3::field::id, seqan3::field::structured_seq>{}};
// note that the order is now different, "id" comes first, because it was specified first
for (auto & [id, struc_seq] : fin)
{
seqan3::debug_stream << "ID: " << id << '\n';
// sequence and structure are part of the same vector, of type std::vector<structured_rna<rna5, wuss51>>
// sequence and structure strings are extracted and converted to char on-the-fly
seqan3::debug_stream << "SEQ: " << (struc_seq | seqan3::views::elements<0> | seqan3::views::to_char) << '\n';
seqan3::debug_stream << "STRUCTURE: " << (struc_seq | seqan3::views::elements<1> | seqan3::views::to_char)
<< '\n';
}
}
elements.hpp
Provides seqan3::views::elements.
seqan3::views::elements
constexpr auto elements
A view calling get on each element in a range.
Definition elements.hpp:77

When reading a file, all fields not present in the file (but requested implicitly or via the selected_field_ids parameter) are ignored.

#### Views on files

Since SeqAn files are ranges, you can also create views over files. A useful example is to filter the records based on certain criteria, e.g. minimum length of the sequence field:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <ranges>
#include <sstream>
#include <seqan3/alphabet/views/to_char.hpp>
#include <seqan3/core/debug_stream.hpp>
#include <seqan3/io/structure_file/input.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA
(((((((..((((........)))).((((.........)))).....(((((.......)))))))))))). (-17.50)
> example
UUGGAGUACACAACCUGUACACUCUUUC
..(((((..(((...)))..)))))... (-3.71))";
int main()
{
seqan3::structure_file_input fin{std::istringstream{input}, seqan3::format_vienna{}};
auto minimum_length5_filter = std::views::filter(
[](auto const & rec)
{
return std::ranges::size(rec.sequence()) >= 5;
});
for (auto & rec : fin | minimum_length5_filter) // only record with sequence length >= 5 will "appear"
seqan3::debug_stream << (rec.sequence() | seqan3::views::to_char) << '\n';
}

#### End of file

You can check whether a file is at end by comparing begin() and end() (if they are the same, the file is at end).

#### Formats

Currently, the only implemented format is seqan3::format_vienna. More formats will follow soon.

### Writing structure files

Structured sequence files contain intra-molecular interactions of RNA or protein. Usually, but not necessarily, they contain the nucleotide or amino acid sequences and descriptions as well. Interactions can be represented either as fixed secondary structure, where every character is assigned at most one interaction partner (structure of minimum free energy), or an annotated sequence, where every character is assigned a set of interaction partners with specific base pair probabilities.
The structured sequence file abstraction supports writing ten different fields:

1. seqan3::field::seq (sequence)
2. seqan3::field::id (identifier)
3. seqan3::field::bpp (annotated sequence)
4. seqan3::field::structure (secondary structure)
5. seqan3::field::structured_seq (sequence and structure in one range)
6. seqan3::field::energy (minimum free energy)
7. seqan3::field::react (reactivity)
8. seqan3::field::react_err (reactivity error)
9. seqan3::field::comment (free text)
10. seqan3::field::offset (index of first sequence character)

The member functions take any and either of these fields. If the field ID of an argument cannot be deduced, it is assumed to correspond to the field ID of the respective template parameter.

#### Construction and specialisation

This class comes with two constructors, one for construction from a file name and one for construction from an existing stream and a known format. The first one automatically picks the format based on the extension of the file name. The second can be used if you have a non-file stream, like std::cout or std::ostringstream, that you want to read from and/or if you cannot use file-extension based detection, but know that your output file has a certain format.
In most cases the template parameters are deduced completely automatically:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <filesystem>
#include <seqan3/io/structure_file/output.hpp>
int main()
{
auto tmp_file = std::filesystem::temp_directory_path() / "my.dbn";
seqan3::structure_file_output fout{tmp_file}; // Vienna format detected, std::ofstream opened for file
std::filesystem::remove(tmp_file);
}

Writing to std::cout:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <iostream>
#include <seqan3/alphabet/nucleotide/rna4.hpp>
#include <seqan3/alphabet/structure/wuss.hpp>
#include <seqan3/io/structure_file/output.hpp>
int main()
{
using namespace seqan3::literals;
seqan3::structure_file_output fout{std::cout, seqan3::format_vienna{}};
// ^ no need to specify the template arguments
fout.emplace_back("AACGUU"_rna4, "example_id", ".(())."_wuss51); // default order for vienna: SEQ, ID, STRUCTURE
}
std::cout
iostream

Note that this is not the same as writing structure_file_output<> (with angle brackets). In the latter case they are explicitly set to their default values, in the former case automatic deduction happens which chooses different parameters depending on the constructor arguments. Prefer deduction over explicit defaults.

#### Writing record-wise

You can iterate over this file record-wise:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include <seqan3/alphabet/nucleotide/rna5.hpp>
#include <seqan3/alphabet/structure/wuss.hpp>
#include <seqan3/io/structure_file/output.hpp>
int main()
{
using namespace seqan3::literals;
seqan3::structure_file_output fout{std::ostringstream{}, seqan3::format_vienna{}};
for (int i = 0; i < 10; i++) // ...
{
std::string id{"test_id"};
seqan3::rna5_vector seq{"ACGU"_rna5};
std::vector<seqan3::wuss51> structure{".()."_wuss51};
// ...
fout.emplace_back(seq, id, structure); // as individual variables
// or:
fout.push_back(std::tie(seq, id, structure)); // as a tuple
}
}
std::ostringstream
std::string
seqan3::structure_file_output::push_back
void push_back(record_t &&r)
Write a seqan3::record to the file.
Definition io/structure_file/output.hpp:286
rna5.hpp
Provides seqan3::rna5, container aliases and string literals.
string
std::tie
T tie(T... args)
tuple

The easiest way to write to a sequence file is to use the push_back() or emplace_back() member functions. These work similarly to how they work on a std::vector. If you pass a tuple to push_back() or give arguments to emplace_back() the seqan3::field ID of the i-th tuple-element/argument is assumed to be the i-th value of selected_field_ids, i.e. by default the first is assumed to be seqan3::field::seq, the second seqan3::field::id and the third one seqan3::field::structure. You may give less fields than are selected, if the actual format you are writing to can cope with less (e.g. for Vienna it is sufficient to write seqan3::field::seq, seqan3::field::id and seqan3::field::structure, even if selected_field_ids also contains seqan3::field::energy).
You may also use the output file's iterator for writing, however, this rarely provides an advantage.

#### Writing record-wise (custom fields)

If you want to pass a combined object for SEQ and STRUCTURE fields to push_back() / emplace_back(), or if you want to change the order of the parameters, you can pass a non-empty fields trait object to the structure_file_output constructor to select the fields that are used for interpreting the arguments.
The following snippets demonstrates the usage of such a fields trait object.

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include <seqan3/alphabet/nucleotide/rna5.hpp>
#include <seqan3/alphabet/structure/structured_rna.hpp>
#include <seqan3/alphabet/structure/wuss.hpp>
#include <seqan3/io/structure_file/output.hpp>
int main()
{
using namespace seqan3::literals;
seqan3::structured_rna<seqan3::rna5, seqan3::wuss51> sr{'G'_rna5, '.'_wuss51};
seqan3::structure_file_output fout{std::ostringstream{},
seqan3::format_vienna{},
seqan3::fields<seqan3::field::id, seqan3::field::structured_seq>{}};
for (int i = 0; i < 10; i++) // ...
{
std::string id{"test_id"};
// vector of combined data structure
std::vector<seqan3::structured_rna<seqan3::rna5, seqan3::wuss51>> structured_sequence{sr, sr, sr, sr};
// ...
// note also that the order the arguments is now different, because
// you specified that `seqan3::field::id` should be first in the fields template argument
fout.emplace_back(id, structured_sequence);
// or:
fout.push_back(std::tie(id, structured_sequence));
}
}
seqan3::structured_rna
A seqan3::alphabet_tuple_base that joins a nucleotide alphabet with an RNA structure alphabet.
Definition structured_rna.hpp:53
structured_rna.hpp
Provides the composite of nucleotide with structure alphabets.

A different way of passing custom fields to the file is to pass a seqan3::record – instead of a tuple – to push_back(). The seqan3::record clearly indicates which of its elements has which seqan3::field ID so the file will use that information instead of the template argument. This is especially handy when reading from one file and writing to another, because you don't have to configure the output file to match the input file, it will just work:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <seqan3/io/structure_file/input.hpp>
#include <seqan3/io/structure_file/output.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA
(((((((..((((........)))).((((.........)))).....(((((.......)))))))))))). (-17.50)
> example
UUGGAGUACACAACCUGUACACUCUUUC
..(((((..(((...)))..)))))... (-3.71))";
int main()
{
bool criteria = true;
seqan3::structure_file_input fin{std::istringstream{input},
seqan3::format_vienna{},
seqan3::fields<seqan3::field::id, seqan3::field::seq, seqan3::field::structure>{}};
// the output doesn't have to match the configuration of the input
seqan3::structure_file_output fout{std::ostringstream{}, seqan3::format_vienna{}};
for (auto & r : fin)
{
if (criteria) // r fulfills some filter criterium
fout.push_back(r);
}
}

#### Writing record-wise in batches

You can write multiple records at once, by assigning to the file:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include <seqan3/alphabet/nucleotide/rna5.hpp>
#include <seqan3/alphabet/structure/wuss.hpp>
#include <seqan3/io/structure_file/output.hpp>
int main()
{
using namespace seqan3::literals;
seqan3::structure_file_output fout{std::ostringstream{}, seqan3::format_vienna{}};
std::vector<std::tuple<seqan3::rna5_vector, std::string, std::vector<seqan3::wuss51>>> range{
{"ACGT"_rna5, "First", "...."_wuss51},
{"NATA"_rna5, "2nd", "...."_wuss51},
{"GATA"_rna5, "Third", "...."_wuss51}}; // a range of "records"
fout = range; // will iterate over the records and write them
}

#### File I/O pipelines

Record-wise writing in batches also works for writing from input files directly to output files, because input files are also input ranges in SeqAn. This can be combined with file-based views to create I/O pipelines:

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <seqan3/io/structure_file/input.hpp>
#include <seqan3/io/structure_file/output.hpp>
auto input = R"(> S.cerevisiae_tRNA-PHE M10740/1-73
GCGGAUUUAGCUCAGUUGGGAGAGCGCCAGACUGAAGAUUUGGAGGUCCUGUGUUCGAUCCACAGAAUUCGCA
(((((((..((((........)))).((((.........)))).....(((((.......)))))))))))). (-17.50)
> example
UUGGAGUACACAACCUGUACACUCUUUC
..(((((..(((...)))..)))))... (-3.71))";
int main()
{
seqan3::structure_file_input my_in{std::istringstream{input}, seqan3::format_vienna{}};
my_in | std::views::take(2) | seqan3::structure_file_output{std::ostringstream{}, seqan3::format_vienna{}};
}

#### Column-based writing

The record-based interface treats the file as a range of tuples (the records), but in certain situations you might have the data as columns, i.e. a tuple-of-ranges, instead of range-of-tuples.
You can use column-based writing in that case, it uses operator=() and seqan3::views::zip():

// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sstream>
#include <string>
#include <vector>
#include <seqan3/alphabet/container/concatenated_sequences.hpp>
#include <seqan3/alphabet/nucleotide/rna5.hpp>
#include <seqan3/alphabet/structure/wuss.hpp>
#include <seqan3/io/structure_file/output.hpp>
#include <seqan3/utility/views/zip.hpp>
using namespace seqan3::literals;
struct data_storage_t
{
seqan3::concatenated_sequences<seqan3::rna5_vector> sequences{"AACGUU"_rna5};
seqan3::concatenated_sequences<std::string> ids{std::string{"seq1"}};
seqan3::concatenated_sequences<std::vector<seqan3::wuss51>> structures{".(())."_wuss51};
};
int main()
{
data_storage_t data_storage{}; // a global or globally used variable in your program
// ... in your file writing function:
seqan3::structure_file_output fout{std::ostringstream{}, seqan3::format_vienna{}};
fout = seqan3::views::zip(data_storage.sequences, data_storage.ids, data_storage.structures);
}
seqan3::concatenated_sequences
Container that stores sequences concatenated internally.
Definition concatenated_sequences.hpp:86
concatenated_sequences.hpp
Provides seqan3::concatenated_sequences.
seqan3::views::zip
seqan::stl::views::zip zip
A view adaptor that takes several views and returns tuple-like values from every i-th element of each...
Definition zip.hpp:24
zip.hpp
Provides seqan3::views::zip.

#### Formats

Currently, the only implemented format is seqan3::format_vienna. More formats will follow soon.

Hide me