Skip to content

Commit

Permalink
gemmi-fprime: options to specify ranges of energies or wavelengths
Browse files Browse the repository at this point in the history
  • Loading branch information
wojdyr committed Jan 14, 2025
1 parent 4dfefa1 commit ef52e6d
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 12 deletions.
12 changes: 10 additions & 2 deletions docs/fprime-help.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
$ gemmi fprime -h
Usage:
gemmi fprime [options] ELEMENT[...]

Prints anomalous scattering factors f' and f".

Options:
-h, --help Print usage and exit.
-V, --version Print version and exit.
-e, --energy=ENERGY Energy [eV]
-w, --wavelength=LAMBDA Wavelength [A]
-e, --energy=ENERGY Energy [eV] or range of energies (e.g. 9.8:12.2).
-w, --wavelength=LAMBDA Wavelength [A] or range (e.g. 0.5:0.9).
-s, --step=STEP Step size for a range.
-n N Number of values in a range.

Options -e/-w can be given multiple times:
gemmi fprime -e 12.4 -e 11.5 -e 9.8 Se
If -e or -w specifies a range, -n or -s must be provided, e.g.:
gemmi fprime -w 0.5:0.9 -s 0.01 Os
75 changes: 65 additions & 10 deletions prog/fprime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "gemmi/elem.hpp" // for Element, find_element
#include "gemmi/fprime.hpp" // for cromer_liberman_for_array
#include "gemmi/math.hpp" // for hc
#include "gemmi/util.hpp" // for vector_move_extend
#include <cstdlib> // for atof
#include <stdio.h>

Expand All @@ -11,20 +12,30 @@

namespace {

enum OptionIndex { Energy=4, Wavelen };
enum OptionIndex { Energy=4, Wavelen, Step, Nvalues };

const option::Descriptor Usage[] = {
{ NoOp, 0, "", "", Arg::None,
"Usage:\n " EXE_NAME " [options] ELEMENT[...]"
"\nPrints anomalous scattering factors f' and f\"."
"\n\nPrints anomalous scattering factors f' and f\"."
"\n\nOptions:" },
CommonUsage[Help],
CommonUsage[Version],
//CommonUsage[Verbose],
{ Energy, 0, "e", "energy", Arg::Float,
" -e, --energy=ENERGY \tEnergy [eV]" },
{ Wavelen, 0, "w", "wavelength", Arg::Float,
" -w, --wavelength=LAMBDA \tWavelength [A]" },
{ Energy, 0, "e", "energy", Arg::NumberOrRange,
" -e, --energy=ENERGY \tEnergy [eV] or range of energies (e.g. 9.8:12.2)." },
{ Wavelen, 0, "w", "wavelength", Arg::NumberOrRange,
" -w, --wavelength=LAMBDA \tWavelength [A] or range (e.g. 0.5:0.9)." },
{ Step, 0, "s", "step", Arg::Float,
" -s, --step=STEP \tStep size for a range." },
{ Nvalues, 0, "n", "", Arg::Int,
" -n N \tNumber of values in a range." },
{ NoOp, 0, "", "", Arg::None,
"\nOptions -e/-w can be given multiple times:"
"\n " EXE_NAME " -e 12.4 -e 11.5 -e 9.8 Se"
"\nIf -e or -w specifies a range, -n or -s must be provided, e.g.:"
"\n " EXE_NAME " -w 0.5:0.9 -s 0.01 Os"
},
{ 0, 0, 0, 0, 0, 0 }
};

Expand All @@ -37,6 +48,32 @@ int GEMMI_MAIN(int argc, char **argv) {
fprintf(stderr, "Neither energy nor wavelength was specified.\n");
return -1;
}
p.check_exclusive_pair(Step, Nvalues);
bool range_error = false;
auto expand_range = [&](double xmin, double xmax) {
std::vector<double> result;
int nvalues = 0;
double step = 0.;
if (p.options[Step]) {
step = std::atof(p.options[Step].arg);
if ((xmax - xmin) * step < 0)
step = -step;
nvalues = int((xmax - xmin) / step + 1.01);
} else if (p.options[Nvalues]) {
nvalues = std::atoi(p.options[Nvalues].arg);
step = (xmax - xmin) / (nvalues - 1);
} else {
fprintf(stderr, "Specifying range requires either -s or -n.\n");
range_error = true;
}
if (nvalues > 0) {
result.reserve(nvalues);
for (int i = 0; i < nvalues; ++i)
result.push_back(xmin + i * step);
}
return result;
};

for (int i = 0; i < p.nonOptionsCount(); ++i) {
const char* name = p.nonOption(i);
gemmi::Element elem = gemmi::find_element(name);
Expand All @@ -45,11 +82,29 @@ int GEMMI_MAIN(int argc, char **argv) {
return -1;
}
std::vector<double> energies;
for (const option::Option* opt = p.options[Energy]; opt; opt = opt->next())
energies.push_back(std::atof(opt->arg));
double xmin, xmax;
for (const option::Option* opt = p.options[Energy]; opt; opt = opt->next()) {
parse_number_or_range(opt->arg, &xmin, &xmax);
if (xmin == xmax) {
energies.push_back(xmin);
} else {
gemmi::vector_move_extend(energies, expand_range(xmin, xmax));
if (range_error)
return -1;
}
}
double hc = gemmi::hc();
for (const option::Option* opt = p.options[Wavelen]; opt; opt = opt->next())
energies.push_back(hc / std::atof(opt->arg));
for (const option::Option* opt = p.options[Wavelen]; opt; opt = opt->next()) {
parse_number_or_range(opt->arg, &xmin, &xmax);
if (xmin == xmax) {
energies.push_back(hc / xmin);
} else {
for (double wavelength : expand_range(xmin, xmax))
energies.push_back(hc / wavelength);
if (range_error)
return -1;
}
}
std::vector<double> fp(energies.size(), 0);
std::vector<double> fpp(energies.size(), 0);
printf("Element\t E[eV]\tWavelength[A]\t f' \t f\"\n");
Expand Down

0 comments on commit ef52e6d

Please sign in to comment.