This policy for the Webel Psy
library for Psychrometrics (humid air physics) in Mathematica is very easy to apply in the Wolfram Language code (indeed much easier than not applying it), and comes only at a very slight performance cost, for a great advantage in robustness. From the point of view of the SysML modelling for SysML4Mathematica it involves a bit more lower-level modelling fuss, but is still worth doing, and makes higher level SysML modelling easier (and more robust).
From the Mathematica code point of view
Consider this Psy
library Mathematica code for rate of water vapour added TO humid air going from a State1 with humidity ratio 'w1' and State2 with humidity ratio 'w2', and with 'mDot$a' the mass flow rate of the dry air portion ("fraction"):
psy$E$mDot$wat$i[mDot$a_,w1_,w2_] := mDot$a (w2 - w1);
For the convenience of coding and modelling at higher levels (and to avoid having to use negation at higher levels), a version of the function that gives the mDot$wat$o (out) could be used. It might be tempting to implement such by just reversing the 'w1' and 'w2' as:
psy$E$mDot$wat$o[mDot$a_,w1_,w2_] := mDot$a (w1 - w2);
But what if there was an error in the rest of the formula in the above approach? You'd have to change the algebra for some reason (and potentially fiddle with the signs also) in 2 separate places, which does not respect [util: ssot_dry_]. It is also more error prone.
The policy described here, however, advocates that - given we already have mDot$wat$i
- the mDot$wat$o
should be implemented instead with reuse by introducing simple numerical negation without any more algebra:
psy$E$mDot$wat$o[mDot$a_,w1_,w2_] :=
- psy$E$mDot$wat$i[mDot$a,w1,w2];
For this very simple case it might not seem to be such a big deal, but it pays off for more complex systems.
From the SysML modelling point of view
For reasons described here (a better way using Mathematica as external maths engine is given here), each Mathematica function is encapsulated in the SysMLv1.x model as both a ConstraintBlock and a Behavior, preferably as a simple OpaqueBehavior with a simple mathematical Constraint given in an opaque language (and requiring no further modelling), or as an Activity.
In the case of the SysML Parametrics approach, a simple ConstraintBlock for psy$E$mDot$wat$i
has been used (as a constraint property) in a wrapping and negating ConstraintBlock psy$E$mDot$wat$o
together with a usage of a simple ConstraintBlock @neg
to perform the flow direction negation. Implementing the wrapping ConstraintBlock psy$E$mDot$wat$o
requires modelling of an extra SysML Parametric Diagram, but it's very simple to do.
In the case of the SysML Activities approach, a simple OpaqueBehavior for psy$E$mDotWatIn
has been used (via a CallBehaviorAction) in a wrapping and negating Activity psy$E$mDot$wat$o
together with a usage of a simple OpaqueBehavior @negQ
(that can handle a Quantity) to perform the flow direction negation.
In both cases, there is no need to "repeat and adapt" the formula algebra of the Constraint of the psy$E$mDot$wat$i
ConstraintBlock or of the 'body' of the psy$E$mDot$wat$i
OpaqueExpression. From the SysML side, it does, however, introduce this small risk:
But overall, it's well worth applying this policy strictly. At higher levels of modelling, it quickly pays off.