Closed grumpyinca closed 2 years ago
Consider blocking the operation of Search, Seek & Trade if there are any un-read (un-viewed) alerts.
Pseudo-code implementing first generation design-type specific alerts
Per 6/12/2021 discussion, there is an analogy with the "Validator" in the UT CLE system. This code might be implemented as {designtype}/validate.js files. Separately, the design-type independent code currently in code currently in
Note that there is a bit of terminology clash on the term "validator". In spring design, the term "design validation" is used to describe the process of checking an existing design for correctness.
See the initial description of this issue for a more detailed description of "condition", "details", "severity", "viewed" and "control" properties.
As noted above in the original issue description:
Compression Spring
From existing code in ReportBase.js: if (this.props.symbol_table[o.L_Free].value < this.props.symbol_table[o.L_Solid].value) { this.hits++; msg.condition = "L_Free < L_Solid" msg.severity = "warn" msg.viewed = FALSE msg.control = "always" msg.details = this.props.symbol_table[o.L_Free].name + " < " + this.props.symbol_table[o.L_Solid].name; } if (this.props.symbol_table[o.L_2].value < this.props.symbol_table[o.L_Solid].value) { this.hits++; msg.condition = "L_2 < L_Solid" msg.severity = "warn" msg.viewed = FALSE msg.control = "always" msg.details = this.props.symbol_table[o.L_2].name + " < " + this.props.symbol_table[o.L_Solid].name; } if (this.props.symbol_table[o.ID_Free].value < 0.0) { this.hits++; msg.condition = "ID_Free < Wire_Dia" msg.severity = "error" msg.viewed = FALSE msg.control = "always" msg.details = this.props.symbol_table[o.ID_Free].name + " < Wire_Dia"; } if (this.props.symbol_table[o.Coils_A].value < 1.0) { this.hits++; msg.condition = "Coils_A < 1.0" msg.severity = "warn" msg.viewed = FALSE msg.control = "always" msg.details = this.props.symbol_table[o.Coils_A].name + " < 1.0"; } if (this.props.symbol_table[o.Wire_Dia].value < 0.1 this.props.symbol_table[o.tbase010].value) { this.hits++; msg.condition = "Wire_Dia < reasonable" msg.severity = "warn" msg.viewed = FALSE msg.control = "always" msg.details = this.props.symbol_table[o.Wire_Dia].name + " < reasonable"; } if (this.props.symbol_table[o.Wire_Dia].value > 5.0 this.props.symbol_table[o.tbase400].value) { this.hits++; msg.condition = "Wire_Dia > reasonable" msg.severity = "warn" msg.viewed = FALSE msg.control = "always" msg.details = this.props.symbol_table[o.Wire_Dia].name + " > reasonable"; } if (this.props.symbol_table[o.Tensile].value <= this.props.system_controls.smallnum) { this.hits++; msg.condition = "Tensile < reasonable" msg.severity = "warn" msg.viewed = FALSE msg.control = "always" msg.details = this.props.symbol_table[o.Tensile].name + " < reasonable"; } if (this.props.symbol_table[o.PC_Avail_Deflect].value > 80.0) { msg.condition = "%_Avail_Deflect > 80" msg.severity = "info" msg.viewed = FALSE msg.control = "always" msg.details = "Deflection at load point 2 is" + {this.props.symbol_table[o.PC_Avail_Deflect].value.toFixed(0)} + "% of total available deflection." + "Coil to coil contact may cause inaccuracy in point 2."; }
temp = this.props.symbol_table[o.Deflect_2].value / this.props.symbol_table[o.L_Free].value;
sq1 = 1.4 * this.props.symbol_table[o.Slenderness].value - 4.0;
this.errmsg1 = undefined;
this.errmsg0 = undefined;
if (sq1 > this.props.system_controls.smallnum) {
/* structured to avoid div by 0 */
if (temp > 0.76 / sq1) {
this.errmsg1 = "Given a deflection ratio of " + temp.toFixed(3) +
" and a Slenderness ratio of " + this.props.symbol_table[o.Slenderness].value.toFixed(1) + ", " +
"the spring will tend to buckle with fixed/free ends.";
sq1 = 2.0 * this.props.symbol_table[o.Slenderness].value - 8.0;
if (sq1 <= 0.0 || temp < 1.6 / sq1)
this.errmsg0 = " not";
else
this.errmsg0 = "";
this.errmsg0 = "The spring will" + this.errmsg0 + " tend to buckle with fixed/fixed ends.";
}
}
if (this.errmsg1 !== undefined) {
msg.condition = "Buckling concern"
msg.severity = "info"
msg.viewed = FALSE
msg.control = "always"
msg.details = errmsg1 + errmsg0;
}
New messages:
PC_Avail_Deflect1 = 100.0 * this.props.symbol_table[o.Deflect_1] / (this.props.symbol_table[o.L_Free] - this.props.symbol_table[o.L_Solid])
if PC_Avail_Deflect1 < 20.0) {
msg.condition = "Deflect_1 < 20 %_Avail_Deflect"
msg.severity = "info"
msg.viewed = FALSE
msg.control = "always"
msg.details = "Deflection at load point 1 is" + PC_Avail_Deflect1.toFixed(0) +
"% of total available deflection. " + "End effects may cause inaccuracy in point 1.";
}
if this.props.symbol_table[o.FS_Solid] < 1.0) {
msg.condition = "FS_Solid < 1.0"
msg.severity = "warn"
msg.viewed = FALSE
msg.control = "always"
msg.details = "This spring may be over-stressed if deflected to solid.
It may 'set' as in not return to its original free length.";
}
if (this.props.symbol_table[o.FS_2].lmax = 'CONSTRAINED' && this.props.symbol_table[o.FS_2].value > this.props.symbol_table[o.FS_2].cmax) {
msg.condition = "Over design concern"
msg.severity = "info"
msg.viewed = FALSE
msg.control = "always"
msg.details = "Factor of Safety at load point 2 exceeds its maximum constraint.
This design may be excessively conservative.
Suggest investigating a smaller wire diameter.
Alternatively, increase the MAX constraint level or disable the MAX constraint";
}
if (this.props.symbol_table[o.Life_Category].value > 1 && this.props.symbol_table[o.FS_Cycle_Life].lmin != 'CONSTRAINED') {
msg.condition = "No FS_Cycle_Life constraint"
msg.severity = "info"
msg.viewed = FALSE
msg.control = "always"
msg.details = "A more restrictive Life_Category has been selected but
the corresponding constraint on FS_Cycle_Life is not enabled.
Suggest enabling FS_Cycle_Life MIN constraint.
See Cycle Life section of Help Spring Overview and tutorial session tutor4";
}
if (this.props.symbol_table[o.Force_2].lmin != 'FIXED' && this.props.symbol_table[o.Force_2].lmin != 'CONSTRAINED' &&
this.props.symbol_table[o.Rate].lmin != 'FIXED' && this.props.symbol_table[o.Rate].lmin != 'CONSTRAINED' && this.props.symbol_table[o.Rate].lmax != 'CONSTRAINED' &&
this.props.symbol_table[o.Deflect_2].lmin != 'FIXED' && this.props.symbol_table[o.Deflect_2].lmin != 'CONSTRAINED' && this.props.symbol_table[o.Deflect_2].lmax != 'CONSTRAINED' &&
this.props.symbol_table[o.L_2].lmin != 'FIXED' && this.props.symbol_table[o.L_2].lmin != 'CONSTRAINED' && this.props.symbol_table[o.L_2].lmax != 'CONSTRAINED'
)
{
msg.condition = "Under-specified?"
msg.severity = "warn"
msg.viewed = FALSE
msg.control = "onSearchSeek"
msg.details = "It appears that no constraints on Force_2, Rate, Deflect_2 or L_2 are enabled.
The design may be under-specified. Search & Seek may generate trivial solutions.
Refer to Help on Design Situations.";
}
if (this.props.symbol_table[o.Deflect_2].value <= 0.0) {
this.hits++;
msg.condition = "Deflect_2 <= 0"
msg.severity = "warn"
msg.viewed = FALSE
msg.control = "always"
msg.details = this.props.symbol_table[o.Deflect_2].name + " <= 0.
Calculations for L_Stroke and Cycle_Life may not be valid.
Confirm that input values are not negative and Force_2 is greater than Force_1.";
}
if (this.props.symbol_table[o.L_Stroke].value <= 0.0) {
this.hits++;
msg.condition = "L_Stroke <= 0"
msg.severity = "warn"
msg.viewed = FALSE
msg.control = "always"
msg.details = this.props.symbol_table[o.Deflect_2].name + " <= 0.
Calculations for Cycle_Life may not be valid.
Confirm that input values are not negative and Force_2 is greater than Force_1.";
}
if (this.props.symbol_table[o.Spring_Index].value < 4.0) {
this.hits++;
msg.condition = "Spring_Index < 4"
msg.severity = "warn"
msg.viewed = FALSE
msg.control = "always"
msg.details = this.props.symbol_table[o.Spring_Index].name + " less than 4 is difficult to manufacture.
Suggest enabling the " + this.props.symbol_table[o.Spring_Index].name + " MIN constraint and possibly
increasing the value of " + this.props.symbol_table[o.OD_Free].name + " to provide a better starting point for the next Search.";
}
if (this.props.symbol_table[o.Spring_Index].value > 25.0) {
this.hits++;
msg.condition = "Spring_Index > 25"
msg.severity = "warn"
msg.viewed = FALSE
msg.control = "always"
msg.details = this.props.symbol_table[o.Spring_Index].name + " greater than 25 is difficult to manufacture.
Suggest enabling the " + this.props.symbol_table[o.Spring_Index].name + " MAX constraint and possibly
decreasing the value of " + this.props.symbol_table[o.OD_Free].name + " to provide a better starting point for the next Search.";
}
if (this.props.symbol_table[o.Force_2].value <= this.props.symbol_table[o.Force_1].value) {
this.hits++;
msg.condition = "Force_2 <= Force_1"
msg.severity = "warn"
msg.viewed = FALSE
msg.control = "always"
msg.details = this.props.symbol_table[o.Force_2].name + " must be greater than " + this.props.symbol_table[o.Force_1].name + ".";
}
At end of table of rendered messages: if (this.hits) { msg.condition = "Potential numeric difficulties" msg.severity = "warn" msg.viewed = FALSE msg.control = "always" msg.details = "Physically unrealistic values may cause numeric difficulties that the Search algorithm is not able to resolve. Consider adjusting values to create a more reasonable start point before continuing with Search, Seek or Trade. Any "NaN" values are "Not a Number". See Help Alerts for additional information."; }
Extension Spring
Continue with the pattern developed for compression springs.
if (this.props.symbol_table[o.Force_1].value < this.props.symbol_table[o.Initial_tension].value) {
msg.condition = "Force_1 < Initial_Tension"
msg.severity = "info"
msg.viewed = FALSE
msg.control = "always"
msg.details = "The current value of Force_1 is less than the current value of Initial_Tension.
Calculations for L_Stroke and Cycle_Life may not be valid.
Suggest increasing the value of Force_1 so that it is greater than Initial_Tension.
See Help Terminology FUNCTION CONSTRAINTS (FDCL) and
Help Extension Spring (Constraints unique to extension springs)";
}
Torsion Spring
Continue with the pattern developed for compression springs.
Consider having eqnset return a parameter that says "Out of bounds" or "Invalid combination of inputs" or "Not physically realistic".
This parameter could be checked before starting a search (resulting in pop-up warning) and also at each iteration in the search (resulting in search termination and return with an error condition). The error message may provide a suggestion as to how the user may correct the situation.
Consider adding a "user having difficulty" measurement. If the measurement exceeds some threshold. trigger an alert that offers free technical support.
One possible "user having difficulty" measurement is the number of searches executed within the current session. I am thinking of a simple counter that does not persist. So for example, if the user executes more than 10? searches within the current session, an alert that says something along the lines of: "Having difficulty? Contact us"
Should Alerts be automatically cleared at the time that they are viewed?
Should informational alerts that have been viewed multiple times in the current session be suppressed from recurrence ?
Consider enhancing the Execute (script) facility to allow it to write alerts and result panel messages.
To do items:
This comment may be more appropriate in issue 590.
Search needs to be able to start from an invalid start point. The pre-590 Search could do that. There were relatively common cases where a start from what post-590 considers to be an invalid start point produced a valid result.
Once Search can start from an invalid start point, it will be reasonable to move validity checks and UI elements (pop-ups) from before Search to after Search. The pop-up will be necessary only for the case of an invalid result.
DONE - before 6/26/2022 BDW & MKM
The current state of branch 569 has a minor bug in failing to highlight constraint violations in the green zone. This is true in both Advanced and Calculator Views.
To reproduce the problem:
THIS IS GOING TO BE IGNORED AND NOT DONE - WON'T FIX - 6/25/2022 BDW AND MKM.
The current state of branch 569 has a minor bug in that it can carry "stale" alert triangle(s) across a change of design type. To demonstrate this behavior:
FIXED AND DONE - before 6/25/2022.
This comment is more a question than a specification for a change in app behavior.
Would it be better for alert severity to adapt a density range of a single color (purple?, violet?) as opposed to the current overlap with the color scheme of the multi-color feasibility indicator ? The highest severity would be the brightest possible shade of the selected color. The decreasing severity levels could have darker shades of the single color until the lowest severity ("Info") would be black.
The multi-color feasibility indicator would get a narrow band of the selected color at the right end. Objective Value of Infinity would point there.
What about changing the severity designations from (Err, Warn, Notice, Info) to (Invalid, Concern, Notice, Info) ?
NOT USE A COLOR, BUT INSTEAD USE BLACK and FONT STYLE (ITALIC) & WIDTH (BOLD) CHANGES. NO POS_INFINITY SO WE ARE NOT GOING TO MODIFY THE FEASIBILITY INDICATOR. NOR WILL WE CHANGE THE SEVERITY DESIGNATION. - 6/25/2022 BDW AND MKM.
Merged into master, closing
As currently envisioned, a new "Alerts facility" provides design-type specific messages. It is potentially manifested by a button in the ResultTable adjacent to the Search button of issue #560.
Labeled "Alerts", this button would have three possible states:
For the Spring design types, the Alert message string is currently visualized as a stack or table of currently active individual alert messages, each with a color-coded severity. The individual alert messages would include existing warning messages produced in Spring Report1 (including the compression spring buckling and extension spring end fatigue failure messages) plus new alert/warning messages. The full set of alerts should continue to appear in Report1. This may require a re-implementation based on the new Alerts facility.
Alternative renderings in the UI:
Possible new alert/warning messages include:
For example: Deflection < 0, L_Stroke < 0, Spring_Index < 4 or > 25, Force_2 <= Force_1 (produces negative L_Stroke), others
Implementation The Alert conditions may be computed in a single place, but the alert text likely needs to be rendered in multiple places, including:
Ideally, the criteria for active alerts would be computed only as it is needed. For example, when the ResultTable.js is invoked and before the ResultTable is rendered. As this is design-type specific information, there may be challenges to maintaining appropriate modularity and isolation. In order to keep design-type specific messages isolated and not re-computed every time that eqnset is called during a search, it might be necessary to put the alert conditions into a separate design-type specific function that is called somewhat more frequently than ResultTable is rendered. For example, whenever the Objective Value is updated outside of Search. A quick review suggests that might be one place in updateViolationsAndObjectiveValue.js or multiple (13?) places in dispatcher.js.
If the alert conditions are computed in one place but rendered in multiple places, consider defining the message table in a .json file and structuring each message with "condition", "details", "severity", "viewed" and "control" properties.
The first generation Alerts facility does not need to include the generic messages implemented in #557 (Add warning messages prior to Action : Search).