Skip to content

Commit a320531

Browse files
adding more validations from the 4nec2 side and merging them together with cebic
1 parent 7743cd1 commit a320531

File tree

11 files changed

+246
-156
lines changed

11 files changed

+246
-156
lines changed

doc/Deck Validation Tests.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,20 @@ This document summarizes the validation and guidance checks implemented in OpenN
6565
- Overlapping wires: Warn if any two wires have identical endpoints (same or reversed).
6666
- Parallel wires: Warn when parallel wires closer than `0.05` wavelengths have different segmentation (counts or lengths differing by >10%).
6767
- Segment length vs. wavelength (WL):
68-
- `>= 0.1 WL`: warn.
69-
- `>= 0.05 WL`: advisory (critical regions should be < `0.05 WL`).
70-
- `< 0.001 WL`: advisory (excessive segmentation).
68+
- Cebik guidance: `>= 0.1 WL` warning; `>= 0.05 WL` advisory; `< 0.001 WL` advisory for excessive segmentation.
69+
- 4nec2 additions: error if `>= 0.2 WL` (coarse segmentation) or `< 0.001 WL` (too fine).
70+
- Combined check produces both Cebik and 4nec2 messages where thresholds overlap.
71+
- Radius vs. wavelength:
72+
- 4nec2 warns if radius > `WL/100`, errors if > `WL/30`.
73+
- Length/radius ratio on a segment:
74+
- Cebik warns if `L/R <= 10` (now adjusted to `<= 8` per 4nec2); error if `L/R <= 2`.
75+
- With EK: warning if `L/R <= 2`, error if `L/R <= 0.5`.
76+
- Junction checks:
77+
- Segmentation ratio: warn if endpoints differ by >20% (existing) and also if one length is >5× the other (4nec2).
78+
- Radius ratio at junction: warn if `R_big/R_small > 5`, error if `> 10` (4nec2).
79+
- Length/radius at junction: warn if `L < 6R`, error if `L < 2R` (4nec2).
80+
- Surface patch area:
81+
- 4nec2 error when patch area (in λ²) exceeds `1/25 WL`.
7182
- Radius guidance (thin-wire assumptions):
7283
- Default kernel: warn if `radius >= len/2`; advise if `radius >= len/10`.
7384
- Extended kernel (`EK`): warn if `radius >= 2*len`.

src/card_validation.c

Lines changed: 18 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -43,119 +43,21 @@ static field_validation_t ok(void)
4343
return r;
4444
}
4545

46-
/* Find the first usable FR base frequency in MHz. Returns 1 when found. */
47-
static int get_first_fr_mhz(const deck_t *deck, double *freq_mhz)
48-
{
49-
if (!deck || !freq_mhz)
50-
return 0;
51-
52-
for (int i = 0; i < deck->num_cards; i++)
53-
{
54-
const card_t *c = &deck->cards[i];
55-
if (strncmp(c->card_code, "FR", 2) != 0)
56-
continue;
57-
if (c->ignore)
58-
continue;
59-
if (c->f[1] > 0.0)
60-
{
61-
*freq_mhz = c->f[1];
62-
return 1;
63-
}
64-
}
65-
66-
return 0;
67-
}
68-
69-
static double estimate_helix_length(double s, double hl, double a1, double b1, double a2, double b2)
70-
{
71-
double abs_hl = fabs(hl);
72-
if (abs_hl <= 0.0)
73-
return 0.0;
74-
if (fabs(s) < 1.0e-12)
75-
return abs_hl;
76-
77-
double turns = fabs(hl / s);
78-
double b1_eff = (b1 == 0.0) ? a1 : b1;
79-
double b2_eff = (b2 == 0.0) ? a2 : b2;
80-
double a = 0.5 * (fabs(a1) + fabs(a2));
81-
double b = 0.5 * (fabs(b1_eff) + fabs(b2_eff));
8246

83-
double perim;
84-
if (fabs(a - b) <= 1.0e-12)
85-
perim = 2.0 * PI * a;
86-
else
87-
perim = PI * (3.0 * (a + b) - sqrt((3.0 * a + b) * (a + 3.0 * b)));
8847

89-
{
90-
double circum_path = perim * turns;
91-
return sqrt(circum_path * circum_path + abs_hl * abs_hl);
92-
}
93-
}
94-
95-
/* Deck-aware warning on I2 segment field for GW/GA/GH. */
96-
static field_validation_t validate_geometry_segment_field_with_deck(const card_t *c, const deck_t *deck, int is_int, int idx)
48+
/* Stubs for geometry segment warnings
49+
*
50+
* The earlier implementation made a best-effort to compute a warning based on
51+
* the first FR card in the deck. That is a deck-level check and belongs in
52+
* deck_validations.c, not in this per-card module. We simply return OK here
53+
* and drop the dependency on the deck pointer. The API remains simple and
54+
* deck-agnostic.
55+
*/
56+
static field_validation_t validate_geometry_segment_field(const card_t *c, int is_int, int idx)
9757
{
98-
if (!c || !is_int || idx != 2)
99-
return ok();
100-
101-
if (!(strcmp(c->card_code, "GW") == 0 || strcmp(c->card_code, "GA") == 0 || strcmp(c->card_code, "GH") == 0))
102-
return ok();
103-
104-
if (c->i[2] <= 0)
105-
return ok(); /* Existing card-local validators report the hard error. */
106-
107-
double freq_mhz = 0.0;
108-
if (!get_first_fr_mhz(deck, &freq_mhz))
109-
return ok(); /* Explicitly silent when no FR exists in deck. */
110-
111-
if (freq_mhz <= 0.0)
112-
return ok();
113-
114-
double wavelength = CVEL / freq_mhz;
115-
if (wavelength <= 0.0)
116-
return ok();
117-
118-
double total_len = 0.0;
119-
double radius = 0.0;
120-
if (strcmp(c->card_code, "GW") == 0)
121-
{
122-
double dx = c->f[4] - c->f[1];
123-
double dy = c->f[5] - c->f[2];
124-
double dz = c->f[6] - c->f[3];
125-
total_len = sqrt(dx * dx + dy * dy + dz * dz);
126-
radius = c->f[7];
127-
}
128-
else if (strcmp(c->card_code, "GA") == 0)
129-
{
130-
double arc_r = fabs(c->f[1]);
131-
double theta = fabs(c->f[3] - c->f[2]) * (PI / 180.0);
132-
total_len = arc_r * theta;
133-
radius = c->f[4];
134-
}
135-
else if (strcmp(c->card_code, "GH") == 0)
136-
{
137-
total_len = estimate_helix_length(c->f[1], c->f[2], c->f[3], c->f[4], c->f[5], c->f[6]);
138-
radius = c->f[7];
139-
}
140-
141-
if (total_len <= 0.0)
142-
return ok();
143-
144-
{
145-
double seg_len = total_len / (double)c->i[2];
146-
double min_seg = 1.0e-4 * wavelength;
147-
if (seg_len < min_seg)
148-
RESULT(WARNING, "%s on line %d: I2 gives segment length %.6g, smaller than 1e-4 wavelength (%.6g).", c->card_code, c->card_num, seg_len, min_seg);
149-
150-
if (radius > 0.0)
151-
{
152-
double lim_seg = 0.5 * seg_len;
153-
double lim_wav = 0.1 * wavelength;
154-
if (radius < lim_seg || radius < lim_wav)
155-
RESULT(WARNING, "%s on line %d: I2 implies segment length %.6g, and wire radius %.6g is smaller than 0.5*segment (%.6g) or 0.1*wavelength (%.6g).", c->card_code, c->card_num, seg_len, radius, lim_seg, lim_wav);
156-
}
157-
}
158-
58+
(void)c;
59+
(void)is_int;
60+
(void)idx;
15961
return ok();
16062
}
16163

@@ -639,7 +541,7 @@ static field_validation_t validate_SP_field(const card_t *c, int is_int, int idx
639541
* validate_card_field — public dispatch entry point
640542
*****************************************************************************/
641543

642-
field_validation_t validate_card_field_with_deck(const card_t *card, const deck_t *deck, const char *field_name)
544+
field_validation_t validate_card_field(const card_t *card, const char *field_name)
643545
{
644546
if (!card || !field_name)
645547
return ok();
@@ -703,16 +605,13 @@ field_validation_t validate_card_field_with_deck(const card_t *card, const deck_
703605
if (base.severity != NONE)
704606
return base;
705607

706-
return validate_geometry_segment_field_with_deck(card, deck, is_int, idx);
608+
/* deck-independent stub (see notes above) */
609+
return validate_geometry_segment_field(card, is_int, idx);
707610

708611
/* GF: no field rules — filename lives in card_str, not i[]/f[] */
709612
/* CM, CE, EN, SY, and others: no per-field rules at this level */
710613
}
711614

712-
field_validation_t validate_card_field(const card_t *card, const char *field_name)
713-
{
714-
return validate_card_field_with_deck(card, NULL, field_name);
715-
}
716615

717616
/******************************************************************************
718617
* validate_card_all_fields — validate all 11 fields in one call
@@ -722,20 +621,16 @@ field_validation_t validate_card_field(const card_t *card, const char *field_nam
722621
* results[4..10] => F1..F7 (F_idx = fieldN + 3)
723622
*****************************************************************************/
724623

725-
void validate_card_all_fields_with_deck(const card_t *card, const deck_t *deck, field_validation_t results[11])
624+
void validate_card_all_fields(const card_t *card, field_validation_t results[11])
726625
{
727626
/* I1..I4 at indices 0..3 */
728627
static const char *int_names[] = {"I1", "I2", "I3", "I4"};
729628
for (int n = 0; n < 4; n++)
730-
results[n] = validate_card_field_with_deck(card, deck, int_names[n]);
629+
results[n] = validate_card_field(card, int_names[n]);
731630

732631
/* F1..F7 at indices 4..10 */
733632
static const char *flt_names[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7"};
734633
for (int n = 0; n < 7; n++)
735-
results[4 + n] = validate_card_field_with_deck(card, deck, flt_names[n]);
634+
results[4 + n] = validate_card_field(card, flt_names[n]);
736635
}
737636

738-
void validate_card_all_fields(const card_t *card, field_validation_t results[11])
739-
{
740-
validate_card_all_fields_with_deck(card, NULL, results);
741-
}

src/card_validation.h

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
*
88
* Unlike deck_validations.c, which sweeps the whole deck and returns a message
99
* list, these functions primarily validate single cards and return a result by
10-
* value. Deck-aware variants are provided when a field rule depends on deck
11-
* context (for example, FR-driven wavelength checks).
10+
* value. (Earlier versions exposed deck-aware helpers, but all current
11+
* rules operate on a single card without knowledge of other cards.)
1212
*
1313
* Severity uses the existing error_level enum from types.h:
1414
* NONE = 0 No problem detected, or no validation rule defined for field
@@ -54,14 +54,6 @@ typedef struct {
5454
*/
5555
field_validation_t validate_card_field(const card_t *card, const char *field_name);
5656

57-
/*
58-
* validate_card_field_with_deck
59-
*
60-
* Same as validate_card_field(), but may use deck context for rules that
61-
* depend on other cards (for example FR-dependent segment-size warnings).
62-
* If deck is NULL, deck-dependent rules are skipped.
63-
*/
64-
field_validation_t validate_card_field_with_deck(const card_t *card, const deck_t *deck, const char *field_name);
6557

6658
/*
6759
* validate_card_all_fields
@@ -80,11 +72,5 @@ field_validation_t validate_card_field_with_deck(const card_t *card, const deck_
8072
*/
8173
void validate_card_all_fields(const card_t *card, field_validation_t results[11]);
8274

83-
/*
84-
* validate_card_all_fields_with_deck
85-
*
86-
* Deck-aware equivalent of validate_card_all_fields().
87-
*/
88-
void validate_card_all_fields_with_deck(const card_t *card, const deck_t *deck, field_validation_t results[11]);
8975

9076
#endif /* CARD_VALIDATION_H */

0 commit comments

Comments
 (0)