def apply_inverse(self, V, mu=None, least_squares=False): from pymor.operators.constructions import FixedParameterOperator assembled_op = self.assemble(mu) if assembled_op != self and not isinstance(assembled_op, FixedParameterOperator): return assembled_op.apply_inverse(V, least_squares=least_squares) elif self.linear: options = self.solver_options.get('inverse') if self.solver_options else None return genericsolvers.apply_inverse(assembled_op, V, options=options, least_squares=least_squares) else: from pymor.algorithms.newton import newton from pymor.core.exceptions import NewtonError options = self.solver_options.get('inverse') if self.solver_options else None if options: if isinstance(options, str): assert options == 'newton' options = {} else: assert options['type'] == 'newton' options = options.copy() options.pop('type') else: options = {} options['least_squares'] = least_squares R = V.empty(reserve=len(V)) for i in range(len(V)): try: R.append(newton(self, V[i], mu=mu, **options)[0]) except NewtonError as e: raise InversionError(e) return R
def apply_inverse(self, V, ind=None, mu=None, least_squares=False): from pymor.operators.constructions import FixedParameterOperator assembled_op = self.assemble(mu) if assembled_op != self and not isinstance(assembled_op, FixedParameterOperator): return assembled_op.apply_inverse(V, ind=ind, least_squares=least_squares) elif self.linear: options = (self.solver_options.get('inverse') if self.solver_options else 'least_squares' if least_squares else None) if options and not least_squares: solver_type = options if isinstance(options, str) else options['type'] if solver_type.startswith('least_squares'): self.logger.warn('Least squares solver selected but "least_squares == False"') try: return genericsolvers.apply_inverse(assembled_op, V.copy(ind), options=options) except InversionError as e: if least_squares and options: solver_type = options if isinstance(options, str) else options['type'] if not solver_type.startswith('least_squares'): msg = str(e) \ + '\nNote: linear solver was selected for solving least squares problem ' \ + '(maybe not invertible?)' raise InversionError(msg) raise e else: from pymor.algorithms.newton import newton from pymor.core.exceptions import NewtonError assert V.check_ind(ind) options = self.solver_options if options: if isinstance(options, str): assert options == 'newton' options = {} else: assert options['type'] == 'newton' options = options.copy() options.pop('type') else: options = {} options['least_squares'] = least_squares ind = (list(range(len(V))) if ind is None else [ind] if isinstance(ind, Number) else ind) R = V.empty(reserve=len(ind)) for i in ind: try: R.append(newton(self, V.copy(i), **options)[0]) except NewtonError as e: raise InversionError(e) return R
def apply_inverse(self, V, mu=None, initial_guess=None, least_squares=False): """Apply the inverse operator. Parameters ---------- V |VectorArray| of vectors to which the inverse operator is applied. mu The |parameter values| for which to evaluate the inverse operator. initial_guess |VectorArray| with the same length as `V` containing initial guesses for the solution. Some implementations of `apply_inverse` may ignore this parameter. If `None` a solver-dependent default is used. least_squares If `True`, solve the least squares problem:: u = argmin ||op(u) - v||_2. Since for an invertible operator the least squares solution agrees with the result of the application of the inverse operator, setting this option should, in general, have no effect on the result for those operators. However, note that when no appropriate |solver_options| are set for the operator, most implementations will choose a least squares solver by default which may be undesirable. Returns ------- |VectorArray| of the inverse operator evaluations. Raises ------ InversionError The operator could not be inverted. """ assert V in self.range assert initial_guess is None or initial_guess in self.source and len( initial_guess) == len(V) from pymor.operators.constructions import FixedParameterOperator assembled_op = self.assemble(mu) if assembled_op != self and not isinstance(assembled_op, FixedParameterOperator): return assembled_op.apply_inverse(V, initial_guess=initial_guess, least_squares=least_squares) elif self.linear: options = self.solver_options.get( 'inverse') if self.solver_options else None return genericsolvers.apply_inverse(assembled_op, V, initial_guess=initial_guess, options=options, least_squares=least_squares) else: from pymor.algorithms.newton import newton from pymor.core.exceptions import NewtonError options = self.solver_options.get( 'inverse') if self.solver_options else None if options: if isinstance(options, str): assert options == 'newton' options = {} else: assert options['type'] == 'newton' options = options.copy() options.pop('type') else: options = {} options['least_squares'] = least_squares with self.logger.block( 'Solving nonlinear problem using newton algorithm ...'): R = V.empty(reserve=len(V)) for i in range(len(V)): try: R.append( newton(self, V[i], initial_guess=initial_guess[i] if initial_guess is not None else None, mu=mu, **options)[0]) except NewtonError as e: raise InversionError(e) return R
def _newton(order): mop = MonomOperator(order) rhs = NumpyVectorArray([0.0]) guess = NumpyVectorArray([1.0]) return newton(mop, rhs, initial_guess=guess)
def _newton(order, **kwargs): mop = MonomOperator(order) rhs = NumpyVectorArray([0.0]) guess = NumpyVectorArray([1.0]) return newton(mop, rhs, initial_guess=guess, **kwargs)
def _newton(mop, initial_value=1.0, **kwargs): rhs = NumpyVectorSpace.from_numpy([0.0]) guess = NumpyVectorSpace.from_numpy([initial_value]) return newton(mop, rhs, initial_guess=guess, **kwargs)
def apply_inverse(self, V, mu=None, least_squares=False): """Apply the inverse operator. Parameters ---------- V |VectorArray| of vectors to which the inverse operator is applied. mu The |Parameter| for which to evaluate the inverse operator. least_squares If `True`, solve the least squares problem:: u = argmin ||op(u) - v||_2. Since for an invertible operator the least squares solution agrees with the result of the application of the inverse operator, setting this option should, in general, have no effect on the result for those operators. However, note that when no appropriate |solver_options| are set for the operator, most implementations will choose a least squares solver by default which may be undesirable. Returns ------- |VectorArray| of the inverse operator evaluations. Raises ------ InversionError The operator could not be inverted. """ from pymor.operators.constructions import FixedParameterOperator assembled_op = self.assemble(mu) if assembled_op != self and not isinstance(assembled_op, FixedParameterOperator): return assembled_op.apply_inverse(V, least_squares=least_squares) elif self.linear: options = self.solver_options.get( 'inverse') if self.solver_options else None return genericsolvers.apply_inverse(assembled_op, V, options=options, least_squares=least_squares) else: from pymor.algorithms.newton import newton from pymor.core.exceptions import NewtonError options = self.solver_options.get( 'inverse') if self.solver_options else None if options: if isinstance(options, str): assert options == 'newton' options = {} else: assert options['type'] == 'newton' options = options.copy() options.pop('type') else: options = {} options['least_squares'] = least_squares R = V.empty(reserve=len(V)) for i in range(len(V)): try: R.append(newton(self, V[i], mu=mu, **options)[0]) except NewtonError as e: raise InversionError(e) return R
def apply_inverse(self, V, ind=None, mu=None, least_squares=False): from pymor.operators.constructions import FixedParameterOperator assembled_op = self.assemble(mu) if assembled_op != self and not isinstance(assembled_op, FixedParameterOperator): return assembled_op.apply_inverse(V, ind=ind, least_squares=least_squares) elif self.linear: options = (self.solver_options.get('inverse') if self.solver_options else 'least_squares' if least_squares else None) if options and not least_squares: solver_type = options if isinstance(options, str) else options['type'] if solver_type.startswith('least_squares'): self.logger.warn( 'Least squares solver selected but "least_squares == False"' ) try: return genericsolvers.apply_inverse(assembled_op, V.copy(ind), options=options) except InversionError as e: if least_squares and options: solver_type = options if isinstance( options, str) else options['type'] if not solver_type.startswith('least_squares'): msg = str(e) \ + '\nNote: linear solver was selected for solving least squares problem ' \ + '(maybe not invertible?)' raise InversionError(msg) raise e else: from pymor.algorithms.newton import newton from pymor.core.exceptions import NewtonError assert V.check_ind(ind) options = self.solver_options if options: if isinstance(options, str): assert options == 'newton' options = {} else: assert options['type'] == 'newton' options = options.copy() options.pop('type') else: options = {} options['least_squares'] = least_squares ind = (list(range(len(V))) if ind is None else [ind] if isinstance(ind, Number) else ind) R = V.empty(reserve=len(ind)) for i in ind: try: R.append(newton(self, V.copy(i), **options)[0]) except NewtonError as e: raise InversionError(e) return R
def main( dim: int = Argument(..., help='Spatial dimension of the problem.'), n: int = Argument( ..., help='Number of mesh intervals per spatial dimension.'), order: int = Argument(..., help='Finite element order.'), ): """Reduces a FEniCS-based nonlinear diffusion problem using POD/DEIM.""" from pymor.tools import mpi if mpi.parallel: from pymor.models.mpi import mpi_wrap_model local_models = mpi.call(mpi.function_call_manage, discretize, dim, n, order) fom = mpi_wrap_model(local_models, use_with=True, pickle_local_spaces=False) else: fom = discretize(dim, n, order) parameter_space = fom.parameters.space((0, 1000.)) # ### ROM generation (POD/DEIM) from pymor.algorithms.ei import ei_greedy from pymor.algorithms.newton import newton from pymor.algorithms.pod import pod from pymor.operators.ei import EmpiricalInterpolatedOperator from pymor.reductors.basic import StationaryRBReductor U = fom.solution_space.empty() residuals = fom.solution_space.empty() for mu in parameter_space.sample_uniformly(10): UU, data = newton(fom.operator, fom.rhs.as_vector(), mu=mu, rtol=1e-6, return_residuals=True) U.append(UU) residuals.append(data['residuals']) dofs, cb, _ = ei_greedy(residuals, rtol=1e-7) ei_op = EmpiricalInterpolatedOperator(fom.operator, collateral_basis=cb, interpolation_dofs=dofs, triangular=True) rb, svals = pod(U, rtol=1e-7) fom_ei = fom.with_(operator=ei_op) reductor = StationaryRBReductor(fom_ei, rb) rom = reductor.reduce() # the reductor currently removes all solver_options so we need to add them again rom = rom.with_(operator=rom.operator.with_( solver_options=fom.operator.solver_options)) # ### ROM validation import time import numpy as np # ensure that FFC is not called during runtime measurements rom.solve(1) errs = [] speedups = [] for mu in parameter_space.sample_randomly(10): tic = time.perf_counter() U = fom.solve(mu) t_fom = time.perf_counter() - tic tic = time.perf_counter() u_red = rom.solve(mu) t_rom = time.perf_counter() - tic U_red = reductor.reconstruct(u_red) errs.append(((U - U_red).norm() / U.norm())[0]) speedups.append(t_fom / t_rom) print(f'Maximum relative ROM error: {max(errs)}') print(f'Median of ROM speedup: {np.median(speedups)}')
def _newton(order, **kwargs): mop = MonomOperator(order) rhs = NumpyVectorSpace.from_data([0.0]) guess = NumpyVectorSpace.from_data([1.0]) return newton(mop, rhs, initial_guess=guess, **kwargs)
def fenics_nonlinear_demo(args): DIM = int(args['DIM']) N = int(args['N']) ORDER = int(args['ORDER']) from pymor.tools import mpi if mpi.parallel: from pymor.models.mpi import mpi_wrap_model local_models = mpi.call(mpi.function_call_manage, discretize, DIM, N, ORDER) fom = mpi_wrap_model(local_models, use_with=True, pickle_local_spaces=False) else: fom = discretize(DIM, N, ORDER) # ### ROM generation (POD/DEIM) from pymor.algorithms.ei import ei_greedy from pymor.algorithms.newton import newton from pymor.algorithms.pod import pod from pymor.operators.ei import EmpiricalInterpolatedOperator from pymor.reductors.basic import StationaryRBReductor U = fom.solution_space.empty() residuals = fom.solution_space.empty() for mu in fom.parameter_space.sample_uniformly(10): UU, data = newton(fom.operator, fom.rhs.as_vector(), mu=mu, rtol=1e-6, return_residuals=True) U.append(UU) residuals.append(data['residuals']) dofs, cb, _ = ei_greedy(residuals, rtol=1e-7) ei_op = EmpiricalInterpolatedOperator(fom.operator, collateral_basis=cb, interpolation_dofs=dofs, triangular=True) rb, svals = pod(U, rtol=1e-7) fom_ei = fom.with_(operator=ei_op) reductor = StationaryRBReductor(fom_ei, rb) rom = reductor.reduce() # the reductor currently removes all solver_options so we need to add them again rom = rom.with_(operator=rom.operator.with_( solver_options=fom.operator.solver_options)) # ### ROM validation import time import numpy as np # ensure that FFC is not called during runtime measurements rom.solve(1) errs = [] speedups = [] for mu in fom.parameter_space.sample_randomly(10): tic = time.time() U = fom.solve(mu) t_fom = time.time() - tic tic = time.time() u_red = rom.solve(mu) t_rom = time.time() - tic U_red = reductor.reconstruct(u_red) errs.append(((U - U_red).l2_norm() / U.l2_norm())[0]) speedups.append(t_fom / t_rom) print(f'Maximum relative ROM error: {max(errs)}') print(f'Median of ROM speedup: {np.median(speedups)}')