How to calculate a function with different equations depending on different ranges?

Question:

I am trying to calculate this equation in python.

Equation

However I seem to be unable to perform the logic operation as had to use array in np to create the decimal range.

I wonder if there is an alternative method of creating the range without np, or an alternative method of perform logic on this.

I would appreciate help on this problem as I am still learning, thank you!

This is what I’ve tried below.
Although I am getting a syntax error:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Did try np.logical_and without success.

# Cardiac Elastance and Compliance Calculation

import numpy as np

# Timestep for one cardiac cycle
# Creates from 0 to 1 spaced by 0.02
x = np.linspace(0, 1, num=51)

# Time of ventricular contraction and relaxation
T_vc = 0.25
T_vr = 0.125

#Ventricles 
def vent_elastance(x):
    if x >= 0 and x <= T_vc:
        return 0.5 - 0.5 * cos(pi*x/T_vc)
    #elif x > T_vc and  x <= (T_vc + T_vr):
        #return 0.5 + 0.5 * cos (pi * (x-T_vc) / T_vr )
    #else:
        #return 0

y = vent_elastance(x)
Asked By: 3nhu1

||

Answers:

The syntax error is with the ‘if’ statement.
try if x >= 0 and x <= T_vc: and then the code. No, I don’t think this is possible outside NumPy, but this is a bit outside my skill set. Judging from the equation, I’d say just use NumPy.

Answered By: user20624405

The equation you’ve shown says that e_v is calculated using a different expression for different values of x (or t in the screenshot). To do this, you can initialize the result array to an array of zeros (or nans, if you want), and then fill the values corresponding to each group of x using the expression for that group. Numpy’s vectorized math capabilities make this approach significantly faster than the other answers that iterate over the array and calculate each element individually.

def vent_elastance(x):
    result = np.zeros_like(x)
    # Create a boolean mask for elements of x that fulfill the first condition
    condition1 = (x >= 0) & (x <= T_vc)
    # Calculate the first expression for values of x that satisfy that condition, 
    # Then set only those values of the result
    result[condition1] = 0.5 * (1 - np.cos(np.pi * x[condition1] / T_vc))

    # Do the same for the second condition
    condition2 = (x > T_vc) & (x <= T_vr + T_vc)
    result[condition2] = 0.5 * (1 + np.cos(np.pi * (x[condition2] - T_vc) / T_vr))

    # Don't need condition3 because it's zero anyway

    return result

Comparing the runtimes of the different approaches, we see that the vectorized numpy approach clearly beats Ori’s list comprehension and user19077881’s for loop when the input x is larger than ~100 elements. Here, I defined x as np.linspace(0, 1, N), where N is the input size shown on the x-axis.

Runtime comparison plot

Answered By: Pranav Hosangadi

You need to be clear if you are dealing with a List of values or values in sequence. This answer deals with the values one at a time; other answer operate on the whole array at once :

# Cardiac Elastance and Compliance Calculation

import numpy as np
import math as m

# Timestep for one cardiac cycle
# Creates from 0 to 1 spaced by 0.02
x = np.linspace(0, 1, num=51)

# Time of ventricular contraction and relaxation
T_vc = 0.25
T_vr = 0.125

#Ventricles
def vent_elastance(xlist):
    result = []
    for t in xlist:
        if t >= 0 and t <= T_vc:
             result.append(0.5 - 0.5 * m.cos(m.pi*t/T_vc))
    
        elif t > T_vc and  t <= (T_vc + T_vr):
            result.append(0.5 + 0.5 * m.cos (m.pi * (t-T_vc) / T_vr ))
            
        else:
            result.append(0)
    return result

y = vent_elastance(x)
print(y)
Answered By: user19077881

Use the function with list comprehension:

import numpy as np

# Timestep for one cardiac cycle
# Creates from 0 to 1 spaced by 0.02
x = np.linspace(0, 1, num=51)
# Time of ventricular contraction and relaxation
T_vc = 0.25
T_vr = 0.125

#Ventricles 
def vent_elastance(x):
    if x >= 0 and x <= T_vc:
        return 0.5 - 0.5 * np.cos(np.pi*x/T_vc)
    
    elif x > T_vc and  x <= (T_vc + T_vr):
        return 0.5 + 0.5 * np.cos(np.pi * (x-T_vc) / T_vr )
    
    else:
        return 0

y = [vent_elastance(_x) for _x in x]
print(y)

Outputs:

[0.0, 0.015708419435684462, 0.06184665997806821, 0.13551568628929422, 0.23208660251050173, 0.3454915028125263, 0.46860474023534326, 0.5936906572928624, 0.7128896457825363, 0.8187119948743449, 0.9045084971874737, 0.9648882429441257, 0.9960573506572389, 0.9842915805643155, 0.8644843137107056, 0.6545084971874738, 0.4063093427071376, 0.18128800512565496, 0.03511175705587444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Also, you could just vectorize the function:

vent_elastance = np.vectorize(vent_elastance)
y = vent_elastance(x)
Answered By: Ori Yarden

I’ve also just managed to do it like this, so happy to have learnt all the ways

import math

#Timestep for one cardiac cycle
#Creates from 0 to 1 spaced by 0.02

x = [i/100 for i in range(0, 102, 2)]

#Time of ventricular contraction and relaxation

T_vc = 0.25

T_vr = 0.125


#Ventricles 
def vent_elastance(x):

    if x >= 0 and x <= T_vc:
        return 0.5 - 0.5 * math.cos(math.pi*x/T_vc)

    elif x > T_vc and  x <= (T_vc + T_vr):
        return 0.5 + 0.5 * math.cos (math.pi * (x-T_vc) / T_vr )
    
    else:
        return 0

print([vent_elastance(i) for i in x])
Answered By: 3nhu1

My understanding is that you would like to use vent_elastance on each element of x and y will be the vector built out of these elements. On the syntax errors:
instead of if x >= 0 and x <= T_vc you need if x >= 0 and x <= T_vc: trailing : is always required for if statements. cos and pi are not in python by default, they have to be imported.
My code:

# Cardiac Elastance and Compliance Calculation

import numpy as np
from math import cos, pi

# Timestep for one cardiac cycle
# Creates from 0 to 1 spaced by 0.02

x = np.linspace(0, 1, num=51)

# Time of ventricular contraction and relaxation

T_vc = 0.25

T_vr = 0.125


#Ventricles
def vent_elastance(x):
    if x >= 0 and x <= T_vc:
        return 0.5 - 0.5 * cos(pi*x/T_vc)

    elif x > T_vc and  x <= (T_vc + T_vr):
        return 0.5 + 0.5 * cos (pi * (x-T_vc) / T_vr )

    else:
        return 0

y = np.vectorize(vent_elastance)(x)
print(y)

output:

[0.         0.01570842 0.06184666 0.13551569 0.2320866  0.3454915
 0.46860474 0.59369066 0.71288965 0.81871199 0.9045085  0.96488824
 0.99605735 0.98429158 0.86448431 0.6545085  0.40630934 0.18128801
 0.03511176 0.         0.         0.         0.         0.
 0.         0.         0.         0.         0.         0.
 0.         0.         0.         0.         0.         0.
 0.         0.         0.         0.         0.         0.
 0.         0.         0.         0.         0.         0.
 0.         0.         0.        ]
Answered By: Cryptolis
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.