Community Tip - Have a PTC product question you need answered fast? Chances are someone has asked it before. Learn about the community search. X
The attached worksheet attempts to search a vector and if any values are "single" they are replaced with "group" and the value directly after it is multiplied by 2. In the attached worksheet (first attached jpeg) this doesn't work, however in a prior worksheet (second attached jpeg) it does work. Why is this?
Also, is there a function (such as an if function) that can search an entire vector for "group" and if it finds it anywhere then perform a line-by-line operation such as that above?
Solved! Go to Solution.
Here is the modified version as explained above (filterNaN before calculations) and also a variant with integrated calculation.
If you want the first "single" or all entries before the first group be handled differently, you will have to specify your needs in more detail.
Regards Werner
What is ORIGIN in each worksheet?
I'd guess that ORIGIN=1 in the sheet that works, and ORIGIN=0 (default) in the sheet that doesn't.
Thank you Mark, I mistakenly thought ORIGIN = 1 by default.
Is there a way to search an entire function for "group" similar to the unsuccessful attached?
I prefer to use the following in FOR loop declarations:
for i = ORIGIN ... last(Nn)
This will work regardless of what ORIGIN is set to, so you can copy/paste between worksheets with different ORIGIN values.
I cannot open your file because I don't have the latest version of Prime.
I think the program you used above for Nm is probably the best way to search a Matrix for a certain value.
On second thought, you might want to see if you can utilize the function "match". Depending on what you're trying to accomplish, this may be a better approach than looping through each element.
Great suggestion; I never thought of starting an index definition (is that what it is called?) with ORIGIN
It's the equivalent of
i = first(Nn)...last(Nn)
However, there is no "first" function because it would always return the value ORIGIN.
I. too, can't read 3.1 files and so hev to resort to your screen shots.
You will run into problems if one of the intial 2 x 1 vectors say ("single"; NaN) or if a ("single"; NaN) is followed in the stack by a ("single or double"; any).
So I guess it would be a better idea to filter for the NaN's after processing the stack. You could then use "match" to find all occurrences of "single" and apply your calculation to the next element in the stack.
It may also be easier to create a n x 2 matrix instead of stacking -> first column "text", second column "value". You can use the same stack command to do so but write PhiN^T, etc. So you could use one of the lookup commands to find all "singles".
Whenever you use match or lookup you should provide an error handling using try ..on error in case no match can be found.
The same applies for your use of filterNan - it will throw an error if co NaN is found!
WE
Thank you Werner. I have taken your recommendations and turned the [1x2] -> [2x1]. I wasn't able to get the match or lookup commands working. Instead I created a counter "anchor" such that if "group" is encountered in the first column then anchor >1. Is this a suitable alternative to match or lookup?
How do you define i to go to the last row? I assume my methods in Nm for changing the first value to "group" and multiplying the second column value by 2 is correct.
> How do you define i to go to the last row
last only works for (1 column) vectors. You could either use Nn<column ORIGIN> like I did in my routine below or you could also use ORIGIN+rows(Nn)-1 as end value.
I just see that your screenshot answers my question below - you don't insist on seeing the "single" ion case the value is NaN.
I also realize that it would make sense in my approach to filter the NaN's before going into the loop. It would be more efficient than processing all the NaN's just to delete them after the calculations. Nevertheless with the very few values in the vector you won't notice the difference in performance speed 😉
You can also integrate the calculation part inside of the process routine, but I thought its more clear if I separate the calculation from the loop part, making changes easier and maybe more intuitive. Your choice anyway.
Werner
EDIT: Your "anchor" should avoid processing the first "single" entry, right? This was not the case in the first screenshots you sent.
In fact this "anchor" would prevent processing ALL entries before the first "single" entry.
Is this what you intend?
If you can guarantee, that the very first entry is "single" in every case, you could do without "anchor" just by writing for i=ORIGIN+1 ...
You may get a wrong result if your matrix consists of just one single row if you do so - not sure if this may be a problem.
You also return Nn at the wrong place. The correct place is the last line of the program, after the for loop.
I guess that using match or lookup can make things harder to read so I would stay with the for loop.
Maybe something like the following could be of value:
A similar approach would be possible if you insist on the one column vector data type.
Do you really need to see the type identifier in case the value is NaN as in your original approach?
Here is the modified version as explained above (filterNaN before calculations) and also a variant with integrated calculation.
If you want the first "single" or all entries before the first group be handled differently, you will have to specify your needs in more detail.
Regards Werner
Thank you very much Werner. You’re right, if any value in the beginning [2x1] vector is NaN, the vector is not important and can be ignored.
The anchor counter was intended to be >0 if “group” is encountered in any of the vectors. The vectors at the top are the results from checking various load cases on anchors in a concrete foundation; in some cases only a single anchor is checked, in other cases 2 anchors are checked. If 2 are checked then all the single anchor values must be multiplied by 2 so that they can be compared against the “group” values. Eventually I’ll expand this to >2 anchors.
Is your practice to highlight in grey any routine that is used repeatedly? I learned a couple more tricks from your explanation; thank you.
> Is your practice to highlight in grey any routine that is used repeatedly?
I am not really consequent doing so. The intention was to highlight functions which are used/called later in contrast to "static" calculation routines.
Usually I prefer using functions even when I call them just once in a sheet. Who knows, I might be tempted to extend the sheet one day or maybe I could reuse this function in another sheet 😉
WE
Werner I will incorporate your highlighting approach. Is there a way to modify your process3(S) such that if group never appears in the first column then don't replace "single" with "group" and don't multiply the second value by 2? Attached is my attempt.
EDIT: I got it! See the attached, if interested!
Is there a way to modify your process3(S) such that if group never appears in the first column then don't replace "single" with "group" and don't multiply the second value by 2?
How about looking if the string "group" exists somewhere in the matrix (using "match") and exiting the program with the unchanged (apart from filterNaN) matrix as return value?
EDIT: Just looked at your screenshot. You have nested for-loops but they use the same count-variable i - thats a no-go!
In your case you don't need the outer loop anyway, so get rid of it.
You simply run through your matrix looking for "group" and then you go into the processing phase but only if s>0.
You could also use something like "if s=0 <then> return S" before the processing loop (a return statement exits a program) or you could at least avoid the two nested if by "AND-ing" the two constraints -> if s>0 ^ S[i,O="single" ...
Here is a variation. As we already use match, we can also use "match" to replace the if statement in the loop. We look for "single" in the first column only, the return of match is either an error, if no "single" is found (that's the reason for the "try/on error" which exits the program in that case) or a vector with the appropriate row indices. The following for-loop just loops through those indices and that way we can avoid the "if" as we are only processing the necessary lines.
The routine looks larger mainly because of the try statements.
To make it shorter, I think you can put both "match" functions within the same "try" statement:
try
match("group",S)
idx <- match("single",S<0>)
on error
return S
Clever idea 😉
This sure should work OK.
Thank you again Werner. Your program (is this proper or should it be called a routine?) has "return S" 4 times. Does this essentially make it 4 programs in one?
Can I check my understanding:
1. Remove any row with NaN regardless of NaN position in the row (interesting that this doesn't need to be iterative)
2. The 1st try looks in S for "group" anywhere in S. If it finds "group" is this somehow stored somewhere; does it create a vector/array of values?
3. The 2nd try looks for "single" in the origin column of S and if found it stores the origin column to idx.
4. The 4th component iterates from i until the last line in vector idx (if idx is created); the row is replaced with [ "group", 2x ]
A few questions:
1. What action does the 1st try perform on S if it does or doesn't find a match?
2.If "group" is not found anywhere, how does this program know not to perform step 4 above?
Daniel,
I would suggest trying each of the individual commands on various matrices (S) to get a better understanding of what they each do.
First, a few clarifications:
"filterNaN" is a built-in function that searches for any instances of NaN in the specified matrix and deletes those rows. Therefore, an iterative process is not needed to call this function (though, Mathcad likely uses an iterative process in the background). If no instances of NaN are found, Mathcad throws an error.
"match" searches for any instances of your specified value in the specified matrix and returns the index locations of all instances in the form of another matrix. If no instances of the specified value are found, Mathcad throws an error.
"return" halts the program and returns the specified value. No subsequent calculations are performed.
Now an explanation of Werner's program:
1.) redefine S as filterNaN(S) to eliminate any rows with NaN's. However, if no NaN's exist ("on error") just redefine S as itself. Werner's code is equivalent to:
try
S <- filterNaN(S)
on error
S <- S
(obviously, the "on error" code of S <- S does nothing.)
2.) Mathcad searches for the term "group" (it's looking in all columns, but you could modify so it is only looking in the first column). If it finds "group", it does nothing with that information (it just goes on to the next "try" statement). If it does not find "group", it goes to "on error" where the program is halted and S is returned without further processing (no need to modify S if none of the results are "group").
3.) Mathcad searches for the term "single" in the first column of S. If it finds "single", it stores the row numbers of all the "singles" in a new vector (idx). If it does not find "single", it goes to "on error" where the program is halted and S is returned without further processing ((no need to modify S if none of the results are "single").
4.) Mathcad only reaches this point if some results are "single" and others are "group". Now it iterates only through the rows that contain "single" because idx contains only row numbers that contain "single".
> Thank you again Werner.
You are welcome!
Mark has already answered most of your questions in detail, i guess - so just some remarks:
> Your program (is this proper or should it be called a routine?)
I eventually use both expression. Probably you should ask someone whose first language is English
> has "return S" 4 times. Does this essentially make it 4 programs in one?
I just see three return statements and they don't make it three programs in one. They just indicate three different exit points of the program/routine.
The first two can be merged into one as was pointed out by Mark and the last one would not be necessary at all - you could simply replace its by "S", because a program in Mathcad returns the last value calculated/evaluated. But I find it good behavior to use "return" in that case, too.
> 1. Remove any row with NaN regardless of NaN position in the row (interesting that this doesn't need to be iterative)
It was already said that the built-in "filterNaN" internally would use some kind of iteration anyway.
> 2. The 1st try looks in S for "group" anywhere in S. If it finds "group" is this somehow stored somewhere; does it create a vector/array of values?
Yes, the "match" command does exactly that and as I am looking in the whole 2D matrix, it creates a vector whose elements are 2 x 1 vectors with the appropriate matrix indices. All I need when I am looking for "group", though, is the part when match fails because it finds no "group" entry and via try/on error I exit the program in that case, returning S unchanged (apart from being stripped from the NaN's).
> 3. The 2nd try looks for "single" in the origin column of S and if found it stores the origin column to idx.
This time "match" just looks in the first column of S for "single" and that way it returns just a normal vector of vector indices (the row indices for "single" entries. This is exactly what could be used in a for-loop for cycling through those relevant rows only.
> 4. The 4th component iterates from i until the last line in vector idx (if idx is created); the row is replaced with [ "group", 2x ]
Correct. We don't have to ask if the entry in the first column is "single" using an if-statement - we know it has to be "single" - otherwise match would not had put that value in the idx vector.
As Mark already wrote - play around with the various match or lookup.. commands yourself, feeding those commands with different matrices to get a feeling for the mechanisms.
On thing of notice: I find it quite annoying that "filterNaN" throws an error if the provided matrix does not contain a NaN, so when I need this command more often in a sheet, I usually redefine this command (in a collapsed area) so it returns the matrix unchanged in case no NaN is present (maybe it would be good behavior to use "return M" instead of just M 😉 :
Regards,
Werner