Calculator: multiple variable coding question

Could someone help me to explain how one could write a (function node) code with multiple variables that are entered from a text field in the UI?

I would like to make a dilution calculator for my student (I am a chemist).
The main formula is as follows:
C1 * V1 = C2 * V2

The variables could be written down as followed:
C1=((C2*V2) / (V1))

V1=((C2*V2) / (C1))

C2=((C1*V1) / (V2))

V2=((C1*V1) / (C2))

All the variables should be known except the one before the equal mark.
example:
V2=((C1*V1)/(C2))

(Background info for fun)
I took a volume of 1 litre (V1) that contains a concentration of 100 grams per litre (C1)
I would like to end with a concentration of 25 grams per litre (C2). What is the final volume after dilution? (V2)

I am not sure exactly what you are asking, but possibly what you are looking for is the ui_form node, which allows you have multiple fields in which the numbers could be entered, and all get passed to the next node when the Submit button is hit.

I re-read my question and made a little edit. It was a bit vague, sorry.
My problem: I don't know how to write the code that should solve the equations.

May be something like this, leave the field you want answered empty

[{"id":"502b7419641df689","type":"inject","z":"bf9e1e33.030598","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"V1\":100,\"C1\":100,\"C2\":25,\"V2\":null}","payloadType":"json","x":130,"y":140,"wires":[["62f0b8d9.0608c"]]},{"id":"62f0b8d9.0608c","type":"ui_form","z":"bf9e1e33.030598","name":"","label":"","group":"2d4fe667.28f8ba","order":22,"width":0,"height":0,"options":[{"label":"S Volume","value":"V1","type":"number","required":false,"rows":null},{"label":"S Concentration","value":"C1","type":"number","required":false,"rows":null},{"label":"F Concentration","value":"C2","type":"number","required":false,"rows":null},{"label":"F Volume","value":"V2","type":"number","required":false,"rows":null}],"formValue":{"V1":"","C1":"","C2":"","V2":""},"payload":"","submit":"submit","cancel":"Reset","topic":"topic","topicType":"msg","splitLayout":"","className":"","x":220,"y":100,"wires":[["a0537cfa.753e3"]]},{"id":"a0537cfa.753e3","type":"function","z":"bf9e1e33.030598","name":"","func":"const formula = Object.keys(msg.payload).filter(e => !msg.payload[e]) \nif(formula.length === 1){\nswitch(formula[0]) {\n  case \"C1\":\n    msg.payload.C1 = ((msg.payload.C2*msg.payload.V2) / (msg.payload.V1));\n    break;\n  case \"V1\":\n    msg.payload.V1 = ((msg.payload.C2*msg.payload.V2) / (msg.payload.C1));\n    break;\n  case \"C2\":\n      msg.payload.C2 = ((msg.payload.C1*msg.payload.V1) / (msg.payload.V2));\n      break;\n  case \"V2\":\n      msg.payload.V2 = ((msg.payload.C1*msg.payload.V1) / (msg.payload.C2));\n      break;\n  default:\n    msg.payload.C1 = \"Error\";\n  }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":340,"y":140,"wires":[["8ad333f6.78443","62f0b8d9.0608c"]]},{"id":"8ad333f6.78443","type":"debug","z":"bf9e1e33.030598","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":560,"y":140,"wires":[]},{"id":"2d4fe667.28f8ba","type":"ui_group","name":"demo","tab":"1caa8458.b17814","order":1,"disp":true,"width":"12","collapse":false},{"id":"1caa8458.b17814","type":"ui_tab","name":"Demo","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

the function looks for the payload property key that is null.
[edit] added a check for atleast 3 values.

I think there are only two different cases: where the final volume is unknown and where the final concentration is unknown.

So a function node to do the calculation might be like this

var result;

if (msg.hasOwnProperty('FinalConc')) {
    result = msg.InitialConc * msg.InitialVol / msg.FinalConc;
}
else if (msg.hasOwnProperty('FinalVol')) {
    result = msg.InitialConc * msg.InitialVol / msg.FinalVol;
}
msg.payload = result;
return msg;

If you suggest that the calculator needs to handle a question like "I diluted a solution from 1litre to 1.6litre. It's was then 0.7 Molar. What was the original concentration", it can:
InitialVol = 1.6, InitialConc = 0.7, FInalVol = 1

You should of course check that all values are numeric and the denominator is not zero.

This is brilliant! Thanks!

Now a method to not-change-the-results once the submit button is pressed :thinking: (the answer field i mean)

I am thinking of making 3 or 4 squares with infill fields.. each for another form of the equation.

C1=((C2*V2) / (V1))

V1=((C2*V2) / (C1))

C2=((C1*V1) / (V2))

V2=((C1*V1) / (C2))

Maybe then I can get the number to be unchangeable? or am I thinking wrong

Not sure what you mean, once you press submit and the answer is given, even if you press submit again the fields keep their values.

I can manually type something different in the answer field after pressing submit!

i will describe what I did to explain what I mean =D

step 1 fill in and leave 1 blank
image

Step 2, pressed submit (and your wonderfull calc works! i am so happy)
image

Step 3 "be an annoying student of the teacher and change numbers"
image

Step 4.... Students will use this to get away with stuff hahaha i know how inventive they are

Pressing submit after step 3 will not change anything so a fool could assume it to be correct =D

Ok I see. Store the values when the calc has been completed then the values will return if submitted again. Then later flow you can then retrieve them
eg.

[{"id":"502b7419641df689","type":"inject","z":"bf9e1e33.030598","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"V1\":100,\"C1\":100,\"C2\":25,\"V2\":null}","payloadType":"json","x":130,"y":140,"wires":[["62f0b8d9.0608c"]]},{"id":"62f0b8d9.0608c","type":"ui_form","z":"bf9e1e33.030598","name":"","label":"","group":"2d4fe667.28f8ba","order":22,"width":0,"height":0,"options":[{"label":"S Volume","value":"V1","type":"number","required":false,"rows":null},{"label":"S Concentration","value":"C1","type":"number","required":false,"rows":null},{"label":"F Concentration","value":"C2","type":"number","required":false,"rows":null},{"label":"F Volume","value":"V2","type":"number","required":false,"rows":null}],"formValue":{"V1":"","C1":"","C2":"","V2":""},"payload":"","submit":"submit","cancel":"Reset","topic":"topic","topicType":"msg","splitLayout":"","className":"","x":220,"y":100,"wires":[["a0537cfa.753e3"]]},{"id":"a0537cfa.753e3","type":"function","z":"bf9e1e33.030598","name":"","func":"const formula = Object.keys(msg.payload).filter(e => !msg.payload[e]) \nif(formula.length === 1){\nswitch(formula[0]) {\n  case \"C1\":\n    msg.payload.C1 = ((msg.payload.C2*msg.payload.V2) / (msg.payload.V1));\n    break;\n  case \"V1\":\n    msg.payload.V1 = ((msg.payload.C2*msg.payload.V2) / (msg.payload.C1));\n    break;\n  case \"C2\":\n      msg.payload.C2 = ((msg.payload.C1*msg.payload.V1) / (msg.payload.V2));\n      break;\n  case \"V2\":\n      msg.payload.V2 = ((msg.payload.C1*msg.payload.V1) / (msg.payload.C2));\n      break;\n  default:\n    msg.payload.C1 = \"Error\";\n  }\ncontext.set(\"value_store\", msg.payload)\nmsg.values = msg.payload;\n}else{\n    msg.payload = context.get(\"value_store\");\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":340,"y":140,"wires":[["8ad333f6.78443","62f0b8d9.0608c"]]},{"id":"8ad333f6.78443","type":"debug","z":"bf9e1e33.030598","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":520,"y":140,"wires":[]},{"id":"2d4fe667.28f8ba","type":"ui_group","name":"demo","tab":"1caa8458.b17814","order":1,"disp":true,"width":"12","collapse":false},{"id":"1caa8458.b17814","type":"ui_tab","name":"Demo","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

msg.values now holds the inputted values for further processing.

How are you so quick with this?
Marvelous!

Have you ever watched Rainman (joke, i function extremely well) If you have an inventive student, challenge them with harder tasks.

1 Like

Hahahaha yes, I do and I understand the reference :smiley:

speaking of references....

Are you up for a bigger challenge?

I never answer yes to questions like that, but maybe.

Mark this a solution (if it is) then make a new topic for any new questions. It will make it easier for people in future to find solutions.

Sure!

I Can't seem to send you a dm as your profile is hidden. How should I contact you?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.