-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathparam.c
2707 lines (2606 loc) · 115 KB
/
param.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Initialization, parsing and handling of input parameters; also printout general information;
* contains file locking routines
*
* Copyright (C) ADDA contributors
* This file is part of ADDA.
*
* ADDA is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* ADDA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with ADDA. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "const.h" // keep this first
#include "param.h" // corresponding header
// project headers
#include "cmplx.h"
#include "comm.h"
#include "crosssec.h"
#include "debug.h"
#include "fft.h"
#include "function.h"
#include "io.h"
#include "oclcore.h"
#include "os.h"
#include "parbas.h"
#include "vars.h"
// system headers
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef CLFFT
/* One can also include clFFT.h (the only recommended public header), which can be redundant, but more portable.
* However, version macros are not documented anyway (in the manual), so there seem to be no perfectly portable way to
* obtain them.
*/
# include <clFFT.version.h>
#endif
#ifdef OCL_BLAS
/* In contrast to clFFT, here including main header (clBLAS.h) is not an option, since it doesn't include the
* following header.
*/
# include <clBLAS.version.h>
#endif
#ifdef WINDOWS
# include <windows.h> // all windows functions need this
# include <io.h> // for _isatty
#endif
#ifndef NO_GITHASH
# include "githash.h" // for GITHASH, this file is automatically created during compilation
#endif
// definitions for file locking
#ifdef USE_LOCK
# ifdef WINDOWS
# define FILEHANDLE HANDLE
# elif defined(POSIX)
# include <unistd.h>
# include <fcntl.h>
# ifdef LOCK_FOR_NFS
# include <errno.h> // for error handling of fcntl call
# endif
# define FILEHANDLE int
# else
# error "Unknown operation system. Creation of lock files is not supported."
# endif
# define LOCK_WAIT 1 // in seconds
# define MAX_LOCK_WAIT_CYCLES 60
# define ONLY_FOR_LOCK
#else
# define FILEHANDLE int
# define ONLY_FOR_LOCK ATT_UNUSED
#endif
// GLOBAL VARIABLES
opt_index opt; // main option index; it is also defined as extern in param.h
#ifdef WINDOWS
bool emulLinebuf; // whether to emulate line buffering of stdout, defined as extern in io.h
#endif
// SEMI-GLOBAL VARIABLES
// defined and initialized in crosssec.c
extern const char *avg_string;
// defined and initialized in GenerateB.c
extern const char *beam_descr;
extern const double prIncRefl[3],prIncTran[3];
// defined and initialized in make_particle.c
extern const bool volcor_used;
extern const char *sh_form_str1,*sh_form_str2;
#ifndef SPARSE
extern const int gr_N;
extern const double gr_vf_real;
#endif //SPARSE
extern const size_t mat_count[];
// used in CalculateE.c
bool store_int_field; // save full internal fields to text file
bool store_dip_pol; // save dipole polarizations to text file
bool store_beam; // save incident beam to file
bool store_scat_grid; // Store the scattered field for grid of angles
bool calc_Cext; // Calculate the extinction cross-section - always do
bool calc_Cabs; // Calculate the absorption cross-section - always do
bool calc_Csca; // Calculate the scattering cross-section by integration
bool calc_vec; // Calculate the unnormalized asymmetry-parameter
bool calc_asym; // Calculate the asymmetry-parameter
bool calc_mat_force; // Calculate the scattering force by matrix-evaluation
bool store_force; // Write radiation pressure per dipole to file
bool store_ampl; // Write amplitude matrix to file
int phi_int_type; // type of phi integration (each bit determines whether to calculate with different multipliers)
// used in calculator.c
bool avg_inc_pol; // whether to average CC over incident polarization
double polNlocRp; // Gaussian width for non-local polarizability
const char *alldir_parms; // name of file with alldir parameters
const char *scat_grid_parms; // name of file with parameters of scattering grid
// used in crosssec.c
double incPolX_0[3],incPolY_0[3]; // initial incident polarizations (in lab RF)
enum scat ScatRelation; // type of formulae for scattering quantities
// used in GenerateB.c
int beam_Npars;
double beam_pars[MAX_N_BEAM_PARMS]; // beam parameters
opt_index opt_beam; // option index of beam option used
const char *beam_fnameY; // names of files, defining the beam (for two polarizations)
const char *beam_fnameX;
// used in interaction.c
double igt_lim; // limit (threshold) for integration in IGT
double igt_eps; // relative error of integration in IGT
double nloc_Rp; // Gaussian width for non-local interaction
bool InteractionRealArgs; // whether interaction (or reflection) routines can be called with real arguments
// used in io.c
char logfname[MAX_FNAME]=""; // name of logfile
// used in iterative.c
double iter_eps; // relative error to reach
enum init_field InitField; // how to calculate initial field for the iterative solver
const char *infi_fnameY; // names of files, defining the initial field (for two polarizations)
const char *infi_fnameX;
bool recalc_resid; // whether to recalculate residual at the end of iterative solver
enum chpoint chp_type; // type of checkpoint (to save)
time_t chp_time; // time of checkpoint (in sec)
char const *chp_dir; // directory name to save/load checkpoint
// used in make_particle.c
enum sh shape; // particle shape definition
int sh_Npars; // number of shape parameters
double sh_pars[MAX_N_SH_PARMS]; // storage for shape parameters
double sizeX; // size of particle along x-axis
double dpl; // number of dipoles per lambda (wavelength)
double lambda; // incident wavelength (in vacuum)
int jagged; // size of big dipoles, used to construct a particle
const char *shape_fname; // name of file, defining the shape
const char *save_geom_fname; // geometry file name to save dipole configuration
const char *shapename; // name of the used shape
bool volcor; // whether to use volume correction
bool save_geom; // whether to save dipole configuration in .geom file
opt_index opt_sh; // option index of shape option used
double gr_vf; // granules volume fraction
double gr_d; // granules diameter
int gr_mat; // domain number to granulate
double a_eq; // volume-equivalent radius of the particle
enum shform sg_format; // format for saving geometry files
bool store_grans; // whether to save granule positions to file
// LOCAL VARIABLES
#define GFORM_RI_DIRNAME "%.4g" // format for refractive index in directory name
static const char *run_name; // first part of the dir name ('run' or 'test')
static const char *avg_parms; // name of file with orientation averaging parameters
static const char *exename; // name of executable (adda, adda.exe, adda_mpi,...)
static int Nmat_given; // number of refractive indices given in the command line
static enum sym sym_type; // how to treat particle symmetries
static int sobuf; // mode for stdout buffering
/* The following '..._used' flags are, in principle, redundant, since the structure 'options' contains the same flags.
* However, the latter can't be easily addressed by the option name (a search over the whole options is required).
* When thinking about adding a new one, first consider using UNDEF machinery instead
*/
static bool prop_used; // whether '-prop ...' was used in the command line
static bool orient_used; // whether '-orient ...' was used in the command line
static bool yz_used; // whether '-yz ...' was used in the command line
static bool scat_plane_used; // whether '-scat_plane ...' was used in the command line
static bool so_buf_used; // whether '-so_buf ...' was used in the command line
static bool beam_center_used; // whether '-beam_center ...' was used in the command line
static bool deprecated_bc_used; // whether '-beam ... <x> <y> <z>' was used in the command line (deprecated option)
/* TO ADD NEW COMMAND LINE OPTION
* If you need new variables or flags to implement effect of the new command line option, define them here. If a
* variable is used only in this source file, define it as local (static). If it is used in one another file, define
* them as semi-global, i.e. define them here under corresponding 'used in ...' line and put 'extern' declaration in
* corresponding source file under 'defined and initialized in param.c' line. If it is used in this and two or more
* files, define it as global, by putting definition in vars.c and 'extern' declaration in vars.h.
*/
// structure definitions
struct subopt_struct {
const char *name; // name of option
const char *usage; // how to use (argument list)
const char *help; // help string
const int narg; /* possible number of arguments; UNDEF -> should not be checked; may contain also some special
negative codes, like FNAME_ARG. Currently it is assumed that all arguments are float (if no
special argument is specified), but it can be changed if will become a limitation. */
const int type; // type of suboption
};
struct opt_struct {
const char *name; // name of option
void (*func)(int Narg,char **argv); // pointer to a function, parsing this parameter
bool used; // flag to indicate, if the option was already used
const char *usage; // how to use (argument list)
const char *help; // help string
const int narg; // possible number of arguments; UNDEF -> should not be checked
const struct subopt_struct *sub; // suboptions
};
// const string for usage of ADDA
static const char exeusage[]="[-<opt1> [<args1>] [-<opt2> <args2>]...]]";
/* initializations of suboptions (comments to elements of subopt_struct are above); Contrary to 'options', suboptions
* are defined as null-terminated array, because they may be referenced not directly by their names but also as
* options[i].sub. In the latter case macro LENGTH can't be used to estimate the length of the array. So getting this
* length is at least nontrivial (e.g. can be done with some intermediate variables). So using NULL-termination seems
* to be the easiest.
*/
static const struct subopt_struct beam_opt[]={
{"barton5","<width> [<x> <y> <z>]","5th order approximation of the Gaussian beam (by Barton). The beam width is "
"obligatory and x, y, z coordinates of the center of the beam (in laboratory reference frame) are optional "
"(zero, by default). All arguments are in um. This is recommended option for simulation of the Gaussian beam. "
"Specification of coordinates here is DEPRECATED, use -beam_center instead.",UNDEF,B_BARTON5},
#ifndef NO_FORTRAN
{"besselCS","<order> <angle>","Bessel beam with circularly symmetric energy density. Order is integer (of any "
"sign) and the half-cone angle (in degrees) is measured from the z-axis.",2,B_BES_CS},
{"besselCSp","<order> <angle>","Alternative Bessel beam with circularly symmetric energy density. Order is "
"integer (of any sign) and the half-cone angle (in degrees) is measured from the z-axis.",2,B_BES_CSp},
{"besselM","<order> <angle> <ReMex> <ReMey> <ReMmx> <ReMmy> [<ImMex> <ImMey> <ImMmx> <ImMmy>]",
"Generalized Bessel beam. Order is integer (of any sign) and the half-cone angle (in degrees) is measured from "
"the z-axis. The beam is defined by 2x2 matrix M: (Mex, Mey, Mmx, Mmy). Real parts of these four elements are "
"obligatory, while imaginary parts are optional (zero, by default).",UNDEF,B_BES_M},
{"besselLE","<order> <angle>","Bessel beam with linearly polarized electric field. Order is integer (of any sign) "
"and the half-cone angle (in degrees) is measured from the z-axis.",2,B_BES_LE},
{"besselLM","<order> <angle>","Bessel beam with linearly polarized magnetic field. Order is integer (of any sign) "
"and the half-cone angle (in degrees) is measured from the z-axis.",2,B_BES_LM},
{"besselTEL","<order> <angle>","Linear component of the TE Bessel beam. Order is integer (of any sign) and the "
"half-cone angle (in degrees) is measured from the z-axis.",2,B_BES_TEL},
{"besselTML","<order> <angle>","Linear component of the TM Bessel beam. Order is integer (of any sign) and the "
"half-cone angle (in degrees) is measured from the z-axis.",2,B_BES_TML},
#endif // !NO_FORTRAN
{"davis3","<width> [<x> <y> <z>]","3rd order approximation of the Gaussian beam (by Davis). The beam width is "
"obligatory and x, y, z coordinates of the center of the beam (in laboratory reference frame) are optional "
"(zero, by default). All arguments are in um. Specification of coordinates here is DEPRECATED, use "
"-beam_center instead.",UNDEF,B_DAVIS3},
{"dipole","[<x> <y> <z>]","Field of a unit point dipole placed at x, y, z coordinates (in laboratory reference "
"frame). All arguments are in um. Orientation of the dipole is determined by -prop command line option."
"Implies '-scat_matr none'. If '-surf' is used, dipole position should be above the surface. Specification of "
"coordinates here is DEPRECATED, use -beam_center instead.",UNDEF,B_DIPOLE},
{"lminus","<width> [<x> <y> <z>]","Simplest approximation of the Gaussian beam. The beam width is obligatory and "
"x, y, z coordinates of the center of the beam (in laboratory reference frame) are optional (zero, by"
" default). All arguments are in um. Specification of coordinates here is DEPRECATED, use -beam_center "
"instead.",UNDEF,B_LMINUS},
{"plane","","Infinite plane wave",0,B_PLANE},
{"read","<filenameY> [<filenameX>]","Defined by separate files, which names are given as arguments. Normally two "
"files are required for Y- and X-polarizations respectively, but a single filename is sufficient if only "
"Y-polarization is used (e.g. due to symmetry). Incident field should be specified in a particle reference "
"frame in the same format as used by '-store_beam'.",FNAME_ARG_1_2,B_READ},
/* TO ADD NEW BEAM
* add a row to this list in alphabetical order. It contains: beam name (used in command line), usage string, help
* string, possible number of float parameters, beam identifier (defined inside 'enum beam' in const.h). Usage and
* help string are shown either when -h option is invoked or error is found in input command line. Usage string is
* one line giving a list of possible arguments or argument combinations. Do not include beam name in it, use
* <arg_name> to denote argument, [...] for optional arguments, and {...|...|...} for multiple options of an
* argument. Help string should contain general description of the beam type and its arguments. Instead of number
* of parameters UNDEF can be used (if beam can accept variable number of parameters, then check it explicitly in
* function PARSE_FUNC(beam) below) or one of FNAME_ARG family (see explanation in const.h) if beam accepts a
* filenames as arguments. Number of parameters should not be greater than MAX_N_BEAM_PARMS (defined in const.h).
*/
{NULL,NULL,NULL,0,0}
};
static const struct subopt_struct shape_opt[]={
#ifndef SPARSE
{"axisymmetric","<filename>","Axisymmetric homogeneous shape, defined by its contour in ro-z plane of the "
"cylindrical coordinate system. Its symmetry axis coincides with the z-axis, and the contour is read from "
"file.",FNAME_ARG,SH_AXISYMMETRIC},
{"bicoated","<R_cc/d> <d_in/d>","Two identical concentric coated spheres with outer diameter d (first domain), "
"inner diameter d_in, and center-to-center distance R_cc (along the z-axis). It describes both separate and "
"sintered coated spheres. In the latter case sintering is considered symmetrically for cores and shells.",
2,SH_BICOATED},
{"biellipsoid","<y1/x1> <z1/x1> <x2/x1> <y2/x2> <z2/x2>","Two general ellipsoids in default orientations with "
"centers on the z-axis, touching each other. Their semi-axes are x1,y1,z1 (lower one, first domain) and "
"x2,y2,z2 (upper one, second domain).",5,SH_BIELLIPSOID},
{"bisphere","<R_cc/d> ","Two identical spheres with diameter d and center-to-center distance R_cc (along the "
"z-axis). It describe both separate and sintered spheres.",1,SH_BISPHERE},
{"box","[<y/x> <z/x>]","Homogeneous cube (if no arguments are given) or a rectangular parallelepiped with edges "
"x,y,z.",UNDEF,SH_BOX},
{"capsule","<h/d>","Homogeneous capsule (cylinder with half-spherical end caps) with cylinder height h and "
"diameter d (its axis of symmetry coincides with the z-axis).",1,SH_CAPSULE},
{"chebyshev","<eps> <n>","Axisymmetric Chebyshev particle of amplitude eps and order n, r=r_0[1+eps*cos(n*theta)]. "
"eps is a real number, such that |eps|<=1, while n is a natural number",2,SH_CHEBYSHEV},
{"coated","<d_in/d> [<x/d> <y/d> <z/d>]","Sphere with a spherical inclusion; outer sphere has a diameter d (first "
"domain). The included sphere has a diameter d_in (optional position of the center: x,y,z).",UNDEF,SH_COATED},
{"coated2","<ds/d> <dc/d>","Three concentric spheres (core with 2 shells). Outer sphere has a diameter d (first "
"domain), intermediate sphere (shell) - ds (second domain), and the internal core - dc (third domain). This "
"shape is DEPRECATED, use 'onion' instead.",2,SH_COATED2},
{"cylinder","<h/d>","Homogeneous cylinder with height (length) h and diameter d (its axis of symmetry coincides "
"with the z-axis).",1,SH_CYLINDER},
{"egg","<eps> <nu>","Axisymmetric egg shape given by a^2=r^2+nu*r*z-(1-eps)z^2, where 'a' is scaling factor. "
"Parameters must satisfy 0<eps<=1, 0<=nu<eps.",2,SH_EGG},
{"ellipsoid","<y/x> <z/x>","Homogeneous general ellipsoid with semi-axes x,y,z",2,SH_ELLIPSOID},
{"line","","Line along the x-axis with the width of one dipole",0,SH_LINE},
{"onion","<d2/d> [<d3/d> ... <dn/d>]","Multilayered concentric sphere (core with arbitrary number of shells). "
"n is the total number of particle domains, corresponding to a core with n-1 shells. Outer shell is between "
"the spheres of diameters d and d2 (first domain), next one - between d2 and d3 (second domain), etc., down to "
"the core with diameter dn (n-th domain). Maximum number of domains is " TO_STRING(MAX_NMAT) " (controlled by "
"the parameter MAX_NMAT in const.h).",
UNDEF,SH_ONION},
{"onion_ell","<y/x> <z/x> <x2/x> [<x3/x> ... <xn/x>]","Multilayered concentric ellipsoid (core with arbitrary "
"number of shells) with semi-axes x,y,z. Outer shell is between the ellipsoids with semi-axes (along the "
"x-axis) x and x2 (first domain), next one - between x2 and x3 (second domain), etc., down to the core with "
"semi-axis xn (n-th domain). Maximum number of domains is " TO_STRING(MAX_NMAT) " (controlled by the parameter "
"MAX_NMAT in const.h).",UNDEF,SH_ONION_ELL},
{"plate", "<h/d>","Homogeneous plate (cylinder with rounded side) with cylinder height h and full diameter d (i.e. "
"diameter of the constituent cylinder is d-h). Its axis of symmetry coincides with the z-axis.",1,SH_PLATE},
{"prism","<n> <h/Dx>","Homogeneous right prism with height (length along the z-axis) h based on a regular polygon "
"with n sides of size 'a'. The polygon is oriented so that positive x-axis is a middle perpendicular for one "
"of its sides. Dx is size of the polygon along the x-axis, equal to 2Ri and Rc+Ri for even and odd n "
"respectively. Rc=a/[2sin(pi/n)] and Ri=Rc*cos(pi/n) are radii of circumscribed and inscribed circles "
"respectively.",2,SH_PRISM},
{"rbc","<h/d> <b/d> <c/d>","Red Blood Cell, an axisymmetric (over z-axis) biconcave homogeneous particle, which is "
"characterized by diameter d, maximum and minimum width h, b, and diameter at the position of the maximum "
"width c. The surface is described by ro^4+2S*ro^2*z^2+z^4+P*ro^2+Q*z^2+R=0, ro^2=x^2+y^2, P,Q,R,S are "
"determined by the described parameters.",3,SH_RBC},
#endif // !SPARSE
{"read","<filename>","Read a particle geometry from file <filename>",FNAME_ARG,SH_READ},
#ifndef SPARSE
{"sphere","","Homogeneous sphere",0,SH_SPHERE},
{"spherebox","<d_sph/Dx>","Sphere (diameter d_sph) in a cube (size Dx, first domain)",1,SH_SPHEREBOX},
{"superellipsoid","<b/a> <c/a> <e> <n>","Homogeneous superellipsoid with semi-axes a, b, c along the x, y, and z "
"directions, respectively. Nonnegative e and n control the shape of cross sections parallel and perpendicular "
"to the xy-plane, respectively, according to [(x/a)^(2/e) + (y/b)^(2/e)]^(e/n) + (z/c)^(2/n) <= 1. Large "
"values of e and/or n lead to spiky shapes with potential discretization problems.",4,SH_SUPERELLIPSOID},
#endif // !SPARSE
/* TO ADD NEW SHAPE
* add a row to this list in alphabetical order. It contains: shape name (used in command line), usage string, help
* string, possible number of float parameters, shape identifier (defined inside 'enum sh' in const.h). Usage and
* help string are shown either when -h option is invoked or error is found in input command line. Usage string is
* one line giving a list of possible arguments or argument combinations. Do not include shape name in it, use
* <arg_name> to denote argument, [...] for optional arguments, and {...|...|...} for multiple options of an
* argument. Help string should contain general description of the shape and its arguments. Instead of number of
* parameters UNDEF can be used (if shape can accept variable number of parameters, then check it explicitly in
* function PARSE_FUNC(shape) below) or FNAME_ARG (if the shape accepts a single string argument with file name).
* Number of parameters should not be greater than MAX_N_SH_PARMS (defined in const.h). It is recommended to use
* dimensionless shape parameters, e.g. aspect ratios.
*/
{NULL,NULL,NULL,0,0}
};
/* TO ADD NEW COMMAND LINE OPTION
* If a new option requires separate description of suboptions, add a static structure here (similar to already existing
* ones). It should contain a number of rows corresponding to different suboptions (see definition of subopt_struct
* above for details) and terminate with a NULL row.
*/
// EXTERNAL FUNCTIONS
// GenerateB.c
void InitBeam(void);
//======================================================================================================================
/* Prototypes of parsing functions; definitions are given below. defines are for conciseness. Since we use one common
* prototype style for all parsing functions and many of the latter do not actually use the passed parameters, these
* parameters have 'unused' attribute to eliminate spurious warnings.
*/
#define PARSE_NAME(a) parse_##a
#define PARSE_FUNC(a) static void PARSE_NAME(a)(int Narg ATT_UNUSED,char **argv ATT_UNUSED)
#define PAR(a) #a,PARSE_NAME(a),false
PARSE_FUNC(alldir_inp);
PARSE_FUNC(anisotr);
PARSE_FUNC(asym);
PARSE_FUNC(beam);
PARSE_FUNC(beam_center);
PARSE_FUNC(chp_dir);
PARSE_FUNC(chp_load);
PARSE_FUNC(chp_type);
PARSE_FUNC(chpoint);
PARSE_FUNC(Cpr);
PARSE_FUNC(Csca);
PARSE_FUNC(dir);
PARSE_FUNC(dpl);
PARSE_FUNC(eps);
PARSE_FUNC(eq_rad);
#ifdef OPENCL
PARSE_FUNC(gpu);
#endif
#ifndef SPARSE
PARSE_FUNC(granul);
#endif
PARSE_FUNC(grid);
PARSE_FUNC(h) ATT_NORETURN;
PARSE_FUNC(init_field);
PARSE_FUNC(int);
PARSE_FUNC(int_surf);
PARSE_FUNC(iter);
PARSE_FUNC(jagged);
PARSE_FUNC(lambda);
PARSE_FUNC(m);
PARSE_FUNC(maxiter);
PARSE_FUNC(no_reduced_fft);
PARSE_FUNC(no_vol_cor);
PARSE_FUNC(ntheta);
PARSE_FUNC(opt);
PARSE_FUNC(orient);
PARSE_FUNC(phi_integr);
PARSE_FUNC(pol);
PARSE_FUNC(prognosis);
PARSE_FUNC(prop);
PARSE_FUNC(recalc_resid);
PARSE_FUNC(rect_dip);
#ifndef SPARSE
PARSE_FUNC(save_geom);
#endif
PARSE_FUNC(scat);
PARSE_FUNC(scat_grid_inp);
PARSE_FUNC(scat_matr);
PARSE_FUNC(scat_plane);
#ifndef SPARSE
PARSE_FUNC(sg_format);
#endif
PARSE_FUNC(shape);
PARSE_FUNC(size);
PARSE_FUNC(so_buf);
PARSE_FUNC(store_beam);
PARSE_FUNC(store_dip_pol);
PARSE_FUNC(store_force);
#ifndef SPARSE
PARSE_FUNC(store_grans);
#endif
PARSE_FUNC(store_int_field);
PARSE_FUNC(store_scat_grid);
PARSE_FUNC(surf);
PARSE_FUNC(sym);
PARSE_FUNC(test);
PARSE_FUNC(V) ATT_NORETURN;
PARSE_FUNC(vec);
PARSE_FUNC(yz);
/* TO ADD NEW COMMAND LINE OPTION
* add a function prototype to this list. Add a line 'PARSE_FUNC(option_name);' in alphabetical order. It will be
* expanded automatically using defines specified above.
*/
static struct opt_struct options[]={
{PAR(alldir_inp),"<filename>","Specifies a file with parameters of the grid of scattering angles for calculating "
"integral scattering quantities.\n"
"Default: "FD_ALLDIR_PARMS,1,NULL},
{PAR(anisotr),"","Specifies that refractive index is anisotropic (its tensor is limited to be diagonal in particle "
"reference frame). '-m' then accepts 6 arguments per each domain. Can not be used with '-pol cldr' and "
"'-rect_dip'.",0,NULL},
{PAR(asym),"","Calculate the asymmetry vector. Implies '-Csca' and '-vec'",0,NULL},
{PAR(beam),"<type> [<args>]","Sets the incident beam, either predefined or 'read' from file. All parameters of "
"predefined beam types are floats except for <order> or filenames.\n"
"Default: plane",UNDEF,beam_opt},
{PAR(beam_center),"<x> <y> <z>","Sets the center of the beam in the laboratory reference frame (in um). For most "
"beams it corresponds to the most symmetric point with zero phase, while for a point source or a fast "
"electron, it determines the real position in space.\n"
"Default: 0 0 0",3,NULL},
{PAR(chp_dir),"<dirname>","Sets directory for the checkpoint (both for saving and loading).\n"
"Default: "FD_CHP_DIR,1,NULL},
{PAR(chp_load),"","Restart a simulation from a checkpoint",0,NULL},
{PAR(chp_type),"{normal|regular|always}",
"Sets type of the checkpoint. All types, except 'always', require '-chpoint'.\n"
"Default: normal",1,NULL},
{PAR(chpoint),"<time>","Specifies the time for checkpoints in format '#d#h#m#s'. All fields are optional, numbers "
"are integers, 's' can be omitted, the format is not case sensitive.\n"
"Examples: 12h30M, 1D10s, 3600",1,NULL},
{PAR(Cpr),"","Calculate the total radiation force, expressed as cross section.",0,NULL},
{PAR(Csca),"","Calculate scattering cross section (by integrating the scattered field)",0,NULL},
{PAR(dir),"<dirname>","Sets directory for output files.\n"
"Default: constructed automatically",1,NULL},
{PAR(dpl),"<arg>","Sets parameter 'dipoles per lambda', float.\n"
"Default: 10|m|, where |m| is the maximum of all given refractive indices.",1,NULL},
{PAR(eps),"<arg>","Specifies the stopping criterion for the iterative solver by setting the relative norm of the "
"residual 'epsilon' to reach. <arg> is an exponent of base 10 (float), i.e. epsilon=10^(-<arg>).\n"
"Default: 5 (epsilon=1E-5)",1,NULL},
{PAR(eq_rad),"<arg>","Sets volume-equivalent radius of the particle in um, float. If default wavelength is used, "
"this option specifies the volume-equivalent size parameter. Can not be used together with '-size'. Size is "
"defined by some shapes themselves, then this option can be used to override the internal specification and "
"scale the shape.\n"
"Default: determined by the value of '-size' or by '-grid', '-dpl', '-lambda', and '-rect_dip'.",1,NULL},
#ifdef OPENCL
{PAR(gpu),"<index>","Specifies index of GPU that should be used (starting from 0). Relevant only for OpenCL "
"version of ADDA, running on a system with several GPUs.\n"
"Default: 0",1,NULL},
#endif
#ifndef SPARSE
{PAR(granul),"<vol_frac> <diam> [<dom_number>]","Specifies that one particle domain should be randomly filled with "
"spherical granules with specified diameter <diam> and volume fraction <vol_frac>. Domain number to fill is "
"given by the last optional argument. Algorithm may fail for volume fractions > 30-50%. Cannot be used with "
"'-rect_dip'.\n"
"Default <dom_number>: 1",UNDEF,NULL},
#endif // !SPARSE
{PAR(grid),"<nx> [<ny> <nz>]","Sets dimensions of the computation grid (any positive integers). In most "
"cases <ny> and <nz> can be omitted (they are automatically determined by <nx> based on the proportions of the "
"scatterer). This command line option is not relevant when particle geometry is read from a file ('-shape "
"read'). If '-jagged' option is used the grid dimension is effectively multiplied by the specified number.\n"
"Default: 16 (if neither '-size' nor '-eq_rad' are specified) or defined by\n"
" '-size' or '-eq_rad', '-lambda', '-dpl', and '-rect_dip'.",UNDEF,NULL},
{PAR(h),"[<opt> [<subopt>]]","Shows help. If used without arguments, ADDA shows a list of all available command "
"line options. If first argument is specified, help on specific command line option <opt> is shown (only the "
"name of the option should be given without preceding dash). For some options (e.g. '-beam' or '-shape') "
"specific help on a particular suboption <subopt> may be shown.\n"
"Example: shape coated",UNDEF,NULL},
{PAR(init_field),"{auto|inc|read <filenameY> [<filenameX>]|wkb|zero}",
"Sets prescription to calculate initial (starting) field for the iterative solver.\n"
"'auto' - automatically choose from 'zero' and 'inc' based on the lower residual value.\n"
"'inc' - derived from the incident field,\n"
"'read' - defined by separate files, which names are given as arguments. Normally two files are required for "
"Y- and X-polarizations respectively, but a single filename is sufficient if only Y-polarization is used (e.g. "
"due to symmetry). Initial field should be specified in a particle reference frame in the same format as used "
"by '-store_int_field',\n"
"'wkb' - from Wentzel-Kramers-Brillouin approximation,\n"
#ifdef SPARSE
"!!! 'wkb' is not operational in sparse mode\n"
#endif
"'zero' is a zero vector,\n"
"Default: auto",UNDEF,NULL},
{PAR(int),"{fcd|fcd_st|igt [<lim> [<prec>]]|igt_so|nloc <Rp>|nloc_av <Rp>|poi}",
"Sets prescription to calculate the interaction term.\n"
"'fcd' - Filtered Coupled Dipoles - requires dpl to be larger than 2.\n"
"'fcd_st' - static (long-wavelength limit) version of FCD.\n"
"'igt' - Integration of Green's Tensor. Its parameters are: <lim> - maximum distance (in units of the largest "
"dipole size), for which integration is used, (default: infinity); <prec> - minus decimal logarithm of "
"relative error of the integration, i.e. epsilon=10^(-<prec>) (default: the same as the argument (or default "
"value) of '-eps' command line option).\n"
#ifdef NO_FORTRAN
"!!! 'igt' relies on Fortran sources that were disabled at compile time.\n"
#endif
"'igt_so' - second-order approximate evaluation of IGT.\n"
"'nloc' - non-local interaction of two Gaussian dipole densities (based on point value of Gh), <Rp> is the "
"width of the latter in um (must be non-negative).\n"
"'nloc_av' - same as 'nloc' but based on averaging over the cube volume.\n"
"'poi' - (the simplest) interaction between point dipoles.\n"
#ifdef SPARSE
"!!! All options except 'poi' incur a significant slowing down in sparse mode.\n"
#endif
"Only poi, igt, and igt_so can be used with '-rect_dip'.\n"
"Default: poi",UNDEF,NULL},
/* TO ADD NEW INTERACTION FORMULATION
* Modify string constants after 'PAR(int)': add new argument (possibly with additional sub-arguments) to list
* {...} and its description to the next string. If the new interaction formulation requires unusually large
* computational time, add a special note for sparse mode (after '#ifdef SPARSE').
*/
{PAR(int_surf),"{img|som}",
"Sets prescription to calculate the reflection term.\n"
"'img' - approximation based on a single image dipole (fast but inaccurate).\n"
"'som' - direct evaluation of Sommerfeld integrals.\n"
#ifdef SPARSE
"!!! In sparse mode 'som' is expected to be very slow.\n"
#endif
"Default: som (but 'img' if surface is perfectly reflecting)",1,NULL},
/* TO ADD NEW REFLECTION FORMULATION
* Modify string constants after 'PAR(int_surf)': add new argument (possibly with additional sub-arguments) to
* list {...} and its description to the next string. If the new reflection formulation requires unusually
* large computational time, add a special note for sparse mode (after '#ifdef SPARSE').
* !!! If subarguments are added, second-to-last argument should be changed from 1 to UNDEF, and consistency
* test for number of arguments should be implemented in PARSE_FUNC(int_surf) below.
*/
{PAR(iter),"{bcgs2|bicg|bicgstab|cgnr|csym|qmr|qmr2}","Sets the iterative solver.\n"
"Default: qmr",1,NULL},
/* TO ADD NEW ITERATIVE SOLVER
* add the short name, used to define the new iterative solver in the command line, to the list "{...}" in the
* alphabetical order.
*/
{PAR(jagged),"<arg>","Sets a size of a big dipole in units of small dipoles, integer. It is used to improve the "
"discretization of the particle without changing the shape.\n"
"Default: 1",1,NULL},
{PAR(lambda),"<arg>","Sets incident wavelength in um, float.\n"
"Default: 2*pi",1,NULL},
{PAR(m),"{<m1Re> <m1Im> [...]|<m1xxRe> <m1xxIm> <m1yyRe> <m1yyIm> <m1zzRe> <m1zzIm> [...]}","Sets refractive "
"indices, float. Each pair of arguments specifies real and imaginary part of the refractive index of one of "
"the domains. If '-anisotr' is specified, three refractive indices correspond to one domain (diagonal elements "
"of refractive index tensor in particle reference frame). Maximum number of different refractive indices is "
TO_STRING(MAX_NMAT) " (controlled by the parameter MAX_NMAT in const.h). None of the refractive indices can be "
"equal to 1+0i.\n"
"Default: 1.5 0",UNDEF,NULL},
{PAR(maxiter),"<arg>","Sets the maximum number of iterations of the iterative solver, integer.\n"
"Default: very large, not realistic value",1,NULL},
{PAR(no_reduced_fft),"","Do not use symmetry of the interaction matrix to reduce the storage space for the "
"Fourier-transformed matrix.",0,NULL},
{PAR(no_vol_cor),"","Do not use 'dpl (volume) correction'. If this option is given, ADDA will try to match size of "
"the dipole grid along x-axis to that of the particle, either given by '-size' or calculated analytically from "
"'-eq_rad'. Otherwise (by default) ADDA will try to match the volumes, using either '-eq_rad' or the value "
"calculated analytically from '-size'.",0,NULL},
{PAR(ntheta),"<arg>","Sets the number of intervals, into which the range of scattering angles [0,180] (degrees) is "
"equally divided, integer. This is used for scattering angles in yz-plane. If particle is not symmetric and "
"orientation averaging is not used, the range is extended to 360 degrees (with the same length of elementary "
"interval, i.e. number of intervals is doubled).\n"
"Default: from 90 to 720 depending on the size of the computational grid.",1,NULL},
{PAR(opt),"{speed|mem}",
"Sets whether ADDA should optimize itself for maximum speed or for minimum memory usage.\n"
"Default: speed",1,NULL},
{PAR(orient),"{<alpha> <beta> <gamma>|avg [<filename>]}","Either sets an orientation of the particle by three "
"Euler angles 'alpha','beta','gamma' (in degrees) or specifies that orientation averaging should be "
"performed. <filename> sets a file with parameters for orientation averaging. Here zyz-notation (or "
"y-convention) is used for Euler angles.\n"
"Default orientation: 0 0 0\n"
"Default <filename>: "FD_AVG_PARMS,UNDEF,NULL},
{PAR(phi_integr),"<arg>","Turns on and specifies the type of Mueller matrix integration over azimuthal angle "
"'phi'. <arg> is an integer from 1 to 31, each bit of which, from lowest to highest, indicates whether the "
"integration should be performed with multipliers 1, cos(2*phi), sin(2*phi), cos(4*phi), and sin(4*phi) "
"respectively.\n"
"Examples: 1 (one integration with no multipliers),\n"
" 6 (two integration with cos(2*phi) and sin(2*phi) multipliers).",1,NULL},
{PAR(pol),"{cldr|cm|dgf|fcd|igt_so|lak|ldr [avgpol]|nloc <Rp>|nloc_av <Rp>|rrc}",
"Sets prescription to calculate the dipole polarizability.\n"
"'cldr' - Corrected LDR (see below), incompatible with '-anisotr'.\n"
"'cm' - (the simplest) Clausius-Mossotti.\n"
"'dgf' - Digitized Green's Function (second order approximation to LAK).\n"
"'fcd' - Filtered Coupled Dipoles (requires dpl to be larger than 2).\n"
"'igt_so' - Integration of Green's tensor over a cube (second-order approximation).\n"
"'lak' - (by Lakhtakia) exact integration of Green's Tensor over a sphere.\n"
"'ldr' - Lattice Dispersion Relation, optional flag 'avgpol' can be added to average polarizability over "
"incident polarizations.\n"
"'nloc' - non-local (Gaussian dipole density, based on lattice sums), <Rp> is the width of the latter in um "
"(must be non-negative).\n"
"'nloc_av' - same as 'nloc' but based on averaging of Gh over the dipole volume.\n"
"'rrc' - Radiative Reaction Correction (added to CM).\n"
"Only poi,cldr, and igt_so can be used with '-rect_dip'.\n"
"Default: ldr (without averaging) or cldr (for -rect_dip).",UNDEF,NULL},
/* TO ADD NEW POLARIZABILITY FORMULATION
* Modify string constants after 'PAR(pol)': add new argument (possibly with additional sub-arguments) to list
* {...} and its description to the next string.
*/
{PAR(prognosis),"","Do not actually perform simulation (not even memory allocation) but only estimate the required "
"RAM. Implies '-test'.",0,NULL},
{PAR(prop),"<x> <y> <z>","Sets propagation direction of incident radiation, float. Normalization (to the unity "
"vector) is performed automatically. For point-dipole incident beam this determines its direction.\n"
"Default: 0 0 1",3,NULL},
{PAR(recalc_resid),"","Recalculate residual at the end of iterative solver.",0,NULL},
{PAR(rect_dip),"<x> <y> <z>","Use rectangular-cuboid dipoles. Three arguments are the relative dipole sizes along "
"the corresponding axes. Absolute scale is irrelevant, i.e. '1 2 2' is equivalent to '0.5 1 1'. Cannot be used "
"with '-anisotr' and '-granul'. The compatible polarizability and interaction-term formulations are also "
"limited.\n"
"Default: 1 1 1",3,NULL},
#ifndef SPARSE
{PAR(save_geom),"[<filename>]","Save dipole configuration to a file <filename> (a path relative to the output "
"directory). Can be used with '-prognosis'.\n"
"Default: <type>.geom \n"
"(<type> is a first argument to the '-shape' option; '_gran' is added if '-granul' option is used; file "
"extension can differ depending on argument of '-sg_format' option).",
UNDEF,NULL},
#endif // !SPARSE
{PAR(scat),"{dr|fin|igt_so}","Sets prescription to calculate scattering quantities.\n"
"'dr' - (by Draine) standard formulation for point dipoles\n"
"'fin' - slightly different one, based on a radiative correction for a finite dipole.\n"
"'igt_so' - second-order approximation to integration of Green's tensor.\n"
"Default: dr",1,NULL},
{PAR(scat_grid_inp),"<filename>","Specifies a file with parameters of the grid of scattering angles for "
"calculating Mueller matrix (possibly integrated over 'phi').\n"
"Default: "FD_SCAT_PARMS,1,NULL},
{PAR(scat_matr),"{muel|ampl|both|none}","Specifies which scattering matrices (from Mueller and amplitude) should "
"be saved to file. Amplitude matrix is never integrated (in combination with '-orient avg' or '-phi_integr').\n"
"Default: muel",1,NULL},
{PAR(scat_plane),"","Explicitly enables calculation of the scattering in the plane through e_z (in laboratory "
"reference frame) and propagation direction of incident wave. For default incidence this is the xz-plane. It "
"can also be implicitly enabled by other options.",0,NULL},
#ifndef SPARSE
{PAR(sg_format),"{text|text_ext|ddscat6|ddscat7}","Specifies format for saving geometry files. First two are ADDA "
"default formats for single- and multi-domain particles respectively. 'text' is automatically changed to "
"'text_ext' for multi-domain particles. Two DDSCAT formats correspond to its shape options 'FRMFIL' (version "
"6) and 'FROM_FILE' (version 7) and output of 'calltarget' utility.\n"
"Default: text",1,NULL},
#endif // !SPARSE
/* TO ADD NEW FORMAT OF SHAPE FILE
* Modify string constants after 'PAR(sg_format)': add new argument to list {...} and add its description to
* the next string.
*/
{PAR(shape),"<type> [<args>]","Sets shape of the particle, either predefined or 'read' from file. All parameters "
"of predefined shapes are floats except for <n> and filenames.\n"
"Default: sphere",UNDEF,shape_opt},
{PAR(size),"<arg>","Sets the size of the computational grid along the x-axis in um, float. If default wavelength "
"is used, this option specifies the 'size parameter' of the computational grid. Can not be used together with "
"'-eq_rad'. Size is defined by some shapes themselves, then this option can be used to override the internal "
"specification and scale the shape.\n"
"Default: determined by the value of '-eq_rad' or by '-grid', '-dpl', '-lambda', and '-rect_dip'.",1,NULL},
{PAR(so_buf),"{no|line|full}","Manually sets the buffering of stdout: no buffer, a single line, or using a large "
"buffer (typically, 0.5-4 KB).\n"
"Default: 'line' or 'full' when the stdout is printed directly to a terminal or is redirected, respectively",
1,NULL},
{PAR(store_beam),"","Save incident beam to a file",0,NULL},
{PAR(store_dip_pol),"","Save dipole polarizations to a file",0,NULL},
{PAR(store_force),"","Calculate the radiation force on each dipole. Implies '-Cpr'",0,NULL},
#ifndef SPARSE
{PAR(store_grans),"","Save granule coordinates (placed by '-granul' option) to a file",0,NULL},
#endif
{PAR(store_int_field),"","Save internal fields to a file",0,NULL},
{PAR(store_scat_grid),"","Calculate Mueller matrix for a grid of scattering angles and save it to a file.",0,NULL},
{PAR(surf),"<h> {<mre> <mim>|inf}","Specifies that scatterer is located above the plane surface, parallel to the "
"xy-plane. <h> specifies the height of particle center above the surface (along the z-axis, in um). Particle "
"must be entirely above the substrate. Following argument(s) specify the refractive index of the substrate "
"(below the surface), assuming that the vacuum is above the surface. It is done either by two values (real and "
"imaginary parts of the complex value) or as effectively infinite 'inf' which corresponds to perfectly"
"reflective surface. The latter implies certain simplifications during calculations.",UNDEF,NULL},
{PAR(sym),"{auto|no|enf}","Automatically determine particle symmetries ('auto'), do not take them into account "
"('no'), or enforce them ('enf').\n"
"Default: auto",1,NULL},
{PAR(test),"","Begin name of the output directory with 'test' instead of 'run'",0,NULL},
{PAR(V),"","Show ADDA version, compiler used to build this executable, build options, and copyright information",
0,NULL},
{PAR(vec),"","Calculate the not-normalized asymmetry vector",0,NULL},
{PAR(yz),"","Explicitly enables calculation of the scattering in the yz-plane (in incident-wave reference frame). "
"It can also be implicitly enabled by other options.",0,NULL}
/* TO ADD NEW COMMAND LINE OPTION
* add a row to this list, initializing an option. It should contain: PAR(option_name), usage string, help string,
* number of arguments, pointer to suboption (if exist, NULL otherwise). Usage and help string are shown either
* when -h option is invoked or error is found in input command line. Usage string is one line giving a list of
* possible arguments or argument combinations. Do not include option name in it, use <arg_name> to denote argument,
* [...] for optional arguments, and {...|...|...} for multiple options of an argument. Help string should contain
* general description of the option and its arguments, and provide default value for the arguments (if applicable).
* UNDEF can be used instead of number of arguments to avoid automatic checking, e.g. when command line option can
* accept variable number of arguments. Then check it explicitly in function PARSE_FUNC(option_name) below. A
* separate suboption structure is recommended only for large options such as -beam and -shape, and it should be
* defined above.
*/
};
// auxiliary functions
//======================================================================================================================
static const char *OptionName(void)
// produces full option name for error messages
{
static char buf[MAX_LINE];
if (opt.l2==UNDEF) return options[opt.l1].name;
else {
sprintf(buf,"%s %s",options[opt.l1].name,options[opt.l1].sub[opt.l2].name);
return buf;
}
}
//======================================================================================================================
void PrintErrorHelp(const char * restrict fmt, ... )
/* print anything to stderr (on root processor), then help on the arguments used, and stop; assumes that all processors
* call it; has line wrapping. It is designed to be relatively safe (using snprintf and vsnprintf), but do not produce
* any additional errors in case of buffer overflows, etc. (not to distract from the main error itself). However, for
* uncontrolled (e.g. user-input) arguments, it is recommended to use PrintErrorHelpSafe instead.
*/
{
va_list args;
const char * restrict optname,* restrict use;
char msg[MAX_MESSAGE]="ERROR: ";
int shift,tmp;
if (IFROOT) {
// produce error message
va_start(args,fmt);
shift=strlen(msg);
VSNPRINTF_SHIFT_ROBUST(shift,tmp,msg,MAX_MESSAGE,fmt,args);
va_end(args);
// add help message
if (opt.l1==UNDEF) { // no option is found
SNPRINTF_SHIFT_ROBUST(shift,tmp,msg,MAX_MESSAGE,"\n"
"Usage: %s %s\n"
"Type '%s -h' for help\n",exename,exeusage,exename);
}
else { // at least option is found
if (opt.l2==UNDEF) use=options[opt.l1].usage;
else use=options[opt.l1].sub[opt.l2].usage;
optname=OptionName();
SNPRINTF_SHIFT_ROBUST(shift,tmp,msg,MAX_MESSAGE,"\n"
"Usage: -%s %s\n"
"Type '%s -h %s' for details\n",optname,use,exename,optname);
}
WrapLines(msg);
fflush(NULL);
fprintf(stderr,"%s",msg);
}
// wait for root to generate an error message
Synchronize();
Stop(EXIT_FAILURE);
}
//======================================================================================================================
static void ATT_NORETURN ATT_PRINTF(1,2) PrintErrorHelpSafe(const char * restrict fmt, ... )
/* print anything to stderr (on root processor), then help on the arguments used, and stop; assumes that all processors
* call it; same as PrintErrorHelp but uses no internal buffers to be safe for any input parameters, which may come
* from a command line, at a cost of lacking line wrapping.
*/
{
va_list args;
const char * restrict optname,* restrict use;
if (IFROOT) {
// produce error message
va_start(args,fmt);
fflush(NULL);
fprintf(stderr,"ERROR: ");
vfprintf(stderr,fmt,args);
fprintf(stderr,"\n");
va_end(args);
// add help message
if (opt.l1==UNDEF) // no option is found
fprintf(stderr,"Usage: %s %s\n"
"Type '%s -h' for help\n",exename,exeusage,exename);
else { // at least option is found
if (opt.l2==UNDEF) use=options[opt.l1].usage;
else use=options[opt.l1].sub[opt.l2].usage;
optname=OptionName();
fprintf(stderr,"Usage: -%s %s\n"
"Type '%s -h %s' for details\n",optname,use,exename,optname);
}
}
// wait for root to generate an error message
Synchronize();
Stop(EXIT_FAILURE);
}
//======================================================================================================================
static void NargError(const int Narg,const char *expec)
// Print error of illegal number of arguments to an option (suboption) and display correct usage information
{
PrintErrorHelp("Illegal number of arguments (%d) to '-%s' option (%s expected)",Narg,OptionName(),expec);
}
//======================================================================================================================
static void NargErrorSub(const int Narg,const char *option,const char *expec)
/* Print error of illegal number of arguments to an option (usually with suboption) and display correct usage
* information. Narg is decremented before printing.
*/
{
PrintErrorHelp("Illegal number of arguments (%d) to '-%s' option (%s expected)",Narg-1,option,expec);
}
//======================================================================================================================
static void TestExtraNarg(const int Narg, const bool notAllowed,const char *subopt)
// check if Narg is larger than 1 for suboption, which doesn't allow that
{
if (Narg>1 && notAllowed) PrintErrorHelp("Additional arguments are not allowed for '-%s %s'",OptionName(),subopt);
}
//======================================================================================================================
static void TestNarg(const int Narg,const int need)
// check if Narg given to an option (or suboption) is correct; interface to NargError
{
if (need>=0) { // usual case
if (Narg!=need) {
char buf[MAX_WORD];
snprintf(buf,MAX_WORD,"%d",need);
NargError(Narg,buf);
}
} // otherwise special cases are considered, encoded by negative values
else switch (need) {
case UNDEF: break; // do nothing
case FNAME_ARG: if (Narg!=1) NargError(Narg,"1"); break;
case FNAME_ARG_2: if (Narg!=2) NargError(Narg,"2"); break;
case FNAME_ARG_1_2: if (Narg!=1 && Narg!=2) NargError(Narg,"1 or 2"); break;
default: // rigorous test that every possible special case is taken care of
PrintError("Critical error in TestNarg function (unknown argument 'need'=%d). Probably this comes from "
"value of 'narg' in one of static arrays, describing command line options.",need);
// no break
}
}
//======================================================================================================================
static void ATT_NORETURN NotSupported(const char * restrict type,const char * restrict given)
// print error message that "type 'given' is not supported"; type should start with a capital letter
{
PrintErrorHelpSafe("%s '%s' is not supported",type,given);
}
//======================================================================================================================
static const char *ScanStrError(const char * restrict str,const unsigned int size)
// check if string fits in buffer of size 'size', otherwise produces error message; returns the passed str (redirects)
{
if (strlen(str)>=size) PrintErrorHelp("Too long argument to '-%s' option (only %u chars allowed). If you really "
"need it you may increase MAX_DIRNAME in const.h and recompile",OptionName(),size-1);
return str;
}
//======================================================================================================================
static void ScanDoubleError(const char * restrict str,double *res)
// scanf an option argument and checks for errors
{
if (sscanf(str,"%lf",res)!=1)
PrintErrorHelpSafe("Non-numeric argument (%s) is given to the option '-%s'",str,OptionName());
}
//======================================================================================================================
static void ScanDouble3Error(char **argv,double res[static 3])
// scans an option argument (3D vector of doubles) and checks for errors
{
ScanDoubleError(argv[0],res);
ScanDoubleError(argv[1],res+1);
ScanDoubleError(argv[2],res+2);
}
//======================================================================================================================
static void ScanIntError(const char * restrict str,int *res)
// scanf an option argument and checks for errors
{
double tmp;
if (sscanf(str,"%lf",&tmp)!=1)
PrintErrorHelpSafe("Non-numeric argument (%s) is given to the option '-%s'",str,OptionName());
// The following can be rewritten by call to ConvertToInteger(), but it is complicated due to presence of OptionName
if (tmp != floor(tmp))
PrintErrorHelpSafe("Argument value (%s) of the option '-%s' is not an integer",str,OptionName());
if (tmp <INT_MIN || tmp>INT_MAX)
PrintErrorHelpSafe("Argument value (%s) of the option '-%s' is out of integer bounds",str,OptionName());
*res=(int)tmp;
}
//======================================================================================================================
static bool ScanFnamesError(const int Narg,const int need,char **argv,const char **fname1,const char **fname2)
/* If 'need' corresponds to one of FNAME_ARG, scan Narg<=2 filenames from argv into fname1 and fname2. All consistency
* checks are left to the caller (in particular, whether Narg corresponds to need). argv should be shifted to contain
* only filenames. fname2 can be NULL, but it will produce an error in combination with Narg=2)
*
* Returns whether filenames has been scanned.
*/
{
bool res=false;
if (IS_FNAME_ARG(need)) {
*fname1=ScanStrError(argv[0],MAX_FNAME);
if (Narg==2) {
if (fname2==NULL) // consistency check e.g. for reading shape filename
PrintError("Failed to store the second filename in function ScanFnamesError");
else *fname2=ScanStrError(argv[1],MAX_FNAME);
}
res=true;
}
return res;
}
//======================================================================================================================
static bool IsOption(const char * restrict str)
/* checks if string is an option. First should be '-' and then letter (any case); it enables use of negative numbers
* as sub-parameters
*/
{
// conversion to int is needed to remove warnings caused by the fact that str[1] is _signed_ char
return (str[0]=='-' && isalpha((int)(str[1])));
}
//======================================================================================================================
static int TimeField(const char c)
// analyze one time multiplier
{
switch (c) {
case 'd':
case 'D': return 86400;
case 'h':
case 'H': return 3600;
case 'm':
case 'M': return 60;
case 's':
case 'S': return 1;
default: PrintErrorHelp("Illegal time format specifier (%c)",c);
}
}
//======================================================================================================================
static int ScanTime(const char * restrict str)
// scans time in seconds from a string "%d[d,D[%d]][h,H[%d]][m,M[%d]][s,S]
{
#define TIME_N_TYPES 4 // not so easy to change
int tim,t[TIME_N_TYPES],n,i;
char c[TIME_N_TYPES];
for (i=0;i<TIME_N_TYPES;i++) c[i]=0;
n=sscanf(str,"%d%c%d%c%d%c%d%c",t,c,t+1,c+1,t+2,c+2,t+3,c+3);
if (n<1) PrintErrorHelpSafe("Wrong time format '%s'",str);
tim=0;
i=0;
while (n>0) {
tim+=t[i]*TimeField(c[i]);
n-=2;
i++;
}
return tim;
#undef TIME_N_TYPES