dune-fem 2.12-git
Loading...
Searching...
No Matches
elliptic.hh
Go to the documentation of this file.
1/**************************************************************************
2
3 The dune-fem module is a module of DUNE (see www.dune-project.org).
4 It is based on the dune-grid interface library
5 extending the grid interface by a number of discretization algorithms
6 for solving non-linear systems of partial differential equations.
7
8 Copyright (C) 2003 - 2015 Robert Kloefkorn
9 Copyright (C) 2003 - 2010 Mario Ohlberger
10 Copyright (C) 2004 - 2015 Andreas Dedner
11 Copyright (C) 2005 Adrian Burri
12 Copyright (C) 2005 - 2015 Mirko Kraenkel
13 Copyright (C) 2006 - 2015 Christoph Gersbacher
14 Copyright (C) 2006 - 2015 Martin Nolte
15 Copyright (C) 2011 - 2015 Tobias Malkmus
16 Copyright (C) 2012 - 2015 Stefan Girke
17 Copyright (C) 2013 - 2015 Claus-Justus Heine
18 Copyright (C) 2013 - 2014 Janick Gerstenberger
19 Copyright (C) 2013 Sven Kaulman
20 Copyright (C) 2013 Tom Ranner
21 Copyright (C) 2015 Marco Agnese
22 Copyright (C) 2015 Martin Alkaemper
23
24
25 The dune-fem module is free software; you can redistribute it and/or
26 modify it under the terms of the GNU General Public License as
27 published by the Free Software Foundation; either version 2 of
28 the License, or (at your option) any later version.
29
30 The dune-fem module is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU General Public License for more details.
34
35 You should have received a copy of the GNU General Public License along
36 with this program; if not, write to the Free Software Foundation, Inc.,
37 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38
39**************************************************************************/
40#ifndef DUNE_FEM_SCHEMES_ELLIPTIC_HH
41#define DUNE_FEM_SCHEMES_ELLIPTIC_HH
42
43#include <cstddef>
44
45#include <dune/common/timer.hh>
47
51
55
58
59
60// include parameter handling
63
64// fempy includes
65#include <dune/fempy/quadrature/fempyquadratures.hh>
66
67// EllipticOperator
68// ----------------
69
71template< class DomainDiscreteFunction, class RangeDiscreteFunction, class Model>
73: public virtual Dune::Fem::Operator< DomainDiscreteFunction, RangeDiscreteFunction >
75{
76 typedef DomainDiscreteFunction DomainFunctionType;
77 typedef RangeDiscreteFunction RangeFunctionType;
78 typedef Model ModelType;
79 typedef Model DirichletModelType;
80
81 typedef typename DomainFunctionType::DiscreteFunctionSpaceType DomainDiscreteFunctionSpaceType;
82 typedef typename DomainFunctionType::LocalFunctionType DomainLocalFunctionType;
83 typedef typename DomainLocalFunctionType::RangeType DomainRangeType;
84 typedef typename DomainLocalFunctionType::JacobianRangeType DomainJacobianRangeType;
85 typedef typename RangeFunctionType::DiscreteFunctionSpaceType RangeDiscreteFunctionSpaceType;
86 typedef typename RangeFunctionType::LocalFunctionType RangeLocalFunctionType;
87 typedef typename RangeLocalFunctionType::RangeType RangeRangeType;
88 typedef typename RangeLocalFunctionType::JacobianRangeType RangeJacobianRangeType;
89
90 // the following types must be identical for domain and range
91 typedef typename RangeDiscreteFunctionSpaceType::IteratorType IteratorType;
92 typedef typename IteratorType::Entity EntityType;
93 typedef typename EntityType::Geometry GeometryType;
94 typedef typename RangeDiscreteFunctionSpaceType::DomainType DomainType;
95 typedef typename RangeDiscreteFunctionSpaceType::GridPartType GridPartType;
96 typedef typename GridPartType::IntersectionIteratorType IntersectionIteratorType;
97 typedef typename IntersectionIteratorType::Intersection IntersectionType;
98
101
109 const RangeDiscreteFunctionSpaceType &rSpace,
112 : model_( model ),
113 dSpace_(dSpace), rSpace_(rSpace),
115 {}
116
118 virtual void operator() ( const DomainFunctionType &u, RangeFunctionType &w ) const
119 { apply(u,w); }
120 template <class GF>
121 void operator()( const GF &u, RangeFunctionType &w ) const
122 { apply(u,w); }
123 template <class GF>
124 void apply( const GF &u, RangeFunctionType &w ) const;
125
127 {
128 return dSpace_;
129 }
131 {
132 return rSpace_;
133 }
134 const ModelType &model () const { return model_; }
135 ModelType &model () { return model_; }
136
137 void setQuadratureOrders(unsigned int interior, unsigned int surface)
138 {
139 interiorOrder_ = interior;
140 surfaceOrder_ = surface;
141 }
142
143protected:
145private:
146 ModelType &model_;
147 const DomainDiscreteFunctionSpaceType &dSpace_;
148 const RangeDiscreteFunctionSpaceType &rSpace_;
149};
150
151
152
153// DifferentiableEllipticOperator
154// ------------------------------
155
157template< class JacobianOperator, class Model >
159: public EllipticOperator< typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType, Model >,
160 public Dune::Fem::DifferentiableOperator< JacobianOperator >
162{
164
165 typedef JacobianOperator JacobianOperatorType;
166
170
171 typedef typename DomainFunctionType::DiscreteFunctionSpaceType DomainDiscreteFunctionSpaceType;
172 typedef typename DomainFunctionType::LocalFunctionType DomainLocalFunctionType;
173 typedef typename DomainLocalFunctionType::RangeType DomainRangeType;
174 typedef typename DomainLocalFunctionType::JacobianRangeType DomainJacobianRangeType;
175 typedef typename RangeFunctionType::DiscreteFunctionSpaceType RangeDiscreteFunctionSpaceType;
176 typedef typename RangeFunctionType::LocalFunctionType RangeLocalFunctionType;
177 typedef typename RangeLocalFunctionType::RangeType RangeRangeType;
178 typedef typename RangeLocalFunctionType::JacobianRangeType RangeJacobianRangeType;
179
180 // the following types must be identical for domain and range
181 typedef typename RangeDiscreteFunctionSpaceType::IteratorType IteratorType;
182 typedef typename IteratorType::Entity EntityType;
183 typedef typename EntityType::Geometry GeometryType;
184 typedef typename RangeDiscreteFunctionSpaceType::DomainType DomainType;
185 typedef typename RangeDiscreteFunctionSpaceType::GridPartType GridPartType;
186 typedef typename GridPartType::IntersectionIteratorType IntersectionIteratorType;
187 typedef typename IntersectionIteratorType::Intersection IntersectionType;
188
190 // quadrature for faces - used for Neuman b.c.
192
197 : BaseType( space, space, model, parameter )
198 {}
201 const RangeDiscreteFunctionSpaceType &rSpace,
204 : BaseType( dSpace, rSpace, model, parameter )
205 {}
206
209 { assemble(u,jOp); }
210 template <class GridFunctionType>
211 void jacobian ( const GridFunctionType &u, JacobianOperatorType &jOp ) const
212 { assemble(u,jOp); }
213 template <class GridFunctionType>
214 void assemble ( const GridFunctionType &u, JacobianOperatorType &jOp ) const;
215 using BaseType::operator();
216
217 using BaseType::model;
220};
221
222
223
224// Implementation of EllipticOperator
225// ----------------------------------
226
227template< class DomainDiscreteFunction, class RangeDiscreteFunction, class Model >
228template<class GF>
230 ::apply( const GF &u, RangeFunctionType &w ) const
231{
232 w.clear();
233 // get discrete function space
234 const RangeDiscreteFunctionSpaceType &dfSpace = w.space();
235
236 // get local representation of the discrete functions
239
240 // iterate over grid
241 for( const EntityType &entity : dfSpace )
242 {
243 if( !model().init( entity ) )
244 continue;
245
246 // get elements geometry
247 const GeometryType &geometry = entity.geometry();
248
249 auto uGuard = Dune::Fem::bindGuard( uLocal, entity );
250 auto wGuard = Dune::Fem::bindGuard( wLocal, entity );
251
252 // obtain quadrature order
253 const int quadOrder = interiorOrder_==-1?
254 uLocal.order() + wLocal.order() : interiorOrder_;
255
256 { // element integral
257 QuadratureType quadrature( entity, quadOrder );
258 const size_t numQuadraturePoints = quadrature.nop();
259 for( size_t pt = 0; pt < numQuadraturePoints; ++pt )
260 {
262 const typename QuadratureType::CoordinateType &x = quadrature.point( pt );
263 const double weight = quadrature.weight( pt ) * geometry.integrationElement( x );
264
266 uLocal.evaluate( quadrature[ pt ], vu );
268 uLocal.jacobian( quadrature[ pt ], du );
269
270 // compute mass contribution (studying linear case so linearizing around zero)
271 RangeRangeType avu( 0 );
272 model().source( quadrature[ pt ], vu, du, avu );
273 avu *= weight;
274 // add to local functional wLocal.axpy( quadrature[ pt ], avu );
275
276 RangeJacobianRangeType adu( 0 );
277 // apply diffusive flux
278 model().flux( quadrature[ pt ], vu, du, adu );
279 adu *= weight;
280
281 // add to local function
282 wLocal.axpy( quadrature[ pt ], avu, adu );
284 }
285 }
286
287 if( model().hasNeumanBoundary() && entity.hasBoundaryIntersections() )
288 {
289 const IntersectionIteratorType iitend = dfSpace.gridPart().iend( entity );
290 for( IntersectionIteratorType iit = dfSpace.gridPart().ibegin( entity ); iit != iitend; ++iit )
291 {
292 const IntersectionType &intersection = *iit;
293 if( !intersection.boundary() )
294 continue;
295
297
298 const bool hasDirichletComponent = model().isDirichletIntersection( intersection, components );
299
300 const auto &intersectionGeometry = intersection.geometry();
301 const int quadOrder = surfaceOrder_==-1?
302 uLocal.order() + wLocal.order() : surfaceOrder_;
303 FaceQuadratureType quadInside( dfSpace.gridPart(), intersection, quadOrder, FaceQuadratureType::INSIDE );
304 const std::size_t numQuadraturePoints = quadInside.nop();
305 for( std::size_t pt = 0; pt < numQuadraturePoints; ++pt )
306 {
307 const auto &x = quadInside.localPoint( pt );
308 double weight = quadInside.weight( pt ) * intersectionGeometry.integrationElement( x );
310 uLocal.evaluate( quadInside[ pt ], vu );
312 model().alpha( quadInside[ pt ], vu, alpha );
313 alpha *= weight;
314 for( int k = 0; k < RangeRangeType::dimension; ++k )
315 if( hasDirichletComponent && components[ k ] )
316 alpha[ k ] = 0;
317 wLocal.axpy( quadInside[ pt ], alpha );
318 }
319 }
320 }
321 }
322
323 w.communicate();
324}
325
326
327
328// Implementation of DifferentiableEllipticOperator
329// ------------------------------------------------
330
331template< class JacobianOperator, class Model >
332template<class GF>
334 ::assemble ( const GF &u, JacobianOperator &jOp ) const
335{
336 // std::cout << "starting assembly\n";
337 // Dune::Timer timer;
338 typedef typename DomainDiscreteFunctionSpaceType::BasisFunctionSetType DomainBasisFunctionSetType;
339 typedef typename RangeDiscreteFunctionSpaceType::BasisFunctionSetType RangeBasisFunctionSetType;
341
342 const DomainDiscreteFunctionSpaceType &domainSpace = jOp.domainSpace();
343 const RangeDiscreteFunctionSpaceType &rangeSpace = jOp.rangeSpace();
344
346 jOp.reserve(stencil);
347 jOp.clear();
348 TmpLocalMatrixType jLocal( domainSpace, rangeSpace );
349
350 const int domainBlockSize = domainSpace.localBlockSize; // is equal to 1 for scalar functions
351 std::vector< typename DomainLocalFunctionType::RangeType > phi( domainSpace.blockMapper().maxNumDofs()*domainBlockSize );
352 std::vector< typename DomainLocalFunctionType::JacobianRangeType > dphi( domainSpace.blockMapper().maxNumDofs()*domainBlockSize );
353 const int rangeBlockSize = rangeSpace.localBlockSize; // is equal to 1 for scalar functions
354 std::vector< typename RangeLocalFunctionType::RangeType > rphi( rangeSpace.blockMapper().maxNumDofs()*rangeBlockSize );
355 std::vector< typename RangeLocalFunctionType::JacobianRangeType > rdphi( rangeSpace.blockMapper().maxNumDofs()*rangeBlockSize );
356
358 // std::cout << " in assembly: start element loop size=" << rangeSpace.gridPart().grid().size(0) << " time= " << timer.elapsed() << std::endl;;
359 for( const EntityType &entity : rangeSpace )
360 {
361 if( !model().init( entity ) )
362 continue;
363
364 const GeometryType &geometry = entity.geometry();
365
366 auto uGuard = Dune::Fem::bindGuard( uLocal, entity );
367 jLocal.bind( entity, entity );
368 jLocal.clear();
369
370 const DomainBasisFunctionSetType &domainBaseSet = jLocal.domainBasisFunctionSet();
371 const RangeBasisFunctionSetType &rangeBaseSet = jLocal.rangeBasisFunctionSet();
372 const std::size_t domainNumBasisFunctions = domainBaseSet.size();
373
374 const int quadOrder = interiorOrder_==-1?
375 domainSpace.order() + rangeSpace.order() : interiorOrder_;
376 QuadratureType quadrature( entity, quadOrder );
377 const size_t numQuadraturePoints = quadrature.nop();
378 for( size_t pt = 0; pt < numQuadraturePoints; ++pt )
379 {
381 const typename QuadratureType::CoordinateType &x = quadrature.point( pt );
382 const double weight = quadrature.weight( pt ) * geometry.integrationElement( x );
383
384 // evaluate all basis functions at given quadrature point
385 domainBaseSet.evaluateAll( quadrature[ pt ], phi );
386 rangeBaseSet.evaluateAll( quadrature[ pt ], rphi );
387
388 // evaluate jacobians of all basis functions at given quadrature point
389 domainBaseSet.jacobianAll( quadrature[ pt ], dphi );
390 rangeBaseSet.jacobianAll( quadrature[ pt ], rdphi );
391
392 // get value for linearization
395 uLocal.evaluate( quadrature[ pt ], u0 );
396 uLocal.jacobian( quadrature[ pt ], jacU0 );
397
398 RangeRangeType aphi( 0 );
399 RangeJacobianRangeType adphi( 0 );
400 for( std::size_t localCol = 0; localCol < domainNumBasisFunctions; ++localCol )
401 {
402 // if mass terms or right hand side is present
403 model().linSource( u0, jacU0, quadrature[ pt ], phi[ localCol ], dphi[localCol], aphi );
404
405 // if gradient term is present
406 model().linFlux( u0, jacU0, quadrature[ pt ], phi[ localCol ], dphi[ localCol ], adphi );
407
408 // get column object and call axpy method
409 jLocal.column( localCol ).axpy( rphi, rdphi, aphi, adphi, weight );
410 }
412 }
413
414 if( model().hasNeumanBoundary() && entity.hasBoundaryIntersections() )
415 {
416 const IntersectionIteratorType iitend = rangeSpace.gridPart().iend( entity );
417 for( IntersectionIteratorType iit = rangeSpace.gridPart().ibegin( entity ); iit != iitend; ++iit ) // looping over intersections
418 {
419 const IntersectionType &intersection = *iit;
420 if( !intersection.boundary() )
421 continue;
422
424 bool hasDirichletComponent = model().isDirichletIntersection( intersection, components );
425
426 const auto &intersectionGeometry = intersection.geometry();
427 const int quadOrder = surfaceOrder_==-1?
428 domainSpace.order() + rangeSpace.order() : surfaceOrder_;
429 FaceQuadratureType quadInside( rangeSpace.gridPart(), intersection, quadOrder, FaceQuadratureType::INSIDE );
430 const std::size_t numQuadraturePoints = quadInside.nop();
431 for( std::size_t pt = 0; pt < numQuadraturePoints; ++pt )
432 {
433 const auto &x = quadInside.localPoint( pt );
434 const double weight = quadInside.weight( pt ) * intersectionGeometry.integrationElement( x );
436 uLocal.evaluate( quadInside[ pt ], u0 );
437 domainBaseSet.evaluateAll( quadInside[ pt ], phi );
438 for( std::size_t localCol = 0; localCol < domainNumBasisFunctions; ++localCol )
439 {
441 model().linAlpha( u0,quadInside[ pt ], phi[ localCol ], alpha );
442 for( int k = 0; k < RangeRangeType::dimension; ++k )
443 if( hasDirichletComponent && components[ k ] )
444 alpha[ k ] = 0;
445 jLocal.column( localCol ).axpy( phi, alpha, weight );
446 }
447 }
448 }
449 }
450 jOp.addLocalMatrix( entity, entity, jLocal );
451 jLocal.unbind();
452 } // end grid traversal
453 // std::cout << " in assembly: final " << timer.elapsed() << std::endl;;
454 jOp.flushAssembly();
455}
456#endif // #ifndef DUNE_FEM_SCHEMES_ELLIPTIC_HH
double alpha() const
virtual void operator()()=0
typename Impl::ConstLocalFunction< GridFunction >::Type ConstLocalFunction
Definition const.hh:626
static auto bindGuard(Object &object, Args &&... args) -> std::enable_if_t< isBindable< Object, Args... >::value, BindGuard< Object > >
Definition bindguard.hh:67
Definition common/localcontribution.hh:14
static ParameterContainer & container()
Definition io/parameter.hh:199
abstract differentiable operator
Definition differentiableoperator.hh:29
const DomainSpaceType & domainSpace() const
access to the domain space
Definition localmatrix.hh:382
abstract operator
Definition operator.hh:34
Stencil contaning the entries (en,en) for all entities in the space. Defailt for an operator over a L...
Definition stencil.hh:349
A local matrix with a small array as storage.
Definition temporarylocalmatrix.hh:100
quadrature class supporting base function caching
Definition cachingquadrature.hh:106
[Class for elliptic operator]
Definition elliptic.hh:75
DomainLocalFunctionType::JacobianRangeType DomainJacobianRangeType
Definition elliptic.hh:84
RangeLocalFunctionType::JacobianRangeType RangeJacobianRangeType
Definition elliptic.hh:88
Model ModelType
Definition elliptic.hh:78
DomainFunctionType::LocalFunctionType DomainLocalFunctionType
Definition elliptic.hh:82
int interiorOrder_
Definition elliptic.hh:144
ModelType & model()
Definition elliptic.hh:135
IteratorType::Entity EntityType
Definition elliptic.hh:92
RangeDiscreteFunctionSpaceType::GridPartType GridPartType
Definition elliptic.hh:95
RangeLocalFunctionType::RangeType RangeRangeType
Definition elliptic.hh:87
RangeFunctionType::DiscreteFunctionSpaceType RangeDiscreteFunctionSpaceType
Definition elliptic.hh:85
const DomainDiscreteFunctionSpaceType & domainSpace() const
Definition elliptic.hh:126
RangeDiscreteFunctionSpaceType::IteratorType IteratorType
Definition elliptic.hh:91
Dune::Fem::CachingQuadrature< GridPartType, 0, Dune::FemPy::FempyQuadratureTraits > QuadratureType
Definition elliptic.hh:99
EllipticOperator(const RangeDiscreteFunctionSpaceType &rangeSpace, ModelType &model, const Dune::Fem::ParameterReader &parameter=Dune::Fem::Parameter::container())
Definition elliptic.hh:102
void apply(const GF &u, RangeFunctionType &w) const
Definition elliptic.hh:230
GridPartType::IntersectionIteratorType IntersectionIteratorType
Definition elliptic.hh:96
void setQuadratureOrders(unsigned int interior, unsigned int surface)
Definition elliptic.hh:137
Model DirichletModelType
Definition elliptic.hh:79
void operator()(const GF &u, RangeFunctionType &w) const
Definition elliptic.hh:121
DomainDiscreteFunction DomainFunctionType
Definition elliptic.hh:76
RangeFunctionType::LocalFunctionType RangeLocalFunctionType
Definition elliptic.hh:86
RangeDiscreteFunctionSpaceType::DomainType DomainType
Definition elliptic.hh:94
DomainFunctionType::DiscreteFunctionSpaceType DomainDiscreteFunctionSpaceType
Definition elliptic.hh:81
Dune::Fem::CachingQuadrature< GridPartType, 1, Dune::FemPy::FempyQuadratureTraits > FaceQuadratureType
Definition elliptic.hh:100
IntersectionIteratorType::Intersection IntersectionType
Definition elliptic.hh:97
EntityType::Geometry GeometryType
Definition elliptic.hh:93
const ModelType & model() const
Definition elliptic.hh:134
int surfaceOrder_
Definition elliptic.hh:144
const RangeDiscreteFunctionSpaceType & rangeSpace() const
Definition elliptic.hh:130
RangeDiscreteFunction RangeFunctionType
Definition elliptic.hh:77
DomainLocalFunctionType::RangeType DomainRangeType
Definition elliptic.hh:83
EllipticOperator(const DomainDiscreteFunctionSpaceType &dSpace, const RangeDiscreteFunctionSpaceType &rSpace, ModelType &model, const Dune::Fem::ParameterReader &parameter=Dune::Fem::Parameter::container())
Definition elliptic.hh:108
[Class for linearizable elliptic operator]
Definition elliptic.hh:162
DomainFunctionType::DiscreteFunctionSpaceType DomainDiscreteFunctionSpaceType
Definition elliptic.hh:171
DifferentiableEllipticOperator(const DomainDiscreteFunctionSpaceType &dSpace, const RangeDiscreteFunctionSpaceType &rSpace, ModelType &model, const Dune::Fem::ParameterReader &parameter=Dune::Fem::Parameter::container())
contructor
Definition elliptic.hh:200
EllipticOperator< typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType, Model > BaseType
Definition elliptic.hh:163
RangeDiscreteFunctionSpaceType::IteratorType IteratorType
Definition elliptic.hh:181
DifferentiableEllipticOperator(const RangeDiscreteFunctionSpaceType &space, ModelType &model, const Dune::Fem::ParameterReader &parameter=Dune::Fem::Parameter::container())
contructor
Definition elliptic.hh:194
BaseType::DomainFunctionType DomainFunctionType
Definition elliptic.hh:167
void assemble(const GridFunctionType &u, JacobianOperatorType &jOp) const
IntersectionIteratorType::Intersection IntersectionType
Definition elliptic.hh:187
DomainLocalFunctionType::JacobianRangeType DomainJacobianRangeType
Definition elliptic.hh:174
BaseType::RangeFunctionType RangeFunctionType
Definition elliptic.hh:168
RangeLocalFunctionType::JacobianRangeType RangeJacobianRangeType
Definition elliptic.hh:178
void jacobian(const GridFunctionType &u, JacobianOperatorType &jOp) const
Definition elliptic.hh:211
RangeDiscreteFunctionSpaceType::GridPartType GridPartType
Definition elliptic.hh:185
RangeFunctionType::DiscreteFunctionSpaceType RangeDiscreteFunctionSpaceType
Definition elliptic.hh:175
RangeDiscreteFunctionSpaceType::DomainType DomainType
Definition elliptic.hh:184
BaseType::QuadratureType QuadratureType
Definition elliptic.hh:189
BaseType::FaceQuadratureType FaceQuadratureType
Definition elliptic.hh:191
DomainFunctionType::LocalFunctionType DomainLocalFunctionType
Definition elliptic.hh:172
RangeFunctionType::LocalFunctionType RangeLocalFunctionType
Definition elliptic.hh:176
JacobianOperator JacobianOperatorType
Definition elliptic.hh:165
const ModelType & model() const
Definition elliptic.hh:134
DomainLocalFunctionType::RangeType DomainRangeType
Definition elliptic.hh:173
GridPartType::IntersectionIteratorType IntersectionIteratorType
Definition elliptic.hh:186
EntityType::Geometry GeometryType
Definition elliptic.hh:183
BaseType::ModelType ModelType
Definition elliptic.hh:169
IteratorType::Entity EntityType
Definition elliptic.hh:182
void jacobian(const DomainFunctionType &u, JacobianOperatorType &jOp) const
method to setup the jacobian of the operator for storage in a matrix
Definition elliptic.hh:208
RangeLocalFunctionType::RangeType RangeRangeType
Definition elliptic.hh:177