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

More Automatic Compliance with the format. #17

Merged
merged 2 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
143 changes: 85 additions & 58 deletions docs/index.html

Large diffs are not rendered by default.

Binary file modified docs/sac-format_manual.pdf
Binary file not shown.
107 changes: 105 additions & 2 deletions src/docs/index.org
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,14 @@ running.

*** Small

sac-format is *small*---in total (header + implementation--excluding comments)
it's fewer than 2000 lines of code. Small size opens the door to using on any
sac-format is *small*---in total (header + implementation--excluding comments) the
library is under 2100\ast{} lines of code. Small size opens the door to using on any
sort of hardware (old or new) and makes it easy to expand upon.

\ast{} This value includes only the library, excluding all testing/benchmarking
and example codes. Including =utests.cpp=, =benchmark.cpp=, =util.hpp=, the example
program (=list_sac=), and sac-format totals just over 5100 lines of code.

*** Documented

sac-format is extensively *documented*---both online and in the code. Nothing's
Expand Down Expand Up @@ -272,6 +276,100 @@ Every [[SAC-file format][SAC variable]] is accessed via getters and setters of t
- =trace.evla(32.89)=
- =trace.mag(3.21)=

**** Setter rules

Most of the setters are only constrained by the parameter type
(single-precision, double-precision, boolean, etc.). *Some* setters are
constrained by additional rules.

***** Required for sanity

Rules here are required because the sac-format library assumes them (not
strictly required by the SAC format standard). For instance, the geometric
functions assume certain bounds on latitudes and longitudes. sac-format
automatically imposes these rules.

****** =stla(input)=

Limited to $[-90, 90]$ degrees, input that is outside that range is reduced
using circular symmetry.

****** =stlo(input)=

Limited to $[-180, 180]$ degrees, input that is outside that range is reduced
using circular symmetry.

****** =evla(input)=

Limited to $[-90, 90]$ degrees, input that is outside that range is reduced
using circular symmetry.

****** =evlo(input)=

Limited to $[-180, 180]$ degrees, input that is outside that range is reduced
using circular symmetry.

***** Require for safety

Rules here are required by the SAC format standard. sac-format automatically
imposes these rules to prevent the creation of corrupt sac-files.

****** =npts(input)=

Because =npts= defines the size of the data vectors, changing this value will
change the size of =data1= and =data2=\ast{}. Increasing npts resizes the vectors
([[https://en.cppreference.com/w/cpp/container/vector/resize][std::vector::resize]]) by placing zeros at the *end* of the vectors. Reducing npts
resizes the vectors down to the *first npts* values.

Therefore, care must be taken to maintain separate copies of =data1= and
=data2=\ast{} if you plan to manipulate the original data *after* resizing.

\ast{} data2 has =npts= only if it is legal, otherwise it is of size 0.

****** =leven(input)=

Changing the value of =leven= potentially changes the legality of =data2=, it also
potentially affects the value of =iftype=.

If iftype$>1$, then leven must be ~true~ (evenly sampled data). Therefore, if
leven is made ~false~ in this scenario (unevenly sampled data) then iftype becomes
unset\ast{}.

If changing leven makes data2 legal\ast{}\ast{}, then data2 is resized to have
=npts= zeros.

\ast{} The SAC format defines the unset values for all data-types. For integers
(like iftype) it is the integer value ~-12345~.

\ast{}\ast{} If data2 was already legal, then it is unaffected.

****** =iftype(input)=

Changing the value of =iftype= poentially changes the legality of =data2=, it also potentially affects the value of =leven=.

If leven is =false=, then iftype must be either 1 or unset. Therefore, changing
iftype to have a value $>1$ requires that leven becomes =true= (evenly sampled
data).

If changing iftype makes data2 legal\ast{}, then data2 is resized to have =npts= zeros.

\ast{} If data2 was already legal, then it is unaffected.

****** =data1(input)=

If the size of =data1= is changed, then =npts= must change to reflect the new size.
If =data2= is legal, this adjusts its size to match as well.

****** =data2(input)=

If the size of =data2= is changed to be larger than 0 and it is illegal, it is
made legal by setting =iftype(2)= (spectral-data).

When the size of data2 changes, =npts= is updated to the new size and =data1= is
resized to match.

If =data2= is made illegal, its size is reduced to 0 while =npts= and =data1= are
unaffected.
*** Internal Structure

The SAC-trace stores the data internally in a series of pre-allocated
Expand Down Expand Up @@ -576,6 +674,11 @@ results (=utests --reporter=compact --success=).

To see additional options, run =utests -?=.

*** Using ctest

If you have CMake install, you can run the tests using =ctest=.


** Benchmarking

=benchmark.cpp= contains the benchmarks. Running it locally will provide
Expand Down
68 changes: 67 additions & 1 deletion src/sac_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,11 @@ void Trace::nevid(const int input) noexcept {
ints[sac_map.at(name::nevid)] = input;
}
void Trace::npts(const int input) noexcept {
ints[sac_map.at(name::npts)] = input;
if ((input >= 0) || (input == unset_int)) {
ints[sac_map.at(name::npts)] = input;
const size_t size{static_cast<size_t>(input >= 0 ? input : 0)};
resize_data(size);
}
}
void Trace::nsnpts(const int input) noexcept {
ints[sac_map.at(name::nsnpts)] = input;
Expand All @@ -946,6 +950,12 @@ void Trace::nysize(const int input) noexcept {
}
void Trace::iftype(const int input) noexcept {
ints[sac_map.at(name::iftype)] = input;
const int size{npts() >= 0 ? npts() : 0};
// Uneven 2D data not supported as not in specification
if ((input > 1) && !leven()) {
leven(true);
}
resize_data2(size);
}
void Trace::idep(const int input) noexcept {
ints[sac_map.at(name::idep)] = input;
Expand Down Expand Up @@ -983,6 +993,12 @@ void Trace::ibody(const int input) noexcept {
// Bools
void Trace::leven(const bool input) noexcept {
bools[sac_map.at(name::leven)] = input;
const int size{npts() >= 0 ? npts() : 0};
// Uneven 2D data not supported since not in specification
if (!input && (iftype() > 1)) {
iftype(unset_int);
}
resize_data2(size);
}
void Trace::lpspol(const bool input) noexcept {
bools[sac_map.at(name::lpspol)] = input;
Expand Down Expand Up @@ -1066,9 +1082,59 @@ void Trace::kinst(const std::string &input) noexcept {
// Data
void Trace::data1(const std::vector<double> &input) noexcept {
data[sac_map.at(name::data1)] = input;
// Propagate change as needed
size_t size{data1().size()};
size = (((size == 0) && (npts() == unset_int)) ? unset_int : size);
if (static_cast<int>(size) != npts()) {
npts(static_cast<int>(size));
}
}
void Trace::data2(const std::vector<double> &input) noexcept {
data[sac_map.at(name::data2)] = input;
// Proagate change as needed
size_t size{data2().size()};
size = (((size == 0) && (npts() == unset_int)) ? unset_int : size);
// Need to make sure this is legal
// If positive size and not-legal, make spectral
if (size > 0) {
// If not legal, make spectral
if (leven() && (iftype() <= 1)) {
iftype(2);
}
// If legal and different from npts, update npts
if ((!leven() || (iftype() > 1)) && (static_cast<int>(size) != npts())) {
npts(static_cast<int>(size));
}
}
}

void Trace::resize_data1(const size_t size) noexcept {
if (size != data1().size()) {
std::vector<double> new_data1{data1()};
new_data1.resize(size, 0.0);
data1(new_data1);
}
}

void Trace::resize_data2(const size_t size) noexcept {
// Data2 is legal
if (!leven() || (iftype() > 1)) {
if (size != data2().size()) {
std::vector<double> new_data2{data2()};
new_data2.resize(size, 0.0);
data2(new_data2);
}
} else {
if (!data2().empty()) {
std::vector<double> new_data2{};
data2(new_data2);
}
}
}

void Trace::resize_data(const size_t size) noexcept {
resize_data1(size);
resize_data2(size);
}
//------------------------------------------------------------------------------
// Read
Expand Down
3 changes: 3 additions & 0 deletions src/sac_format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,9 @@ class Trace {
void calc_az() noexcept;
void calc_baz() noexcept;
bool geometry_set() const noexcept;
void resize_data1(size_t size) noexcept;
void resize_data2(size_t size) noexcept;
void resize_data(size_t size) noexcept;
// Objects
// cppcheck-suppress unusedStructMember
std::array<float, num_float> floats{};
Expand Down
Loading