コード例 #1
0
    def check_periodic(self, varTc, varTc_old, eps, check, cyclerr):
        
        if isinstance(varTc, np.ndarray): varTc_sq, varTc_old_sq = varTc, varTc_old
        else: varTc_sq, varTc_old_sq = allgather_vec(varTc, self.comm), allgather_vec(varTc_old, self.comm)

        if check=='allvar':
            
            vals = []
            for i in range(len(varTc_sq)):
                vals.append( math.fabs((varTc_sq[i]-varTc_old_sq[i])/max(1.0,math.fabs(varTc_old_sq[i]))) )

        elif check=='pQvar':
            
            vals = []
            pQvar_ids = [1-self.si[2],3-self.si[0],4,6,10-self.si[3],12-self.si[1],13,15]
            for i in range(len(varTc_sq)):
                if i in pQvar_ids:
                    vals.append( math.fabs((varTc_sq[i]-varTc_old_sq[i])/max(1.0,math.fabs(varTc_old_sq[i]))) )

        else:
            
            raise NameError("Unknown check option!")

        cyclerr[0] = max(vals)

        if cyclerr[0] <= eps:
            is_periodic = True
        else:
            is_periodic = False
        
        return is_periodic
コード例 #2
0
ファイル: cardiovascular0D.py プロジェクト: dbaroli/ambit
    def write_initial(self, path, nm, varTc_old, varTc):

        if isinstance(varTc_old, np.ndarray):
            varTc_old_sq, varTc_sq = varTc_old, varTc
        else:
            varTc_old_sq, varTc_sq = allgather_vec(varTc_old,
                                                   self.comm), allgather_vec(
                                                       varTc, self.comm)

        if self.comm.rank == 0:

            filename1 = path + '/initial_data_' + nm + '_Tstart.txt'  # conditions at beginning of cycle
            f1 = open(filename1, 'wt')
            filename2 = path + '/initial_data_' + nm + '_Tend.txt'  # conditions at end of cycle
            f2 = open(filename2, 'wt')

            for i in range(len(self.varmap)):

                f1.write('%s %.16E\n' %
                         (list(self.varmap.keys())[i] + '_0',
                          varTc_old_sq[list(self.varmap.values())[i]]))
                f2.write('%s %.16E\n' %
                         (list(self.varmap.keys())[i] + '_0', varTc_sq[list(
                             self.varmap.values())[i]]))

            f1.close()
            f2.close()
コード例 #3
0
    def print_to_screen(self, var, aux):

        if isinstance(var, np.ndarray): var_sq = var
        else: var_sq = allgather_vec(var, self.comm)

        nc = len(self.c_)

        if self.comm.rank == 0:

            print("Output of 0D vascular model (syspul):")

            for i in range(nc):
                print('{:<9s}{:<3s}{:<10.3f}'.format(
                    list(self.auxmap.keys())[i], ' = ',
                    aux[list(self.auxmap.values())[i]]))

            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format(
                '' + self.vname_prfx[2] + '_at_l', ' = ',
                var_sq[self.varmap['' + self.vname_prfx[2] + '_at_l']], '   ',
                '' + self.vname_prfx[3] + '_at_r', ' = ',
                var_sq[self.varmap['' + self.vname_prfx[3] + '_at_r']]))
            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format(
                '' + self.vname_prfx[0] + '_v_l', ' = ',
                var_sq[self.varmap['' + self.vname_prfx[0] + '_v_l']], '   ',
                '' + self.vname_prfx[1] + '_v_r', ' = ',
                var_sq[self.varmap['' + self.vname_prfx[1] + '_v_r']]))

            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format(
                'p_ar_sys', ' = ', var_sq[self.varmap['p_ar_sys']], '   ',
                'p_ar_pul', ' = ', var_sq[self.varmap['p_ar_pul']]))
            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format(
                'p_ven_sys', ' = ', var_sq[self.varmap['p_ven_sys']], '   ',
                'p_ven_pul', ' = ', var_sq[self.varmap['p_ven_pul']]))

            sys.stdout.flush()
コード例 #4
0
ファイル: cardiovascular0D.py プロジェクト: dbaroli/ambit
    def write_output(self, path, t, var, aux, nm=''):

        if isinstance(var, np.ndarray): var_sq = var
        else: var_sq = allgather_vec(var, self.comm)

        # mode: 'wt' generates new file, 'a' appends to existing one
        if self.init: mode = 'wt'
        else: mode = 'a'

        self.init = False

        if self.comm.rank == 0:

            for i in range(len(self.varmap)):

                filename = path + '/results_' + nm + '_' + list(
                    self.varmap.keys())[i] + '.txt'
                f = open(filename, mode)

                f.write('%.16E %.16E\n' %
                        (t, var_sq[list(self.varmap.values())[i]]))

                f.close()

            for i in range(len(self.auxmap)):

                filename = path + '/results_' + nm + '_' + list(
                    self.auxmap.keys())[i] + '.txt'
                f = open(filename, mode)

                f.write('%.16E %.16E\n' %
                        (t, aux[list(self.auxmap.values())[i]]))

                f.close()
コード例 #5
0
    def check_periodic(self, varTc, varTc_old, eps, check, cyclerr):

        if isinstance(varTc, np.ndarray):
            varTc_sq, varTc_old_sq = varTc, varTc_old
        else:
            varTc_sq, varTc_old_sq = allgather_vec(varTc,
                                                   self.comm), allgather_vec(
                                                       varTc_old, self.comm)

        if check == 'allvar':

            vals = []
            for i in range(len(varTc_sq)):
                vals.append(
                    math.fabs((varTc_sq[i] - varTc_old_sq[i]) /
                              max(1.0, math.fabs(varTc_old_sq[i]))))

        elif check == 'pQvar':

            vals = []
            pQvar_ids = [
                self.varmap['' + self.vname_prfx[2] + '_at_l'],
                self.varmap['' + self.vname_prfx[0] + '_v_l'],
                self.varmap['p_ar_sys'], self.varmap['p_ven_sys'],
                self.varmap['' + self.vname_prfx[3] + '_at_r'],
                self.varmap['' + self.vname_prfx[1] + '_v_r'],
                self.varmap['p_ar_pul'], self.varmap['p_ven_pul']
            ]
            for i in range(len(varTc_sq)):
                if i in pQvar_ids:
                    vals.append(
                        math.fabs((varTc_sq[i] - varTc_old_sq[i]) /
                                  max(1.0, math.fabs(varTc_old_sq[i]))))

        else:

            raise NameError("Unknown check option!")

        cyclerr[0] = max(vals)

        if cyclerr[0] <= eps:
            is_periodic = True
        else:
            is_periodic = False

        return is_periodic
コード例 #6
0
    def print_to_screen(self, var, aux):

        if isinstance(var, np.ndarray): var_sq = var
        else: var_sq = allgather_vec(var, self.comm)

        if self.comm.rank == 0:

            print("Output of 0D model (2elwindkessel):")

            print('{:<1s}{:<3s}{:<10.3f}'.format(self.cname, ' = ', aux[0]))
            print('{:<1s}{:<3s}{:<10.3f}'.format(self.vname, ' = ', var_sq[0]))

            sys.stdout.flush()
コード例 #7
0
    def print_to_screen(self, x, a):

        if isinstance(x, np.ndarray): x_sq = x
        else: x_sq = allgather_vec(x, self.comm)

        if self.comm.rank == 0:

            print("Output of 0D model (4elwindkesselLsZ):")

            print('{:<1s}{:<3s}{:<10.3f}'.format(self.cname, ' = ', a[0]))

            print('{:<1s}{:<3s}{:<10.3f}'.format('p', ' = ', x_sq[0]))
            print('{:<1s}{:<3s}{:<10.3f}'.format('q', ' = ', x_sq[1]))

            sys.stdout.flush()
コード例 #8
0
ファイル: cardiovascular0D.py プロジェクト: dbaroli/ambit
    def write_restart(self, path, nm, N, var):

        if isinstance(var, np.ndarray): var_sq = var
        else: var_sq = allgather_vec(var, self.comm)

        if self.comm.rank == 0:

            filename = path + '/checkpoint_' + nm + '_' + str(N) + '.txt'
            f = open(filename, 'wt')

            for i in range(len(var_sq)):

                f.write('%.16E\n' % (var_sq[i]))

            f.close()
コード例 #9
0
    def evaluate(self,
                 x,
                 t,
                 df=None,
                 f=None,
                 dK=None,
                 K=None,
                 c=[],
                 y=[],
                 a=None,
                 fnc=[]):

        if isinstance(x, np.ndarray): x_sq = x
        else: x_sq = allgather_vec(x, self.comm)

        # ODE lhs (time derivative) residual part df
        if df is not None:

            for i in range(self.numdof):
                df[i] = self.df__[i](x_sq, c, t, fnc)

        # ODE rhs residual part f
        if f is not None:

            for i in range(self.numdof):
                f[i] = self.f__[i](x_sq, c, t, fnc)

        # ODE lhs (time derivative) stiffness part dK (ddf/dx)
        if dK is not None:

            for i in range(self.numdof):
                for j in range(self.numdof):
                    dK[i, j] = self.dK__[i][j](x_sq, c, t, fnc)

        # ODE rhs stiffness part K (df/dx)
        if K is not None:

            for i in range(self.numdof):
                for j in range(self.numdof):
                    K[i, j] = self.K__[i][j](x_sq, c, t, fnc)

        # auxiliary variable vector a (for post-processing or periodic state check)
        if a is not None:

            for i in range(self.numdof):
                a[i] = self.a__[i](x_sq, c, t, fnc)
コード例 #10
0
    def print_to_screen(self, var, aux):
        
        if isinstance(var, np.ndarray): var_sq = var
        else: var_sq = allgather_vec(var, self.comm)

        if self.comm.rank == 0:
            
            print("Output of 0D vascular model (syspul_veins):")
            
            print('{:<9s}{:<3s}{:<10.1f}{:<3s}{:<9s}{:<3s}{:<10.1f}'.format(''+self.cname_prfx[2]+'_at_l',' = ',aux[0],'   ',''+self.cname_prfx[3]+'_at_r',' = ',aux[9]))
            print('{:<9s}{:<3s}{:<10.1f}{:<3s}{:<9s}{:<3s}{:<10.1f}'.format(''+self.cname_prfx[0]+'_v_l',' = ',aux[2],'   ',''+self.cname_prfx[1]+'_v_r',' = ',aux[11]))
            
            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format(''+self.vname_prfx[2]+'_at_l',' = ',var_sq[1-self.si[2]],'   ',''+self.vname_prfx[3]+'_at_r',' = ',var_sq[10-self.si[3]]))
            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format(''+self.vname_prfx[0]+'_v_l',' = ',var_sq[3-self.si[0]],'   ',''+self.vname_prfx[1]+'_v_r',' = ',var_sq[12-self.si[1]]))
            
            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format('p_ar_sys',' = ',var_sq[4],'   ','p_ar_pul',' = ',var_sq[13]))
            print('{:<9s}{:<3s}{:<10.3f}{:<3s}{:<9s}{:<3s}{:<10.3f}'.format('p_ven_sys',' = ',var_sq[6],'   ','p_ven_pul',' = ',var_sq[15]))

            sys.stdout.flush()
コード例 #11
0
def results_check_vec(vec, vec_corr, comm, tol=1.0e-6):

    success = True

    vec_sq = allgather_vec(vec, comm)

    errs = np.zeros(len(vec_sq))

    for i in range(len(vec_sq)):
        errs[i] = abs(vec_sq[i] - vec_corr[i])
        if errs[i] > tol:
            success = False

    for i in range(len(vec_sq)):
        if comm.rank == 0:
            print("vec[%i]    = %.16E,    CORR = %E,    err = %E" %
                  (i, vec_sq[i], vec_corr[i], errs[i]))
            sys.stdout.flush()

    return success
コード例 #12
0
ファイル: cardiovascular0D.py プロジェクト: dbaroli/ambit
    def evaluate(self,
                 x,
                 dt,
                 t,
                 df=None,
                 f=None,
                 K=None,
                 c=[],
                 y=[],
                 a=None,
                 fnc=[]):

        if isinstance(x, np.ndarray): x_sq = x
        else: x_sq = allgather_vec(x, self.comm)

        # rhs part df
        if df is not None:

            for i in range(self.numdof):
                df[i] = self.df__[i](x_sq, c, t, fnc)

        # rhs part f
        if f is not None:

            for i in range(self.numdof):
                f[i] = self.f__[i](x_sq, c, t, fnc)

        # stiffness matrix K
        if K is not None:

            for i in range(self.numdof):
                for j in range(self.numdof):
                    K[i, j] = self.Kdf__[i][j](
                        x_sq, c, t, fnc) / dt + self.Kf__[i][j](
                            x_sq, c, t, fnc) * self.theta

        # auxiliary variable vector a (for post-processing or periodic state check)
        if a is not None:

            for i in range(self.numdof):
                a[i] = self.a__[i](x_sq, c, t, fnc)
コード例 #13
0
def results_check_node(u, check_node, u_corr, V, comm, tol=1.0e-6, nm='vec'):

    success = True

    # block size of vector to check
    bs = u.vector.getBlockSize()

    # computed errors (difference between simulation and expected results)
    errs = np.zeros(bs * len(check_node))

    # dof coordinates
    co = V.tabulate_dof_coordinates()

    # index map
    im = V.dofmap.index_map.global_indices()

    # in parallel, dof indices can be ordered differently, so we need to check the position of the node in the
    # re-ordered local co array and then grep out the corresponding dof index from the index map
    dof_indices, dof_indices_gathered = {}, []
    for i in range(len(check_node)):

        ind = np.where((np.round(check_node[i],
                                 8) == np.round(co, 8)).all(axis=1))[0]

        if len(ind): dof_indices[i] = im[ind[0]]

    # gather indices
    dof_indices_gathered = comm.allgather(dof_indices)

    # make a flat and ordered list of indices (may still have duplicates)
    dof_indices_flat = []
    for i in range(len(check_node)):

        for l in range(len(dof_indices_gathered)):
            if i in dof_indices_gathered[l].keys():
                dof_indices_flat.append(dof_indices_gathered[l][i])

    # create unique list (remove duplicates, but keep order)
    dof_indices_unique = list(dict.fromkeys(dof_indices_flat))

    # gather vector to check
    u_sq = allgather_vec(u.vector, comm)

    for i in range(len(check_node)):
        for j in range(bs):
            errs[bs * i + j] = abs(u_sq[bs * dof_indices_unique[i] + j] -
                                   u_corr[bs * i + j])
            if errs[bs * i + j] > tol:
                success = False

    for i in range(len(check_node)):
        for j in range(bs):
            if comm.rank == 0:
                print("" + nm +
                      "[%i]    = %.16E,    CORR = %.16E,    err = %.16E" %
                      (bs * i + j, u_sq[bs * dof_indices_unique[i] + j],
                       u_corr[bs * i + j], errs[bs * i + j]))
                sys.stdout.flush()

    if comm.rank == 0:
        print("Max error: %E" % (max(errs)))
        sys.stdout.flush()

    return success
コード例 #14
0
ファイル: solid_constraint.py プロジェクト: dbaroli/ambit
    def solve_problem(self):

        start = time.time()

        # print header
        utilities.print_problem(self.pb.problem_physics, self.pb.pbs.comm,
                                self.pb.pbs.ndof)

        # read restart information
        if self.pb.pbs.restart_step > 0:
            self.pb.pbs.io.readcheckpoint(self.pb.pbs,
                                          self.pb.pbs.restart_step)
            self.pb.pbs.simname += '_r' + str(self.pb.pbs.restart_step)

        self.pb.set_pressure_fem(self.pb.lm_old, self.pb.coupfuncs_old)

        # in case we want to prestress with MULF (Gee et al. 2010) prior to solving the 3D-0D problem
        if self.pb.pbs.prestress_initial and self.pb.pbs.restart_step == 0:
            # solve solid prestress problem
            self.solverprestr.solve_initial_prestress()
            del self.solverprestr
        else:
            # set flag definitely to False if we're restarting
            self.pb.pbs.prestress_initial = False

        self.pb.constr, self.pb.constr_old = [], []
        for i in range(self.pb.num_coupling_surf):
            lm_sq, lm_old_sq = allgather_vec(self.pb.lm,
                                             self.pb.comm), allgather_vec(
                                                 self.pb.lm_old, self.pb.comm)
            con = assemble_scalar(self.pb.cq[i])
            con = self.pb.pbs.comm.allgather(con)
            self.pb.constr.append(sum(con))
            self.pb.constr_old.append(sum(con))

        # consider consistent initial acceleration
        if self.pb.pbs.timint != 'static' and self.pb.pbs.restart_step == 0:
            # weak form at initial state for consistent initial acceleration solve
            weakform_a = self.pb.pbs.deltaW_kin_old + self.pb.pbs.deltaW_int_old - self.pb.pbs.deltaW_ext_old - self.pb.work_coupling_old

            jac_a = derivative(weakform_a, self.pb.pbs.a_old,
                               self.pb.pbs.du)  # actually linear in a_old

            # solve for consistent initial acceleration a_old
            self.solnln.solve_consistent_ini_acc(weakform_a, jac_a,
                                                 self.pb.pbs.a_old)

        # write mesh output
        self.pb.pbs.io.write_output(self.pb.pbs, writemesh=True)

        # solid constraint main time loop
        for N in range(self.pb.pbs.restart_step + 1,
                       self.pb.pbs.numstep_stop + 1):

            wts = time.time()

            # current time
            t = N * self.pb.pbs.dt

            # set time-dependent functions
            self.pb.pbs.ti.set_time_funcs(self.pb.pbs.ti.funcs_to_update,
                                          self.pb.pbs.ti.funcs_to_update_vec,
                                          t)

            # take care of active stress
            if self.pb.pbs.have_active_stress and self.pb.pbs.active_stress_trig == 'ode':
                self.pb.pbs.evaluate_active_stress_ode(t)

            # solve
            self.solnln.newton(self.pb.pbs.u,
                               self.pb.pbs.p,
                               self.pb.lm,
                               t,
                               locvar=self.pb.pbs.theta,
                               locresform=self.pb.pbs.r_growth,
                               locincrform=self.pb.pbs.del_theta)

            # update time step
            self.pb.pbs.ti.update_timestep(
                self.pb.pbs.u, self.pb.pbs.u_old, self.pb.pbs.v_old,
                self.pb.pbs.a_old, self.pb.pbs.p, self.pb.pbs.p_old,
                self.pb.pbs.internalvars, self.pb.pbs.internalvars_old,
                self.pb.pbs.ti.funcs_to_update,
                self.pb.pbs.ti.funcs_to_update_old,
                self.pb.pbs.ti.funcs_to_update_vec,
                self.pb.pbs.ti.funcs_to_update_vec_old)

            # update old pressures on solid
            self.pb.lm.assemble(), self.pb.lm_old.axpby(1.0, 0.0, self.pb.lm)
            self.pb.set_pressure_fem(self.pb.lm_old, self.pb.coupfuncs_old)
            # update old 3D constraint variable
            for i in range(self.pb.num_coupling_surf):
                self.pb.constr_old[i] = self.pb.constr[i]

            # solve time for time step
            wte = time.time()
            wt = wte - wts

            # print time step info to screen
            self.pb.pbs.ti.print_timestep(N, t, wt=wt)

            # write output and restart info
            self.pb.pbs.io.write_output(self.pb.pbs, N=N, t=t)

        if self.pb.comm.rank == 0:  # only proc 0 should print this
            print('Time for computation: %.4f s (= %.2f min)' %
                  (time.time() - start, (time.time() - start) / 60.))
            sys.stdout.flush()
コード例 #15
0
ファイル: fluid_flow0d.py プロジェクト: dbaroli/ambit
    def solve_problem(self):

        start = time.time()

        # print header
        utilities.print_problem(self.pb.problem_physics, self.pb.pbs.comm,
                                self.pb.pbs.ndof)

        # read restart information
        if self.pb.pbs.restart_step > 0:
            self.pb.pbs.io.readcheckpoint(self.pb.pbs,
                                          self.pb.pbs.restart_step)
            self.pb.pbf.readrestart(self.pb.pbs.simname,
                                    self.pb.pbs.restart_step)
            self.pb.pbs.simname += '_r' + str(self.pb.pbs.restart_step)

        # set pressure functions for old state - s_old already initialized by 0D flow problem
        if self.pb.coupling_type == 'monolithic_direct':
            self.pb.pbf.cardvasc0D.set_pressure_fem(
                self.pb.pbf.s_old, self.pb.pbf.cardvasc0D.v_ids, self.pb.pr0D,
                self.pb.coupfuncs_old)

        if self.pb.coupling_type == 'monolithic_lagrange':
            self.pb.pbf.cardvasc0D.set_pressure_fem(
                self.pb.lm_old, list(range(self.pb.num_coupling_surf)),
                self.pb.pr0D, self.pb.coupfuncs_old)

        if self.pb.coupling_type == 'monolithic_direct':
            # old 3D coupling quantities (volumes or fluxes)
            for i in range(self.pb.num_coupling_surf):
                cq = assemble_scalar(self.pb.cq_old[i])
                cq = self.pb.pbs.comm.allgather(cq)
                self.pb.pbf.c.append(sum(cq) * self.pb.cq_factor[i])

        if self.pb.coupling_type == 'monolithic_lagrange':
            for i in range(self.pb.num_coupling_surf):
                lm_sq, lm_old_sq = allgather_vec(self.pb.lm,
                                                 self.pb.comm), allgather_vec(
                                                     self.pb.lm_old,
                                                     self.pb.comm)
                self.pb.pbf.c.append(lm_sq[i])
                con = assemble_scalar(self.pb.cq_old[i])
                con = self.pb.pbs.comm.allgather(con)
                self.pb.constr.append(sum(con) * self.pb.cq_factor[i])
                self.pb.constr_old.append(sum(con) * self.pb.cq_factor[i])

        if bool(self.pb.pbf.chamber_models):
            self.pb.pbf.y = []
            for ch in self.pb.pbf.chamber_models:
                if self.pb.pbf.chamber_models[ch]['type'] == '0D_elast':
                    self.pb.pbf.y.append(
                        self.pb.pbs.ti.timecurves(
                            self.pb.pbf.chamber_models[ch]['activation_curve'])
                        (self.pb.pbs.t_init))

        # initially evaluate 0D model at old state
        self.pb.pbf.cardvasc0D.evaluate(self.pb.pbf.s_old, self.pb.pbs.dt,
                                        self.pb.pbs.t_init, self.pb.pbf.df_old,
                                        self.pb.pbf.f_old, None, self.pb.pbf.c,
                                        self.pb.pbf.y, self.pb.pbf.aux_old)

        # consider consistent initial acceleration
        if self.pb.pbs.timint != 'static' and self.pb.pbs.restart_step == 0:
            # weak form at initial state for consistent initial acceleration solve
            weakform_a = self.pb.pbs.deltaP_kin_old + self.pb.pbs.deltaP_int_old - self.pb.pbs.deltaP_ext_old - self.pb.power_coupling_old

            jac_a = derivative(weakform_a, self.pb.pbs.a_old,
                               self.pb.pbs.dv)  # actually linear in a_old

            # solve for consistent initial acceleration a_old
            self.solnln.solve_consistent_ini_acc(weakform_a, jac_a,
                                                 self.pb.pbs.a_old)

        # write mesh output
        self.pb.pbs.io.write_output(self.pb.pbs, writemesh=True)

        # fluid 0D flow main time loop
        for N in range(self.pb.restart_step + 1, self.pb.numstep_stop + 1):

            wts = time.time()

            # current time
            t = N * self.pb.pbs.dt

            # offset time for multiple cardiac cycles
            t_off = (
                self.pb.pbf.ti.cycle[0] - 1
            ) * self.pb.pbf.cardvasc0D.T_cycl  # zero if T_cycl variable is not specified

            # set time-dependent functions
            self.pb.pbs.ti.set_time_funcs(self.pb.pbs.ti.funcs_to_update,
                                          self.pb.pbs.ti.funcs_to_update_vec,
                                          t - t_off)

            # activation curves for 0D chambers (if present)
            self.pb.pbf.evaluate_activation(t - t_off)

            # solve
            self.solnln.newton(self.pb.pbs.v, self.pb.pbs.p, self.pb.pbf.s,
                               t - t_off)

            # get midpoint dof values for post-processing (has to be called before update!)
            self.pb.pbf.cardvasc0D.midpoint_avg(
                self.pb.pbf.s, self.pb.pbf.s_old,
                self.pb.pbf.s_mid), self.pb.pbf.cardvasc0D.midpoint_avg(
                    self.pb.pbf.aux, self.pb.pbf.aux_old, self.pb.pbf.aux_mid)

            # update time step - fluid and 0D model
            self.pb.pbs.ti.update_timestep(
                self.pb.pbs.v, self.pb.pbs.v_old, self.pb.pbs.a_old,
                self.pb.pbs.p, self.pb.pbs.p_old,
                self.pb.pbs.ti.funcs_to_update,
                self.pb.pbs.ti.funcs_to_update_old,
                self.pb.pbs.ti.funcs_to_update_vec,
                self.pb.pbs.ti.funcs_to_update_vec_old)
            self.pb.pbf.cardvasc0D.update(self.pb.pbf.s, self.pb.pbf.df,
                                          self.pb.pbf.f, self.pb.pbf.s_old,
                                          self.pb.pbf.df_old,
                                          self.pb.pbf.f_old, self.pb.pbf.aux,
                                          self.pb.pbf.aux_old)

            # update old pressures on fluid
            if self.pb.coupling_type == 'monolithic_direct':
                self.pb.pbf.cardvasc0D.set_pressure_fem(
                    self.pb.pbf.s_old, self.pb.pbf.cardvasc0D.v_ids,
                    self.pb.pr0D, self.pb.coupfuncs_old)
            if self.pb.coupling_type == 'monolithic_lagrange':
                self.pb.lm.assemble(), self.pb.lm_old.axpby(
                    1.0, 0.0, self.pb.lm)
                self.pb.pbf.cardvasc0D.set_pressure_fem(
                    self.pb.lm_old, list(range(self.pb.num_coupling_surf)),
                    self.pb.pr0D, self.pb.coupfuncs_old)
                # update old 3D fluxes
                for i in range(self.pb.num_coupling_surf):
                    self.pb.constr_old[i] = self.pb.constr[i]

            # solve time for time step
            wte = time.time()
            wt = wte - wts

            # print to screen
            self.pb.pbf.cardvasc0D.print_to_screen(self.pb.pbf.s_mid,
                                                   self.pb.pbf.aux_mid)
            # print time step info to screen
            self.pb.pbf.ti.print_timestep(N, t, self.pb.pbs.numstep, wt=wt)

            # check for periodicity in cardiac cycle and stop if reached (only for syspul* models - cycle counter gets updated here)
            is_periodic = self.pb.pbf.cardvasc0D.cycle_check(
                self.pb.pbf.s,
                self.pb.pbf.sTc,
                self.pb.pbf.sTc_old,
                t - t_off,
                self.pb.pbf.ti.cycle,
                self.pb.pbf.ti.cycleerror,
                self.pb.pbf.eps_periodic,
                check=self.pb.pbf.periodic_checktype,
                inioutpath=self.pb.pbf.output_path_0D,
                nm=self.pb.pbs.simname,
                induce_pert_after_cycl=self.pb.pbf.perturb_after_cylce)

            # induce some disease/perturbation for cardiac cycle (i.e. valve stenosis or leakage)
            if self.pb.pbf.perturb_type is not None and not self.pb.pbf.have_induced_pert:
                self.pb.induce_perturbation()

            # write output and restart info
            self.pb.pbs.io.write_output(self.pb.pbs, N=N, t=t)
            # raw txt file output of 0D model quantities
            if self.pb.pbf.write_results_every_0D > 0 and N % self.pb.pbf.write_results_every_0D == 0:
                self.pb.pbf.cardvasc0D.write_output(self.pb.pbf.output_path_0D,
                                                    t, self.pb.pbf.s_mid,
                                                    self.pb.pbf.aux_mid,
                                                    self.pb.pbs.simname)
            # write 0D restart info - old and new quantities are the same at this stage (except cycle values sTc)
            if self.pb.pbs.io.write_restart_every > 0 and N % self.pb.pbs.io.write_restart_every == 0:
                self.pb.pbf.writerestart(self.pb.pbs.simname, N)

            if is_periodic:
                if self.pb.comm.rank == 0:
                    print(
                        "Periodicity reached after %i heart cycles with cycle error %.4f! Finished. :-)"
                        % (self.pb.pbf.ti.cycle[0] - 1,
                           self.pb.pbf.ti.cycleerror[0]))
                    sys.stdout.flush()
                break

        if self.pb.comm.rank == 0:  # only proc 0 should print this
            print('Time for computation: %.4f s (= %.2f min)' %
                  (time.time() - start, (time.time() - start) / 60.))
            sys.stdout.flush()