def linearstep(self, subprobctxt, linsys, time, unknowns, endtime): dt = endtime - time ## The matrix equation to be solved (for alpha) is A*alpha=x, ## where ## A = M + theta1 dt C + 1/2 theta2 dt^2 K ## x = -(C + theta1 dt K) adot - K a + rhs ## Note that rhs = -f. ## We work with M (d2/dt2) u + C (d/dt) u + K u = rhs ## instead of M (d2/dt2) u + C (d/dt) u + K u + f = 0 ## a is the known vector of dofs, adot is its known first time ## derivative. rhs is a weighted average of the right hand sides ## over the time interval: ## rhs = (1-theta1) rhs(t) + theta1 rhs(t+dt) ## Values at t+dt are ## a <- a + dt adot + 1/2 dt^2 alpha ## adot <- adot + dt alpha K = linsys.K_MCK() C = linsys.C_MCK() M = linsys.M_MCK() ## This relies on the Fields and their time derivative Fields ## having the same global dof ordering! A = M.clone() A.add(self.theta1*dt, C) A.add(0.5*self.theta2*dt*dt, K) A.consolidate() x = linsys.rhs_MCK() # x = rhs(t_n) x *= (1.0 - self.theta1) # x = (1-theta1) rhs(t_n) ## Compute the rhs at t = endtime. linsys1 = subprobctxt.make_linear_system(endtime, linsys) # x = (1-theta1) rhs(t_n) + theta1 rhs(t_{n+1}) x.axpy(self.theta1, linsys1.rhs_MCK()) # Separate the field and deriv parts of unknowns a = linsys.get_fields_MCKd(unknowns) adot = linsys.get_derivs_MCKd(unknowns) K.axpy(-1.0, a, x) # x = - K a + rhs C.axpy(-1.0, adot, x) # x = -C adot - K a + rhs K.axpy(-self.theta1*dt, adot, x) # ... -theta1 dt K adot alpha = doublevec.DoubleVec(len(a)) subprobctxt.matrix_method(_asymmetric, subprobctxt).solve(A, x, alpha) ## update a and adot, then copy them into endValues a.axpy(dt, adot) a.axpy(0.5*dt*dt, alpha) adot.axpy(dt, alpha) endValues = doublevec.DoubleVec(unknowns.size()) linsys.set_fields_MCKd(a, endValues) linsys.set_derivs_MCKd(adot, endValues) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=endValues, linsys=linsys)
def linearstep(self, subproblem, linsys, time, unknowns, endtime): # C du/dt + K u = f # C, K, and f might depend on time explicitly, but not on u # # Write du/dt = (u_{n+1}-u_n)/dt, K u = K_{n+1} u_{n+1}, f = f_{n+1} # # (C + dt K_{n+1}) u_{n+1} = C u_{n} + dt f_{n+1} dt = endtime - time # Evaluate quantities at endtime. linsys1 = subproblem.make_linear_system(endtime, linsys) K1 = linsys1.K_MCKa() # K_{n+1} f1 = linsys1.rhs_MCKa() # f_{n+1} C = linsys1.C_MCKa() # Construct A = C + dt K_{n+1}, which is the matrix to be inverted. A = C.clone() A.add(dt, K1) # Compute the rhs of the matrix equation. v = dt * f1 C.axpy(1.0, unknowns, v) # Solve the linear system. unknowns is updated in-place. subproblem.matrix_method(_asymmetricGE, subproblem).solve(A, v, unknowns) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=unknowns, linsys=linsys)
def nonlinearstep(self, subproblem, linsys, time, unknowns, endtime, nonlinearMethod): # M d2u/dt2 + C du/dt + F(u,t) = 0 # F might depend on time and u explicitly # M and C might depend on time dt = endtime - time data = NLDataSS22(subproblem, linsys, endtime, dt, unknowns, self.theta1, self.theta2) alpha = doublevec.DoubleVec(linsys.n_unknowns_MCK()) # not MCKd nonlinearMethod.solve( subproblem.matrix_method(_asymmetric, subproblem), self.precomputeNL, self.compute_residual, self.compute_jacobian, self.compute_linear_coef_mtx, data, alpha) # Update a and adot, reusing the storage in data.a0 and data.a0dot. data.a0.axpy(dt, data.a0dot) data.a0.axpy(0.5 * dt * dt, alpha) data.a0dot.axpy(dt, alpha) endValues = doublevec.DoubleVec(unknowns.size()) linsys.set_fields_MCKd(data.a0, endValues) linsys.set_derivs_MCKd(data.a0dot, endValues) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=endValues, linsys=linsys)
def nonlinearstep(self, subproblem, linsys, time, unknowns, endtime, nonlinearMethod): data = timestepper.NLData(subproblem, linsys, endtime) endValues = unknowns.clone() nonlinearMethod.solve(subproblem.matrix_method(subproblem.asymmetricK), self.precomputeNL, self.compute_residual, self.compute_jacobian, self.compute_linear_coef_mtx, data, endValues) return timestepper.StepResult(endTime=endtime, endValues=endValues, linsys=linsys)
def linearstep(self, subproblem, linsys, time, unknowns, endtime): # This function is called only when solving quasi-static # problems. Fully static problems are solved by # SubProblemContext.initializeStaticFields. # Use unknowns as an initial guess for the solution. The # calculation is done in place. (evolve.py created the # unknowns vector by calling SubProblemContext.get_unknowns, # which copied them out of the subproblem's dof list, so we're # already working with a copy here.) linsys = subproblem.make_linear_system(endtime, linsys) self.staticSolve(subproblem, linsys, unknowns) return timestepper.StepResult(endTime=endtime, endValues=unknowns, linsys=linsys)
def linearstep(self, subproblem, linsys, time, unknowns, endtime): # C du/dt + K u = f # C, K, and f might have explicit time dependence, but don't # depend on u. # Write du/dt = (u_{n+1}-u_n)/dt, # K u = (1-theta) K_n u_n + theta K_{n+1} u_{n+1} # f = (1-theta) f_n + theta f_{n+1} # (C + dt theta K_{n+1}) u_{n+1} = # (C - dt (1-theta) K_n) u_n + (1-theta) dt f_n + theta dt f_{n+1} # Because GeneralizedEuler mixes C and K in the matrix to be # solved, it doesn't have to worry that C can be singular, # unlike ForwardEuler. It can work with the full MCKa matrix, # and doesn't have to explicitly solve the static equations. dt = endtime - time # Evaluate quantities at start time. K0 = linsys.K_MCKa() # K_n f0 = linsys.rhs_MCKa() # f_n C = linsys.C_MCKa() # Evaluate quantities at endtime, in case of explicit time # dependence of rhs_ind or K_eff. linsys1 = subproblem.make_linear_system(endtime, linsys) K1 = linsys1.K_MCKa() # K_{n+1} f1 = linsys1.rhs_MCKa() # f_{n+1} # Compute C + dt theta K_{n+1}, which is the matrix to be solved. A = C.clone() A.add(self.theta * dt, K1) # Compute the rhs of the matrix equation. v = (dt * (1.0 - self.theta)) * f0 v.axpy(self.theta * dt, f1) # v = (1-theta) dt f_n + theta dt f_{n+1} K0.axpy(-dt * (1 - self.theta), unknowns, v) # ... - dt (1-theta) K_n u_n C.axpy(1.0, unknowns, v) # ... + C u_n subproblem.matrix_method(_asymmetricGE, subproblem).solve(A, v, unknowns) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=unknowns, linsys=linsys1)
def _do_step(self, subproblem, linsys, time, unknowns, endtime, get_res): # Solve C(u_{n+1} - u_n) = dt*(f - K u_n) # C and K are effective matrices, coming from the reduction of # a second order problem to a system of first order problems. # If C has empty rows, the static solution of those rows has # already been computed by initializeStaticFields() or by a # previous Euler step, and we only have to solve the remaining # nonempty rows here. Unlike GeneralizedEuler, here we're # solving an unmodified C, so it can't contain empty rows. staticEqns = linsys.n_unknowns_part('K') > 0 dt = endtime - time # v = dt * linsys.rhs_MCa() # v = dt*f # # K_MCa is really (MCa)x(MCKa), so we can multiply by # # unknowns, which includes the K part. # K = linsys.K_MCa() # K.axpy(-dt, unknowns, v) # v = dt*(f - K u) v = get_res(linsys, dt, unknowns) C = linsys.C_MCa() # solve() stores u_{n+1}-u_n in endValues. Before calling # solve, set endValues to a good guess for u_{n+1}-u_n. # Assuming that the step size is small, a good guess is zero. endValues = doublevec.DoubleVec(unknowns.size()) endValues.zero() x = linsys.extract_MCa_dofs(endValues) subproblem.matrix_method(_asymmetricFE, subproblem, linsys).solve(C, v, x) linsys.inject_MCa_dofs(x, endValues) endValues += unknowns if staticEqns: # Re-solve the static equations at endtime. subproblem.installValues(linsys, endValues, endtime) linsys = subproblem.make_linear_system(endtime, linsys) subproblem.computeStaticFields(linsys, endValues) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=endValues, linsys=linsys)
def _do_step(self, subprobctxt, linsys, time, unknowns, endtime, get_res): nK = linsys.n_unknowns_part('K') # number of static DoFs staticEqns = nK > 0 dt = endtime - time n = unknowns.size() - nK C = linsys.C_MCa() # K = linsys.K_MCa() # v = linsys.rhs_MCa() - K*unknowns v = get_res(linsys, unknowns) k1 = linsys.extract_MCa_dofs(unknowns) # initial guess for k1 subprobctxt.matrix_method(_asymmetric, subprobctxt, linsys).solve(C, v, k1) if staticEqns: linsys.expand_MCa_dofs(k1) y = unknowns + (0.5 * dt) * k1 subprobctxt.installValues(linsys, y, time + 0.5 * dt) linsys = subprobctxt.make_linear_system(time + 0.5 * dt, linsys) if staticEqns: subprobctxt.computeStaticFields(linsys, y) C = linsys.C_MCa() # K = linsys.K_MCa() # v = linsys.rhs_MCa() - K*y v = get_res(linsys, y) k2 = linsys.extract_MCa_dofs(y) subprobctxt.matrix_method(_asymmetric, subprobctxt, linsys).solve(C, v, k2) if staticEqns: linsys.expand_MCa_dofs(k2) unknowns.axpy(dt, k2) if staticEqns: subprobctxt.installValues(linsys, unknowns, endtime) linsys = subprobctxt.make_linear_system(endtime, linsys) subprobctxt.computeStaticFields(linsys, unknowns) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=unknowns, linsys=linsys)
def nonlinearstep(self, subproblem, linsys, time, unknowns, endtime, nonlinearMethod): # C du/dt + F(u,t) = 0 # C (u_{n+1}-u_n)/dt + theta F(u_{n+1}, t+dt) + (1-theta)F(u_n, t) = 0 # or # C u_{n+1} + theta dt F(u_{n+1}, t+dt) # - C u_n + (1-theta)dt F(u_n,t) = 0 dt = endtime - time data = NLDataGE(subproblem, linsys, endtime, dt, unknowns, self.theta) endValues = unknowns.clone() nonlinearMethod.solve( subproblem.matrix_method(_asymmetricGE, subproblem), self.precomputeNL, self.compute_residual, self.compute_jacobian, self.compute_linear_coef_mtx, data, endValues) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=endValues, linsys=linsys)
def nonlinearstep(self, subproblem, linsys, time, unknowns, endtime, nonlinearMethod): # C du/dt + F = 0 # K, and f might depend on time and u explicitly # Write du/dt = (u_{n+1}-u_n)/dt, # F(u,t) = F( u_{n+1}, t_{n+1} ) # So we need to solve the following nonlinear eqn for v # to obtain u_{n+1} # C v + dt F(v,t+dt) - C u_{n} = 0 dt = endtime - time data = NLDataBE(subproblem, linsys, endtime, dt, unknowns) endValues = unknowns.clone() nonlinearMethod.solve( subproblem.matrix_method(_asymmetricGE, subproblem), self.precomputeNL, self.compute_residual, self.compute_jacobian, self.compute_linear_coef_mtx, data, endValues) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=endValues, linsys=linsys)
def _do_step(self, subprobctxt, linsys, time, unknowns, endtime, get_res): nK = linsys.n_unknowns_part('K') # number of static DoFs staticEqns = nK > 0 dt = endtime - time n = unknowns.size() - nK halftime = time + 0.5 * dt C = linsys.C_MCa() v = get_res(linsys, unknowns) # K = linsys.K_MCa() # really (MCa)x(MCKa) # v = linsys.rhs_MCa() - K*unknowns # (f - K u) k1 = linsys.extract_MCa_dofs(unknowns) # initial guess for k1 assert k1.size() == n subprobctxt.matrix_method(_asymmetric, subprobctxt, linsys).solve(C, v, k1) if staticEqns: linsys.expand_MCa_dofs(k1) # include room for static dofs in k1 y = unknowns + (0.5 * dt) * k1 subprobctxt.installValues(linsys, y, halftime) linsys = subprobctxt.make_linear_system(halftime, linsys) if staticEqns: subprobctxt.computeStaticFields(linsys, y) C = linsys.C_MCa() # K = linsys.K_MCa() # v = linsys.rhs_MCa() - K*y v = get_res(linsys, y) k2 = linsys.extract_MCa_dofs(y) subprobctxt.matrix_method(_asymmetric, subprobctxt, linsys).solve(C, v, k2) if staticEqns: linsys.expand_MCa_dofs(k2) y = unknowns + (0.5 * dt) * k2 subprobctxt.installValues(linsys, y, halftime) linsys = subprobctxt.make_linear_system(halftime, linsys) if staticEqns: subprobctxt.computeStaticFields(linsys, y) C = linsys.C_MCa() # K = linsys.K_MCa() # v = linsys.rhs_MCa() - K*y v = get_res(linsys, y) k3 = linsys.extract_MCa_dofs(y) subprobctxt.matrix_method(_asymmetric, subprobctxt, linsys).solve(C, v, k3) if staticEqns: linsys.expand_MCa_dofs(k3) y = unknowns + dt * k3 subprobctxt.installValues(linsys, y, endtime) linsys = subprobctxt.make_linear_system(endtime, linsys) if staticEqns: subprobctxt.computeStaticFields(linsys, y) C = linsys.C_MCa() # K = linsys.K_MCa() # v = linsys.rhs_MCa() - K*y v = get_res(linsys, y) k4 = linsys.extract_MCa_dofs(y) subprobctxt.matrix_method(_asymmetric, subprobctxt, linsys).solve(C, v, k4) if staticEqns: linsys.expand_MCa_dofs(k4) unknowns.axpy(dt / 6., k1) unknowns.axpy(dt / 3., k2) unknowns.axpy(dt / 3., k3) unknowns.axpy(dt / 6., k4) if staticEqns: subprobctxt.installValues(linsys, unknowns, endtime) linsys = subprobctxt.make_linear_system(endtime, linsys) subprobctxt.computeStaticFields(linsys, unknowns) return timestepper.StepResult(endTime=endtime, nextStep=dt, endValues=unknowns, linsys=linsys)