Commit Graph

287 Commits

Author SHA1 Message Date
Michele Guerini Rocco
3bc1efc2a6
src/minpack.f90: ignore FPE in user-supplied subs
The minimisation algorithm may try to evaluate a function outside of its
domain triggering a floating point exception. However, this is not a
concern because it won't affect the final result, so they can be ignored
2024-02-09 11:16:19 +01:00
Michele Guerini Rocco
3dcacf685c
src/dierckx.f90: fix use of uninitialised var 2024-02-09 11:16:19 +01:00
Michele Guerini Rocco
7c5b443847
src/equilibrium.f90: use enums 2024-02-09 11:16:19 +01:00
Michele Guerini Rocco
fac0c6ded8
src/main.f90: use enums 2024-02-09 11:16:18 +01:00
Michele Guerini Rocco
c5a4b180bc
src/gray_params.f90: replace magic numbers with enums
1. Introduces enumerations (and some booleans) intended to replace all
   the magic numbers used throughout the code to represent multiple
   choices.

2. Replace the gray_params.sh script a new one that automatically
   generates code for all the GRAY parameters by parsing
   gray_params.f90.

3. Also generate extra code to accept the enum identifiers as valid
   values in the configuration files and command line arguments.

4. Set sensible default values for parameters that are rarely changes.
2024-02-09 11:16:18 +01:00
Michele Guerini Rocco
fa89439994
src/ini_parser.f90: handle inline comments and whitespace
While the Fortran read statement will ignore whitespace
and ignored remaining tokens, these are problematic when
manually parsing the INI values.
2024-02-09 11:16:18 +01:00
Michele Guerini Rocco
73bd010458
remove unnecessary implicit statements
Only a single `implicit none` at the start of each module is required.
2024-02-09 11:16:18 +01:00
86ff5ecb06
improve inside and move it to utils.f90
This slightly improves the performance of inside.
For a ~100 points contour the instructions cost is reduced by ~5%.
2024-02-09 11:16:18 +01:00
Michele Guerini Rocco
686f63b01a
fix some gfortran warnings 2024-02-09 11:16:17 +01:00
Michele Guerini Rocco
26976a31dd
src/equilibrium.f90: give the poloidal flux a definition domain
This change limits the evaluation of the poloidal flux spline ψ(R,z) to
a particular domain where ψ(R,z) is strictly monotonic. This choice
ensures that ψ_n < 1 only inside the plasma boundary; so plasma
parameters like q(ψ), Te(ψ), etc. can be mapped to the physical space
without ambiguities.

Before this change, anywhere ψ_n happened to decrease below 1 (either as
a result of a physical current or simply from the spline extrapolation),
Gray would effectively create a spurious plasma region.
This behavior is seriously problematic because it completely invalidates
the simulation: it can alter the ray directions, the power disribution
and total power if the beam enters one such region.

The domain is computed by applying a transformation to the contour of
the plasma boundary: for each contour point we cast a ray from the
magnetic axis to that point and extend the ray until the restriction of
ψ(R,z) on the ray starts decreasing or reach a maximum scaling factor.
The endpoint of the ray is then taken as the new point.
If ψ(R,z) is globally monotonic, the transformation is a homotety wrt
the magnetic axis, so the domain will be an enlarged boundary; otherwise
the shape will be more irregular (an intersection of the enlarged
boundary and several level curves of ψ).

Finally, each `pol_flux(r, z)` call is now guarded behind a check
`inside(psi_domain, r, z)`. For points outside the domain the subroutine
returns, as usual, -1 for ψ and 0 for derivatives.
2024-02-09 11:16:17 +01:00
Michele Guerini Rocco
6fad08ed7c
add tests 2024-02-09 11:16:17 +01:00
Michele Guerini Rocco
ae9f605111
src/gray_core.f90: set initial ray position to z=0
Previously the ray initial positions were set to the wavefront
S_R(x,y,z) = 0, with (x,y) chosen such that S_I(x,y,0) = const.
The wavefront itself, however, was determined using the value of the
beam parameters (k_ξ, k_η, w_ξ, w_η, etc.) fixed at z=0, which is valid
only when the initial wavefront is approximately flat.
Moreover, since the ray are distributed according to S_I(z=0), this
choice creates an inconsistency between the phase (from S_R at z≠0) and
the power (from S_I at z=0) assigned to the rays.

Satisfying both conditions on S_R and S_I exactly is really hard;
however, given we do not really care about the phase and we want to
precisely track the power, so it's more sensible to simply set z=0.

This means that when integrating in the phase (idst=2), gray will no
longer construct wavefronts, but merely transport the initial phase
on the z=0 plane.
Note that k₀⋅s will still give the correct phase. so if necessary, a
wavefront could be reconstructed by interpolating the (s, x̅, y̅, z̅)
points.
2024-01-24 14:37:21 +01:00
Michele Guerini Rocco
9a0f19e9e1
default.nix: update to Nixpkgs 23.05 2024-01-24 14:37:21 +01:00
Michele Guerini Rocco
7417d88d73
Makefile: make use of install portable
install -D on GNU is actually install -d on BSD.
2024-01-24 14:37:21 +01:00
Michele Guerini Rocco
02ade0e2d0
fix static compilation on macOS 2024-01-24 14:37:21 +01:00
Michele Guerini Rocco
d8ffd97739
Makefile: hide warnings when .d missing 2024-01-24 14:37:21 +01:00
Michele Guerini Rocco
b25cdf5f35
Makefile: link gray to libgray
This changes gray to always link to libgray, either statically or dynamically.
2024-01-24 14:37:21 +01:00
Michele Guerini Rocco
af1ed7d1b6
Makefile: fix libgray.a with parallel building
ar does not support multiple builder writing to the same file.
This disable parallel building for .a targets.
See also "Archive Pitfalls" in the GNU Make manual.
2024-01-24 14:37:20 +01:00
Michele Guerini Rocco
c889c754f7
fix partial updates to libgray.a when using Nix
When building the static library the Nixpkgs stdenv `ar` defaults to not
writing timestamps for the members file. This imply make will always try
to add all members to the archive, which defeats the purpose of the
file-level granularity.
2024-01-24 14:37:20 +01:00
Michele Guerini Rocco
95d398d503
src/equilibrium.f90: use the exact toroidal flux
To improve the analytical model correctness this changes the formula
of the toroidal flux to lift the large aspect ratio approximation (a << R₀).
In fact, Φ(r) = B₀πr² is technically inconsistent with the field varying
as B₀R₀/R. The exact expression is:

  Φ(r) = B₀πr² 2/[1 + √(1 - r²/R₀²)],

which is approximately equal to the former for r << R₀.

Note that this change introduces a divergence in the poloidal field at
r=R₀ (since ∂Φ/∂r → +∞), so the domain of the equilibrium has been
restricted to r<R₀, as expected.
This should not be a concern because the field outside the plasma
boundary is never directly, particularly not by the integrator.
2024-01-24 14:37:20 +01:00
Michele Guerini Rocco
9a301f5799
src/equilibrium.f90: re-introduce ρ_t(R,z) mapping
Directly mapping r(R,z) to ρ_p greatly simplifies the implementation of
pol_flux, but also produces a weird current profile and resonance curve.

This keeps the previous changes to the model but reverts the mapping to
the previous one: r → ρ_t.
2024-01-24 14:37:20 +01:00
Michele Guerini Rocco
24edfdc43a
src/gray_core.f90: print_* do not depend on q_spline
This changes all the print_* subroutines to not depend on q_spline,
either for the ψ data points or just their number.
In fact, in the new analytical model q_spline doesn't exist anymore.

Pro: This allows to mark q_spline as private.
2024-01-24 14:37:20 +01:00
Michele Guerini Rocco
8d86d70e91
src/equilibrium.f90: pol_curr return derivative wrt ψ_n 2023-12-12 23:37:56 +01:00
Michele Guerini Rocco
31a7b95fe1
combine equian and equinum_* subroutines
This change combines `equian` and `equinum_psi` into a new `pol_flux`
subroutine that computes ψ(R,z) and derivatives for either numerical or
analytical equilibria.
Similarly, `equian` (the fpol and dfpol outputs) and `equinum_fpol` are
combined intro `pol_curr` that computes F(ψ) and its derivative.

Callers of these subroutines do not select a specific version based on
the value of `iequil` anymore.
2023-12-12 23:37:56 +01:00
Michele Guerini Rocco
98dda6d6fa
src/equilibrium.f90: improve handling of the ψ normalisation
- Hide the implementation of the re-normalisation of the ψ(R,z) spline
  by adjusting the spline coefficients, instead of shifting and
  rescaling after each evaluation.

- Correct the value of `psia` = ψ(X point) - ψ(O point) after the ψ(R,z)
  spline has been re-normalised.

  This fixes another instance of decoupling between the values of X and
  ∇X that introduce a systematic error in the numerical integration of
  the raytracing equations.
  Here the issue is caused by the different normalisations used,
  specifically X=X(ψ_n') and ∇X=∇X(ψ_n), where ψ_n' is the re-normalised
  spline of the normalised flux and ψ_n the spline of the normalised
  flux.

  See d0a5a9f for more details on problems resulting from this error.

- Change `equian` and `equinum_psi` to return the normalised values
  for both the flux and its derivatives, to avoid confusions.
  Callers that needed the unnormalised derivatives now multiply
  explicitly by `psia`.
2023-12-12 23:37:56 +01:00
Michele Guerini Rocco
127d574be7
rework the analytical model
This change modifies the analytical equilibrium in order to simplify the
computation of the poloidal flux normalization and the derivatives.

In the power law parametrisation of the safety factor, ρ_t is replaced
with ρ_p and, similarly, the normalised poloidal radius is now
identified with ρ_p, instead of ρ_t.
With the same parameters (q₀,q₁,α...), this choice slightly changes the
plasma current distribution, but enables us to obtain a closed form for
ψ_a = ψ(r=a) and the relation ρ_t(ρ_p). In fact, both expressions are
now obtained by integrating the q(ρ_p), instead of 1/q(ρ_t), which has
no elementary antiderivative.

As the normalisation is now computed exactly, the values of the
normalised flux ψ_n = ψ/ψ_a and the gradient ∇ψ (entering the raytracing
equations in X and ∇X, respectively) are computed to the same precision.
Previously, ψ_n was computed to a lower precision due to the use of a
simple trapezoid integration of 1/q(ρ_p) for ψ_a, while ∇ψ was computed
up to machine precision using an exact formula.

This error effectively caused a very slight decoupling between X=ω_p²/ω²
and ∇X that introduced a systematic error in the numerical solution of
the raytracing equations.
The error manifests itself as a bias with a weak dependency on X in the
values taken by the dispersion function Λ(r̅, n̅) on the phase-space
points generated by the integrator. More specifically,

  lim h→0 Λ(r̅_i, n̅_i) = -kX(r̅_i)

where h is the integrator step size;
      r̅_i is the position at the i-th step;
      k ≈ -3.258⋅10⁻⁵ and depends only on the number of points used to
        perform the trapedoid integral for ψ_a (as ~ 1/n²).

After this change Λ behaves consistently with being a conserved quantity
(zero) up to the cumulative integration error of the 4° order
Runge-Kutta method. In fact we now have that:

  Λ(r̅_i, n̅_i) ∝ - h⁴ ‖∂⁴X(r̅_i)/∂r̅⁴‖

It must be said that within this model the relation ρ_p(ρ_t) can't be
computed analytically (inverting ρ_t(ρ_p) produces a trascendental
equation of the form b = x + c x^α). However, this relation is not
necessary for raytracing and is easily solved, up to machine
precision, using minpack.

In addition, this change also makes the model consistetly use the
cocos=3 and fully implements the ability to force the signs of I_p, B_φ
(via equilibrium.sgni,sgnb) and rescaling the field (via
equilibrium.factb).
2023-12-12 23:37:43 +01:00
Michele Guerini Rocco
1b814fcb8a
src/main.f90: fix chdir to absolute output path 2023-11-24 11:59:09 +01:00
621c725948 Fix unsafe use of merge and missing igrad override 2023-10-20 15:19:56 +02:00
e3656e8bdd Fix debug/optimization flags 2023-10-20 13:42:06 +02:00
7d9f43e1af Remove tolerance when searching ray-wall intersections 2023-10-05 16:37:56 +02:00
cf8a37fec9 Fix label for Icd units in log output 2023-10-04 16:56:05 +02:00
526195ca94 Fix input files documentation 2023-09-22 15:55:29 +02:00
Michele Guerini Rocco
2fed2ab5ec
src/gray_core.f90: remove unused variables in rhs 2023-09-21 14:21:25 +02:00
Michele Guerini Rocco
f75cedbf2b
src/gray_params.f90: fix comment 2023-09-21 14:21:25 +02:00
Michele Guerini Rocco
8bc5ac0064
always use generic math functions
This replaces double precision-specific function in order to allow
building GRAY with other real kinds, for example single or quadruple
precision.
2023-09-21 14:21:24 +02:00
Michele Guerini Rocco
dcc832ce65
fix simple limiter in analytic equilibrium
In the case of analytic equilibrium without a limiter contour, the
simple limiter was built incorrectly due to an unnecessary conversion
from cm (the equilibrium data are already in metre).
2023-09-20 16:15:41 +02:00
Michele Guerini Rocco
61605d3478
fix density calculation in analytical mode
In the analytical mode the density does not have a tail, so tail%end is
not initialised. The density is exactly zero at ψ≥1.
2023-09-20 16:14:22 +02:00
Michele Guerini Rocco
f5a983f926
src/ini_parser.f90: open file for reading 2023-09-20 16:14:22 +02:00
Michele Guerini Rocco
59dfcb7799
src/gray_cli.f90: allow enabling or disabling all units 2023-09-20 16:14:21 +02:00
Michele Guerini Rocco
8425e5e286
src/gray_cli.f90: simplify argument handling 2023-09-20 16:14:21 +02:00
Michele Guerini Rocco
a27e56933c
src/main.f90: give priority to cli over beamdata.txt 2023-09-20 16:14:21 +02:00
Michele Guerini Rocco
62c3045a7f
src/ini_parser.f90: avoid procedure pointer
In this case a normal procedure dummy argument works as well.
2023-09-20 16:14:21 +02:00
Michele Guerini Rocco
69367ae981
src/gray_core.f90: print profiles up to ψ_bnd 2023-09-20 16:14:20 +02:00
Michele Guerini Rocco
707dca1ab8
src/coreprofiles.f90: add some debug output 2023-09-14 11:26:57 +02:00
Michele Guerini Rocco
7ed76959d4
call exit on errors only in main 2023-09-14 11:26:56 +02:00
Michele Guerini Rocco
daf3d500af
use linear interpolation for monotonic data
The ρ_p/ρ_t mapping is 1:1, so the interpolation must always preserve
monotonicity, of which cubic splines generally make no guarantee.

Note: Linear interpolation does not provide even C¹ continuity, but
these data is not directly used in the numerical integration, so it
should be fine. Ideally this should be replaced with cubic splines
computed with the Fritsch–Carlson algorithm.
2023-09-14 11:26:56 +02:00
Michele Guerini Rocco
9bcad028b1
improve error handling in the gray_main routine
- rename errocodes → gray_errors

- restructure the errors into a `error_spec` type

- make the list of errors easily extensible

- rewrite the `print_errn`, `print_errhcd` (now `print_err_raytracing`,
  `print_err_ecrh_cd`) subroutine to handle arbitrary errors

- add functions to easily manipulate errors
  (`raise_error`, `has_error`, `is_critical`)

- remove print statements from quadpack

- log all errors to stderr using the logger module
2023-05-11 17:47:13 +02:00
Michele Guerini Rocco
78d8bdbb33
src/coreprofiles.f90: exit on density fit errors 2023-05-11 17:47:05 +02:00
Michele Guerini Rocco
b1accf0ae3
simplify handling of splines
This adds a new `splines` module which implements a high-level interface
for creating and evaluating splines and rewrite almost all modules to
use it. Also, notably:

1. both `simplespline` and DIERCKX splines can now used with a uniform
   interface

2. most complexity due to handling working space arrays is gone

3. memory management has been significantly simplified too
2023-04-12 23:45:49 +02:00
Michele Guerini Rocco
1261860f40
add some useful debug messages 2023-04-12 23:45:49 +02:00