44import logging
55
66import numpy as np
7+ from LoopStructural .interpolators .cython .dsi_helper import cg , constant_norm , fold_cg
78
89from LoopStructural .interpolators .discrete_interpolator import \
910 DiscreteInterpolator
@@ -17,23 +18,23 @@ class PiecewiseLinearInterpolator(DiscreteInterpolator):
1718 """
1819
1920 """
20- def __init__ (self , mesh ):
21+ def __init__ (self , support ):
2122 """
2223 Piecewise Linear Interpolator
2324 Approximates scalar field by finding coefficients to a piecewise linear
2425 equation on a tetrahedral mesh. Uses constant gradient regularisation.
2526
2627 Parameters
2728 ----------
28- mesh - TetMesh
29+ support - TetMesh
2930 interpolation support
3031 """
3132
3233 self .shape = 'rectangular'
33- DiscreteInterpolator .__init__ (self , mesh )
34+ DiscreteInterpolator .__init__ (self , support )
3435 # whether to assemble a rectangular matrix or a square matrix
3536 self .interpolator_type = 'PLI'
36- self .support = mesh
37+ self .support = support
3738
3839 self .interpolation_weights = {'cgw' : 0.1 , 'cpw' : 1. , 'npw' : 1. ,
3940 'gpw' : 1. , 'tpw' : 1. , 'ipw' : 1. }
@@ -103,73 +104,58 @@ def add_constant_gradient(self, w= 0.1, direction_vector=None, direction_feature
103104
104105 """
105106 if direction_feature is not None :
106- print ('dir fe' )
107107 direction_vector = direction_feature .evaluate_gradient (self .support .barycentre ())
108108 if direction_vector is not None :
109109 if direction_vector .shape [0 ] == 1 :
110110 # if using a constant direction, tile array so it works for cg calc
111111 direction_vector = np .tile (direction_vector ,(self .support .barycentre ().shape [0 ],1 ))
112+ if direction_vector is not None :
113+ logger .info ("Running constant gradient" )
114+ elements_gradients = self .support .get_element_gradients (np .arange (self .ntetra ))
115+ if elements_gradients .shape [0 ] != direction_vector .shape [0 ]:
116+ logger .error ('Cannot add directional CG, vector field is not the correct length' )
117+ return
118+ region = self .region .astype ('int64' )
119+
120+ neighbours = self .support .get_neighbours ()
121+ elements = self .support .get_elements ()
122+ idc , c , ncons = fold_cg (elements_gradients , direction_vector , neighbours .astype ('int64' ), elements .astype ('int64' ), self .nodes )
123+
124+ idc = np .array (idc [:ncons , :])
125+ A = np .array (c [:ncons , :])
126+ B = np .zeros (c .shape [0 ])
127+ gi = np .zeros (self .support .n_nodes )
128+ gi [:] = - 1
129+ gi [self .region ] = np .arange (0 , self .nx )
130+ idc = gi [idc ]
131+ outside = ~ np .any (idc == - 1 , axis = 1 )
112132
113-
114- # iterate over all elements
115- A , idc , B = self .support .get_constant_gradient (region = self .region ,direction = direction_vector )
116- A = np .array (A )
117- B = np .array (B )
118- idc = np .array (idc )
119-
120- gi = np .zeros (self .support .n_nodes )
121- gi [:] = - 1
122- gi [self .region ] = np .arange (0 , self .nx )
123- idc = gi [idc ]
124- outside = ~ np .any (idc == - 1 , axis = 1 )
125-
126- # w/=A.shape[0]
127- self .add_constraints_to_least_squares (A [outside , :] * w ,
128- B [outside ] * w , idc [outside , :],
129- name = 'regularisation' )
130- return
131-
132- def add_direction_constant_gradient (self , w = 0.1 , direction_vector = None , direction_feature = None ):
133- """
134- Add the constant gradient regularisation to the system where regularisation is projected
135- on a vector
136-
137- Parameters
138- ----------
139- w (double) - weighting of the cg parameter
140- direction_vector
141- direction_feature
142-
143- Returns
144- -------
145-
146- """
147- if direction_feature :
148- print ('dir fe' )
149- direction_vector = direction_feature .evaluate_gradient (self .support .barycentre ())
150- if direction_vector :
151- if direction_vector .shape [0 ] == 1 :
152- # if using a constant direction, tile array so it works for cg calc
153- direction_vector = np .tile (direction_vector ,(self .support .barycentre ().shape [0 ],1 ))
154-
155-
156- # iterate over all elements
157- A , idc , B = self .support .get_constant_gradient (region = self .region ,direction = direction_vector )
158- A = np .array (A )
159- B = np .array (B )
160- idc = np .array (idc )
161-
162- gi = np .zeros (self .support .n_nodes )
163- gi [:] = - 1
164- gi [self .region ] = np .arange (0 , self .nx )
165- idc = gi [idc ]
166- outside = ~ np .any (idc == - 1 , axis = 1 )
167-
168- # w/=A.shape[0]
169- self .add_constraints_to_least_squares (A [outside , :] * w ,
170- B [outside ] * w , idc [outside , :],
171- name = 'directional regularisation' )
172- return
133+ # w/=A.shape[0]
134+ self .add_constraints_to_least_squares (A [outside , :] * w ,
135+ B [outside ] * w , idc [outside , :],
136+ name = 'direction_regularisation' )
137+ else :
138+ logger .info ("Running constant gradient" )
139+ elements_gradients = self .support .get_element_gradients (np .arange (self .support .ntetra ))
140+ region = self .region .astype ('int64' )
141+
142+ neighbours = self .support .get_neighbours ()
143+ elements = self .support .get_elements ()
144+ idc , c , ncons = cg (elements_gradients , neighbours .astype ('int64' ), elements .astype ('int64' ), self .support .nodes ,
145+ region .astype ('int64' ))
146+
147+ idc = np .array (idc [:ncons , :])
148+ A = np .array (c [:ncons , :])
149+ B = np .zeros (A .shape [0 ])
150+ gi = np .zeros (self .support .n_nodes )
151+ gi [:] = - 1
152+ gi [self .region ] = np .arange (0 , self .nx )
153+ idc = gi [idc ]
154+ outside = ~ np .any (idc == - 1 , axis = 1 )
155+ # w/=A.shape[0]
156+ self .add_constraints_to_least_squares (A [outside , :] * w ,
157+ B [outside ] * w , idc [outside , :],
158+ name = 'regularisation' )
173159
174160
175161 def add_gradient_constraints (self , w = 1.0 ):
@@ -212,7 +198,7 @@ def add_gradient_constraints(self, w=1.0):
212198 gi = np .zeros (self .support .n_nodes ).astype (int )
213199 gi [:] = - 1
214200 gi [self .region ] = np .arange (0 , self .nx ).astype (int )
215- w /= 3
201+ # w /= 3
216202 idc = gi [tetras ]
217203 B = np .zeros (idc .shape [0 ])
218204 outside = ~ np .any (idc == - 1 , axis = 1 )
@@ -329,7 +315,6 @@ def add_interface_constraints(self, w=1.0): # for now weight all value points t
329315 points = self .get_interface_constraints ()
330316 if points .shape [0 ] > 1 :
331317 vertices , c , tetras , inside = self .support .get_tetra_for_location (points [:,:3 ])
332- # print(points[inside,:].shape)
333318
334319 gi = np .zeros (self .support .n_nodes )
335320 gi [:] = - 1
0 commit comments