forked from WarwickDumas/FocusFusion2D
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mesh.h
1623 lines (1247 loc) · 50.6 KB
/
mesh.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "FFxtubes.h"
#include "bandlu.h" // must not include a cpp file here!
#include <conio.h>
// no - don't need to be calling getch() in a header file !
#include "flags.h"
#include "vector_tensor.cu"
#include <windows.h> // contains max, min macros
#include <d3dx9.h>
//#include <dinput.h>
#include <dxerr.h>
#include "d3d.h"
#include "cuda_struct.h"
#ifndef mesh_h
#define mesh_h
#define CP_MAX 64
#define FLAG_CODE_LEFT 1
#define FLAG_CODE_RIGHT 2
#define FLAG_CODE_BOTTOM 3
#define FLAG_CODE_TOP 4
#define FLAG_CODE_LEFTTOP 5
#define FLAG_CODE_LEFTBOT 6
#define FLAG_CODE_RIGHTTOP 5
#define FLAG_CODE_RIGHTBOT 6
// DO NOT WANT THE SMART ARRAY CLASSES IN NVCC.
// MOVED HERE.
class smartreal
{
public:
static const int ALLOC = 8;
real * ptr;
short len, alloclen;
smartreal();
void clear();
int ReDim(int length);
void add(real x);
~smartreal();
};
class smartlong
{
public:
static const int ALLOC = 8;
long * ptr;
short len, alloclen;
// experiment with carets:
// long * ptrlast;
smartlong();
void clear();
void remove_if_exists(long what);
void remove(long what);
void IncreaseDim();
void add(long what);
void add_at_element(long what,long iInsert);
void copyfrom(smartlong & src);
bool contains(long what);
long FindIndex(long what);
void add_unique(long what);
void remove_element( long iWhich );
int remove_elements( long iStart, long iHowmany);
~smartlong();
};
class Proto {
public:
// empty class
};
class ConvexPolygon
{
public:
// This seems no good now.
// We need a dynamic array.
Vector2 coord[CP_MAX]; // change according to max desired
int status[CP_MAX];
int numCoords;
ConvexPolygon(const Vector2 & x1,const Vector2 & x2,const Vector2 & x3);
ConvexPolygon();
void SetTri(const Vector2 & x1,const Vector2 & x2, const Vector2 & x3);
void CreateClockwiseImage(const ConvexPolygon & cpSrc) ;
void CreateAnticlockwiseImage(const ConvexPolygon & cpSrc);
void inline ConvexPolygon::Clear()
{
numCoords = 0;
}
void inline ConvexPolygon::add(real x,real y)
{
numCoords++;
coord[numCoords-1].x = x;
coord[numCoords-1].y = y;
}
void inline ConvexPolygon::add(Vector2 & u)
{
numCoords++;
coord[numCoords-1] = u;
}
bool ClipAgainstHalfplane(const Vector2 & r1, const Vector2 & r2, const Vector2 & r3);
void CopyFrom(ConvexPolygon & cp);
real FindTriangleIntersectionArea(Vector2 & r1, Vector2 & r2, Vector2 & r3);
real FindQuadrilateralIntersectionArea(Vector2 & r1, Vector2 & r2, Vector2 & r3, Vector2 & r4);
real GetArea();
void ConvexPolygon::GetCentre(Vector2 & centre);
bool ConvexPolygon::GetIntersectionWithTriangle(ConvexPolygon * pPoly,Vector2 & r1, Vector2 & r2, Vector2 & r3);
bool ConvexPolygon::GetIntersectionWithPolygon(ConvexPolygon * pPoly, ConvexPolygon * pClip);
void ConvexPolygon::Integrate_Planes(Vector2 & r1, Vector2 & r2, Vector2 & r3,
real yvals1[],
real yvals2[],
real yvals3[],
real results[],
long N_planes);
void ConvexPolygon::IntegrateMass(Vector2 & r1, Vector2 & r2, Vector2 & r3,
real yvals1, real yvals2, real yvals3, real * pResult);
//real GetSideLength(int side);
real GetPrecedingSideLength(int side);
real GetSucceedingSideLength(int side);
Vector3 ConvexPolygon::Get_curl2D_from_anticlockwise_array(Vector3 A[]);
Vector2 ConvexPolygon::Get_grad_from_anticlockwise_array(real Te[]);
Vector2 ConvexPolygon::Get_Integral_grad_from_anticlockwise_array(real Te[]);
void ConvexPolygon::Get_Bxy_From_Az(real Az_array[], real * pBx,real * pBy);
Vector2 ConvexPolygon::CalculateBarycenter();
real ConvexPolygon::minmod(real n[], // output array
real ndesire[], real N,
Vector2 central );
};
class fluidnvT
{
public:
real n,T;
Vector3 v;
void Interpolate ( fluidnvT * pvv1, fluidnvT * pvv2,
Vector2 & pos1, Vector2 & pos2, Vector2 & ourpos);
};
// Can't think of a good reason we want that.
class macroscopic
{
public:
real mass, heat;
Vector3 mom;
// store macroscopic conserved quantities for doing triangle collisions
friend macroscopic operator* (const real hh,const macroscopic &vars);
};
/*class AuxVertex // for inner mesh and coarser levels
{
public:
/* real x,y;
Vector3 Temp; // always 0 except for Jz where the reverse current flows
// ?
real epsilon[NUMCELLEQNS]; // store epsilon for 7 eqns
real phi;
Vector3 A, v_e; // for phi solver.
// Note that this is to be used in fixed equilateral meshes.
long iNeighbours[MAXNEIGH];
// What is iNeighbours used for?
// Search for location of point from finer level maybe.
// No, that is triangles I'd think.
long iTriangles[MAXNEIGH];
long iCoarseTriangle; // index into the coarser mesh above for doing multimesh; also use as scratch if need be.
real weight[3];
long iVolley;
long iIndicator; // for prosecuting searches
short tri_len, neigh_len;
short flags;
//real coefficients[8][7][MAXNEIGH];
Coefficientry co;
real coeff_self[NUMCELLEQNSPLUS1][NUMCELLEQNSPLUS2];
//Coefficientry co2, co3, co4;
//real coeff_self2[NUMCELLEQNSPLUS1][NUMCELLEQNSPLUS2];
//real coeff_self4[NUMCELLEQNSPLUS1][NUMCELLEQNSPLUS2];
real regressor[NUMREGRESS][NUMCELLEQNS]; // add to phi, A, v_e
Vector3 extra_regressor; // add to chEz
real contrib_to_Az_avg, contrib_to_phi_avg;
// eqn 8 is IZ and represents effect on Iz eqn rather than its own epsilon
// smartreal coeff_extra;
// smartlong index_extra;
// We now store all coefficient information in a
// Coefficientry object. Except coeff_self.
real sum_eps_beta[NUMCELLEQNS];
real sum_beta_sq[NUMCELLEQNS]; // one for phi,Ax,Ay,Az
// Probably not used:
unsigned char has_periodic_interval; // does its interval for joining domain mesh, cross PB?
unsigned char has_periodic; // whether connects periodically to any vertices - inner or domain
unsigned char look_out_for_periodic; // if yes, then if x < 0 we rotate anticlockwise if cont is to right of 2pi/32 clockwise from this point; if x< 0, vice versa.
real gradient;
// Remember there are relatively few of the coarse vertices.
// If this prevents parallelisation, it's small comfort however.
// DEBUG:
//Tensor2 coeff_debug[320];
//Tensor2 coeff_debug2[320];
//long index_debug[320];
//long index_debug2[320];
//long debug_len;
//long debug_neighlen;
//Vector2 debug_implied_eps,debug_implied_eps2,debug_implied_eps3;
// in the case of a coarse mesh, coeff_extra is used for those
// contributions that are from non-neighbours in coarse mesh
// and those that have to be rotated. index_extra signals
// the rotation of the contribution.
real scratch;
real SSweights;
// need some storage for coefficients applying to domain vertices:
//
// eps = Temp + coeff_self * Aself + coefficients . A values
// new A += -eps/coeff_self
//
// or just, with another schema,
// new A value = coefficients . A values + Temp
//
AuxVertex();
void addtri(long iTri);
void remove_tri(long iTri);
void add_neigh(long iNeigh);
int add_neigh_unique(long iNeigh);
void PopulatePosition(Vector2 & result);
void AuxVertex::periodic_image(Vector2 & result, int side, int do_it);
int Save(FILE * fp, void * pTriArray2);
int Load(FILE * fp, void * pTriArray2);
*/
//};
/*
AuxVertex * cornerptr[3]; // store indices so that we can relate to either
// inner vertex or to an actual vertex.
AuxTriangle * neighbours[3];
int periodic; // number of points that are Clockwise wrapped relative to the others
// note that BYTE == unsigned char and creates problems with testing for decrement below zero
BYTE flags;
Vector2 cc;
real area;
Vector2 edge_normal[3];
void SetTriangleVertex(int which, AuxVertex * pInner);
void AuxTriangle::ReturnCentre(Vector2 * p_cc, AuxVertex * pVertex);
void AuxTriangle::Set(AuxVertex * p1, AuxVertex * p2, AuxVertex * p3);
void AuxTriangle::Set(AuxVertex * p1, AuxVertex * p2, AuxVertex * p3, long iTri);
void AuxTriangle::Reset(AuxVertex * p1, AuxVertex * p2, AuxVertex * p3, long iTri);
void AuxTriangle::GuessPeriodic(void);
void AuxTriangle::CalculateCircumcenter(Vector2 & cc, real * pdistsq);
bool inline AuxTriangle::has_vertex(AuxVertex * pVertex);
void AuxTriangle::MapLeft(Vector2 & u0, Vector2 & u1, Vector2 & u2);
bool AuxTriangle::ContainsPoint(real x, real y);
int AuxTriangle::TestAgainstEdge(real x,real y,
int c1, // the "start" of the relevant edge
int other, // the point opposite the relevant edge
AuxTriangle ** ppNeigh);
AuxVertex * AuxTriangle::ReturnUnsharedVertex(AuxTriangle * pTri2, int * pwhich = 0);
bool AuxTriangle::TestDelaunay(AuxVertex * pAux);
AuxTriangle::AuxTriangle();
AuxTriangle::~AuxTriangle();
void AuxTriangle::PopulatePositions(Vector2 & u0, Vector2 & u1, Vector2 & u2);
int AuxTriangle::GetLeftmostIndex();
int AuxTriangle::GetRightmostIndex();
void AuxTriangle::ReturnCircumcenter(Vector2 & u, AuxVertex * pVertex);
void AuxTriangle::RecalculateEdgeNormalVectors(bool normalise);
*/
struct fluid_NvT
{
real N[3];
Vector3 Nv[3];
real NT[3];
};
struct fluid_nvT
{
real n[3];
Vector3 nv[3];
real nT[3];
// heat density -> nT/n is temp density
// but heat density is better since we want
// usually to integrate and contribute NT.
void inline Interpolate(real beta[3],
fluid_nvT Z[3])
// 3 corners
{
n[0] = beta[0]*Z[0].n[0] +
beta[1]*Z[1].n[0] +
beta[2]*Z[2].n[0];
n[1] = beta[0]*Z[0].n[1] +
beta[1]*Z[1].n[1] +
beta[2]*Z[2].n[1];
n[2] = beta[0]*Z[0].n[2] +
beta[1]*Z[1].n[2] +
beta[2]*Z[2].n[2];
nv[0] = beta[0]*Z[0].nv[0] +
beta[1]*Z[1].nv[0] +
beta[2]*Z[2].nv[0];
nv[1] = beta[0]*Z[0].nv[1] +
beta[1]*Z[1].nv[1] +
beta[2]*Z[2].nv[1];
nv[2] = beta[0]*Z[0].nv[2] +
beta[1]*Z[1].nv[2] +
beta[2]*Z[2].nv[2];
nT[0] = beta[0]*Z[0].nT[0] +
beta[1]*Z[1].nT[0] +
beta[2]*Z[2].nT[0];
nT[1] = beta[0]*Z[0].nT[1] +
beta[1]*Z[1].nT[1] +
beta[2]*Z[2].nT[1];
nT[2] = beta[0]*Z[0].nT[2] +
beta[1]*Z[1].nT[2] +
beta[2]*Z[2].nT[2];
}
fluid_nvT Clockwise() const;
fluid_nvT Anticlockwise() const;
};
//int const MAXNEIGH = 36; // Allow that each level may increase network connection depth.
// Keep neigh, coeff handling OO for the Vertex class so that we can change to heap if/when needed.
int const MAXCOARSE = 8; // Generally should be 2 or 1
// Perhaps we should restrict to 6.
int const AUXNEIGHMAX = 14; // geometric neighbours list
// We need to find out why it is finding 14. :-(
struct ShardData
{
fluid_nvT fluidnvT[MAXNEIGH];
ConvexPolygon cp;
// Coords must match the values array.
Vector2 central;
fluid_nvT cdata;
long len;
// ConvexPolygon has 64 coords static, at present,
// so be really careful about dimensioning a lot
// of these objects.
};
int const NUM_EQNS_1 = 4; // 1 less because Iz eqn not affected by neighbours
int const NUM_AFFECTORS_1 = 4; // A,phi in neighbours
int const NUM_EQNS_2 = 5; // + Iz eqn
int const NUM_AFFECTORS_2 = 6; // + UNITY, chEzExt
struct Coeff_array
{
real co[NUM_EQNS_1][NUM_AFFECTORS_1];
// Think we will have to switch to dynamic allocation.
};
class Vertex
{
private:
// Moved neighbour data to private because I do not want them accessed
// directly.
// We need a way to access that is consistent: does not need to be
// altered whenever a change is made to the nature of storage;
// and it makes sense to populate a local static array of integers,
// both for debugging and hopefully for speed.
long izTri[MAXNEIGH];
long izNeigh[MAXNEIGH]; // index the neighbouring vertices
long tri_len,neigh_len;
long Auxneigh_len, izNeighAux[AUXNEIGHMAX];
// Do OO coefficient handling so that we can adapt later if necessary.
// memcpy sends Coeff_array contents to a local object when we want to use fast.
public:
Vector2 pos;
macroscopic Ion,Elec,Neut; // mass, heat, mom
Vector3 A, E, B, Adot; // It's important to have a stored estimate of Adot.
// This is either the estimate at the same timeslice or at half a timeslice before (empirically)
real phi;
// Let's think about this - do we need a special A_k storage in order to create that information? Economise.
long flags; // Changed to long because of the way it is used by multigrid routine.
bool has_periodic;
// Here was the storage data.
// ---------------------------
// To recalculate:
real AreaCell; // Area of Voronoi, or QV, or whatever used.
Vector2 GradTe;
// scratch data:
real n,T;
Vector3 v, Temp;
Vector2 temp2, centroid;
// other:
Vector2 a_pressure_ion, a_pressure_neut_or_overall, a_pressure_elec;
// adding for now. See later if we can get rid of.
long iVolley; // also used for showing if it is selected to submesh
long iScratch; // can be used to index coarse vertex above in submesh
long iIndicator; // used in searches
// better look again at automatic submesh routine: how it worked?
Vector2 AdvectedPosition0; // or Displacement_default
Vector2 AdvectedPosition; // for solution of move. *We could just use pos in dest mesh. But means changing some code.*
Vector2 xdot, xdotdot; // just temporary - should find suitable scratch data
Vector2 ApplDisp;
// Not clear yet if we will need for Stage III:
Vector2 PressureMomAdditionRate[3]; // in terms of particle mass ; try to reuse smth else
// Ohm's Law:
Vector3 v_e_0, v_i_0, v_n_0;
Tensor3 sigma_e, sigma_i, sigma_n;
// We assume that v_e adapts instantaneously, but the other two "laws" are for stepping to t_k+1
// so that we can do the species relative displacement ready for Stage III.
// Maybe we can find a way to economise on all this memory use. Remember though there are 100 coefficients. 6 x 4 x 4 = 96.
// +36 doubles
// ODE solving:
// _____________
real epsilon[NUM_EQNS_2];
real coeff_self[NUM_EQNS_2][NUM_AFFECTORS_2];
//real coeff[MAXNEIGH][NUM_EQNS_1][NUM_AFFECTORS_1]; // we can collate effects on Iz via neighs...
// 16 x 4 x 4 = 256 doubles -> 2048 kB
Coeff_array coeff[MAXNEIGH];
// Probably want a dynamic array for the 1st [].
// Either we have just a flatpack of reals (which could be OK),
// or, use struct with [NUM_EQNS_1][NUM_AFFECTORS_1].
// Neither of these allows us to access just as pVertex->coeff[1][0][0].
real regressor[2][4];
real circuit_regressor;
// Here, another 5 + 30 + 8 = 43 doubles.
// the following look to be unused (JRLSX only?):
//real sum_eps_beta[4];
//real sum_beta_sq[4]; // one for phi,Ax,Ay,Az // ???
// Multimesh:
//real weight[3]; // 3 corners of supertriangle for which this vertex has a weight.
//long iCoarseTriangle; // need to know which coarse vertex is nearest, ie which Voronoi cell inhabited
long iCoarseIndex[MAXCOARSE]; // usually should be 1,2,3 coarse_len in ratio 1:4:1.
real weight[3];
#ifdef FUNKYWEIGHTS
real wt_var[MAXCOARSE][4]; // maybe one day need matrix; get vector for now.
real wt_eps[MAXCOARSE][4][4]; // recruit to eps_eqn0 from all eqns.
#endif
char PBC_uplink[MAXCOARSE]; // status of coarser point relative to our point
int coarse_len; // how many affectors & affected at coarser level.
char PBC[MAXNEIGH]; // Only intending to populate for auxiliary.
// NOTE it is orientation of THIS POINT relative to neighbour
char iLevel; // what level is this vertex on?
real contrib_to_phi_avg; // so that phi level can be changed on higher levels.
// Is this needed?
// Each phi += [lc with total 1]*phi
// So if we change every coarse phi equally we are changing phi's level.
// ??
// Yet adding to 1 of them a bit more than another could mean
// that we added +1 to 5 phi's fine and -1 to 3 phi's fine.
// ??
// phi_avg probably best put only in beginning row --
// so it's moot.
real Ez_coeff_on_phi, Ez_coeff_on_phi_anode;
// temp:
real ddphidzdz_coeff_on_phi,ddphidzdz_coeff_on_phi_anode;
// DEBUG:
real predict_eps[NUM_EQNS_1];
// I think we may need to now rethink coeff[MAXNEIGH] given that we are doing coefficients for
// vertex object.
// **: Can we inherit an object that has more coeff defined?
// Heap coefficients:
// Finest ClearCoefficients should also redimension them according to neigh_len;
// for auxiliary we use a different way to clear and add coefficients.
inline Vertex() {
iLevel = -1;
this->ClearTris();
this->ClearNeighs();
this->ClearCoarseIndexList();
ClearAuxNeighs();
memset(&(sigma_i),0,sizeof(Tensor3));
memset(&(sigma_e),0,sizeof(Tensor3));
memset(&(sigma_n),0,sizeof(Tensor3));
}
long inline GiveMeAnIndex() const
{
return izTri[0];
}
long inline GetCoarseIndex(int i)
{
return iCoarseIndex[i];
}
void inline Vertex::CopyDataFrom(Vertex * pSrc)
{
A = pSrc->A;
this->Adot = pSrc->Adot;
this->B = pSrc->B;
this->E = pSrc->E;
this->Ion = pSrc->Ion;
this->Neut = pSrc->Neut;
this->Elec = pSrc->Elec;
this->phi = pSrc->phi;
this->pos = pSrc->pos;
// can same class access object's private data?
}
void inline Vertex::CopyLists(Vertex * pSrc)
{
flags = pSrc->flags;
has_periodic = pSrc->has_periodic;
memcpy(izTri,pSrc->izTri,sizeof(long)*MAXNEIGH);
memcpy(izNeigh,pSrc->izNeigh,sizeof(long)*MAXNEIGH);
tri_len = pSrc->tri_len;
neigh_len = pSrc->neigh_len;
// can same class access object's private data?
}
long inline Vertex::GetNeighIndexArray(long * arr)
{
memcpy(arr,izNeigh,sizeof(long)*neigh_len);
return neigh_len;
}
long inline Vertex::GetAuxNeighIndexArray(long * arr)
{
memcpy(arr,izNeighAux,sizeof(long)*Auxneigh_len);
return Auxneigh_len;
}
void inline Vertex::SetNeighIndexArray(long * arr, long len)
{
if (len > MAXNEIGH) {
printf("neighs > MAXNEIGH. [1] \n");
getch();
return;
};
memcpy(izNeigh,arr,sizeof(long)*len);
neigh_len = len;
} // never called?
void inline Vertex::GetCoefficients(real * coefflocal, int iNeigh) // ?
{
if (iNeigh >= neigh_len) {
printf("error iNeigh >= len Vertex::GetCoefficients\n");
return;
}
memcpy(coefflocal, &(coeff[iNeigh].co[0][0]), sizeof(real)*NUM_AFFECTORS_1*NUM_EQNS_1);
}
long inline Vertex::GetTriIndexArray(long * arr)
{
memcpy(arr,izTri, sizeof(long)*tri_len);
return tri_len;
}
void inline Vertex::SetTriIndexArray(long * arr, long len)
{
if (len > MAXNEIGH) {
printf("tris > MAXNEIGH. [1]");
getch();
return;
}
memcpy(izTri,arr, sizeof(long)*len);
tri_len = len;
}
void inline ClearTris()
{
tri_len = 0;
}
void inline ClearNeighs()
{
neigh_len = 0;
ZeroCoefficients();
}
void inline ClearAuxNeighs()
{
Auxneigh_len = 0;
}
void inline ZeroCoefficients()
{
memset(coeff_self,0,NUM_EQNS_2*NUM_AFFECTORS_2*sizeof(real));
for (int i = 0; i < MAXNEIGH; i++)
{
memset(&(coeff[i].co[0][0]),0,sizeof(real)*NUM_EQNS_1*NUM_AFFECTORS_1);
}
}
void inline ClearCoarseIndexList()
{
coarse_len = 0;
}
void inline AddUniqueCoarse(long iVertex)
{
int i;
if (coarse_len < MAXCOARSE) {
for (i = 0; i < coarse_len; i++)
if (iCoarseIndex[i] == iVertex) return;
} else {
printf("more than MAXCOARSE coarse indices added.\n");
getch();
}
iCoarseIndex[coarse_len] = iVertex;
coarse_len++;
}
bool inline Vertex::RemoveCoarseIndexIfExists(long index)
{
int i = 0;
while ((i < coarse_len) && (iCoarseIndex[i] != index)) ++i;
if (i == coarse_len) return false;
coarse_len--;
memmove(iCoarseIndex+i,iCoarseIndex+i+1,sizeof(long)*(coarse_len-i));
return true;
}
void inline Vertex::AddToCoefficients(int iNeigh,real coeff_addition[4][4])
{
int const maxi = NUM_EQNS_1*NUM_AFFECTORS_1;
real *pf64 = &(coeff_addition[0][0]);
if (iNeigh == -1) {
// add to coeff_self
real *ptr;
for (int iEqn = 0; iEqn < NUM_EQNS_1; iEqn++)
{
ptr = &(coeff_self[iEqn][0]);
for (int i = 0; i < NUM_AFFECTORS_1; i++)
{
*ptr += *pf64;
++ptr;
++pf64;
};
};
} else {
real *ptr = &(coeff[iNeigh].co[0][0]);
real *pf64 = &(coeff_addition[0][0]);
for (int i = 0; i < maxi; i++)
{
*ptr += *pf64;
++ptr;
++pf64;
};
};
}
int Vertex::AddNeighbourIfNecessaryAux (long iNeigh)
{
// this is for adding to the 'geometrically connected' array for auxiliary vertices.
int i;
for (i = 0; i < Auxneigh_len; i++)
{
if (izNeighAux[i] == iNeigh) return i;
};
if (Auxneigh_len == AUXNEIGHMAX) {
printf("too many aux neighs\n");
getch();
return -1;
};
izNeighAux[Auxneigh_len] = iNeigh;
Auxneigh_len++;
return Auxneigh_len-1;
}
int Vertex::AddNeighbourIfNecessary(
long iNeigh, char rotate_here_rel_to_there)
{
int i;
for (i = 0; i < neigh_len; i++)
{
if (izNeigh[i] == iNeigh) {
if (rotate_here_rel_to_there == PBC[i]) // CHECK HOW PBC USED: here_rel_to_there?
return i;
if (iLevel < NUM_COARSE_LEVELS-1) {
printf("rotation not in agreement. iNeigh %d rotate %d %d",
iNeigh,rotate_here_rel_to_there,PBC[i]);
// This warning comes up if we have 2 routes across PBC or not to get
// to the affected point.
// However in terms of coefficients that doesn't matter.
// It is used for PBC_uplink but not in this version.
// getch();
// For coarsest level we do not need PBC to be populated, so we can accept
// that some influences come from one way and some from another.
// (In fact, where is PBC flag ever used? Not sure - only for creating PBC_uplink?)
}
return i;
};
};
AddNeighbourIndex(iNeigh);
if (iLevel < NUM_COARSE_LEVELS-1) {
PBC[i] = rotate_here_rel_to_there;
} else {
PBC[i] = 8;
}
return i;
}
void inline Vertex::AddNeighbourIndex(long index)
{
if (neigh_len < MAXNEIGH) {
izNeigh[neigh_len] = index;
memset(&(coeff[neigh_len].co[0][0]),0,sizeof(real)*NUM_EQNS_1*NUM_AFFECTORS_1);
neigh_len++;
} else {
printf("error: neigh_len >= MAXNEIGH and attempted add neigh\n");
};
}
// Only the stupid edge points make us need a separate neigh_len,tri_len.
bool inline RemoveNeighIndexIfExists(long index)
{
int i = 0;
while ((i < neigh_len) && (izTri[i] != index)) ++i;
if (i == neigh_len) return false;
neigh_len--;
memmove(izNeigh+i,izNeigh+i+1,sizeof(long)*(neigh_len-i));
return true;
}
void inline Vertex::AddTriIndex(long index)
{
if (tri_len < MAXNEIGH) {
izTri[tri_len] = index;
tri_len++;
} else {
printf("error: tri_len >= MAXNEIGH and attempted add tri\n");
};
}
bool inline Vertex::RemoveTriIndexIfExists(long index)
{
int i = 0;
while ((i < tri_len) && (izTri[i] != index)) ++i;
if (i == tri_len) return false;
tri_len--;
memmove(izTri+i,izTri+i+1,sizeof(long)*(tri_len-i));
return true;
}
int Save(FILE * fp);
int Load(FILE * fp);
Vector2 Vertex::PopulateContiguousPosition__Guesswork(Vertex * pVertex);
};
class Triangle
{
public:
// Storing data:
Vertex * cornerptr[3]; // keep this way for ease of continuity.
Triangle * neighbours[3]; // do we want this? let's keep.
int periodic; // number of points that are Clockwise wrapped relative to the others
// note that BYTE == unsigned char and creates problems with testing for decrement below zero
unsigned char u8domain_flag;
long indicator; // for storing whether triangle has been traversed in intersection search etc
// Recalculated data:
// Can recalculate normalised or unnormalised. To make use of it, see that it points outwards.
Vector2 edge_normal[3]; // [1] means for edge with 0,2. // unwanted?
Vector2 cent;
// Vector3 B; // if A will be on vertices, B is naturally defined where?
// Best plan will be to put A on edges and triangle centroids to get B_vertex.
// We can also create B_edge by taking a quadrilateral of A.
real temp_f64, area, nT, ROC_nT; // Maybe we need NT for doing pressures.
Triangle() ;
// change most of these to inline and put them here:
void Triangle::PopulatePositions(Vector2 & u0, Vector2 & u1, Vector2 & u2) const
{
u0 = cornerptr[0]->pos;
u1 = cornerptr[1]->pos;
u2 = cornerptr[2]->pos;
};
void Triangle::MapLeftIfNecessary(Vector2 & u0, Vector2 & u1, Vector2 & u2) const;
real Triangle::GetDomainIntersectionArea(bool bUseOwnCoords, Vector2 u[3]) const;
real Triangle::GetDomainIntersectionAreaROC(Vector2 u[3],int iWhichMove,Vector2 ROC);
void Triangle::CreateCoordinates_rel_to_vertex(Vertex * pVertex,Vector2 & u1, Vector2 & u2, Vector2 & u3);
bool inline Triangle::has_vertex(Vertex * pVertex)
{
return ((cornerptr[0] == pVertex) || (cornerptr[1] == pVertex) || (cornerptr[2] == pVertex));
}
int Triangle::GetCentreOfIntersectionWithInsulator(Vector2 & result);
void Triangle::CalculateCircumcenter(Vector2 & cc, real * pdistsq);
Vector2 RecalculateCentroid(real InnermostFrillCentroidRadius,real OutermostFrillCentroidRadius);
Vector2 Triangle::GetContiguousCent_AssumingCentroidsSet(Vertex * pVertex);
real Triangle::ReturnAngle(Vertex * pVertex);
Vector3 GetAAvg() const;
//void Triangle::GenerateContiguousCentroid(Vector2 * pCentre, Triangle * pContig);
void GuessPeriodic(void);
void inline Triangle::GetParity(int parity[3]) const
{
parity[0] = (cornerptr[0]->pos.x > 0.0)?1:0;
parity[1] = (cornerptr[1]->pos.x > 0.0)?1:0;
parity[2] = (cornerptr[2]->pos.x > 0.0)?1:0;
}
int inline Triangle::GetLeftmostIndex() const
{
// Note: we could put an argument for returning the one with leftmost gradient x/y
int c1 = 0;
if (cornerptr[1]->pos.x/cornerptr[1]->pos.y < cornerptr[0]->pos.x/cornerptr[0]->pos.y)
c1 = 1;
if (cornerptr[2]->pos.x/cornerptr[2]->pos.y < cornerptr[c1]->pos.x/cornerptr[c1]->pos.y)
c1 = 2;
return c1;
}
int inline Triangle::GetRightmostIndex() const
{
int c1 = 0;
if (cornerptr[1]->pos.x/cornerptr[1]->pos.y > cornerptr[0]->pos.x/cornerptr[0]->pos.y)
c1 = 1;
if (cornerptr[2]->pos.x/cornerptr[2]->pos.y > cornerptr[c1]->pos.x/cornerptr[c1]->pos.y)
c1 = 2;
return c1;
}
int Triangle::GetCornerIndex(Vertex * pVertex);
Vertex * GetOtherBaseVertex(Vertex * pVertex);
int FindNeighbour(Triangle * pTri);
void Triangle::RecalculateEdgeNormalVectors(bool normalise);
real Triangle::ReturnNormalDist(Vertex * pOppVert);
void Triangle::GetEdgeLengths(real edge_length[]);
real Triangle::GetWeight(Vertex * pVertex); // ?
void Triangle::Return_grad_Area(Vertex *pVertex, real * p_dA_by_dx, real * p_dA_by_dy);
int Triangle::Save(FILE * fp,Vertex * pVertArray, Triangle *pTriArray);
int Triangle::Load(FILE * fp, Vertex * pVertArray, Triangle * pTriArray);
// saving and loading needed or not??
real Triangle::GetArea(void) const
{
Vector2 u[3];
MapLeftIfNecessary(u[0],u[1],u[2]);
// Use shoelace formula not Heron:
real area = 0.5*fabs(
u[0].x*u[1].y - u[1].x*u[0].y
+ u[1].x*u[2].y - u[2].x*u[1].y
+ u[2].x*u[0].y - u[0].x*u[2].y );
return area;
// Heron:
// d1 = distance(u0.x,u0.y,u1.x,u1.y);
// d2 = distance(u1.x,u1.y,u2.x,u2.y);
// d3 = distance(u0.x,u0.y,u2.x,u2.y);
// real Z = (d1+d2+d3)*0.5;
// real Heron = sqrt(Z*(Z-d1)*(Z-d2)*(Z-d3));
}
bool ContainsPoint(real x, real y); // requires transverse vectors to be set
bool ContainsPointInterior (Vertex * pVert); // calls the above function after checking for equality with cornerptr
// We are going to want to see if points lie within what? A vertex-centred cell?
void IncrementPeriodic(void);
void DecrementPeriodic(void);
//char InferRelativeWrapping(Vertex * pVert, Vertex * pVertDisco);
Vertex * Triangle::ReturnOtherSharedVertex(Triangle * pTri,Vertex * pVertex);
Vertex * ReturnUnsharedVertex(Triangle * pTri2, int * pwhich = 0);
//void Triangle::SetTriangleVertex(int which, Vertex * pVert);
int TestAgainstEdge(real x, real y,
int c1, // the "start" of the relevant edge
int other, // the point opposite the relevant edge
Triangle ** ppNeigh);
real Triangle::GetPossiblyPeriodicDistCentres(Triangle * pTri, int * prela);
bool TestAgainstEdges(real x,real y, Triangle ** ppNeigh);