1 /*     CalculiX - A 3-dimensional finite element program                 */
2 /*              Copyright (C) 1998-2021 Guido Dhondt                          */
3 
4 /*     This program is free software; you can redistribute it and/or     */
5 /*     modify it under the terms of the GNU General Public License as    */
6 /*     published by the Free Software Foundation(version 2);    */
7 /*                    */
8 
9 /*     This program is distributed in the hope that it will be useful,   */
10 /*     but WITHOUT ANY WARRANTY; without even the implied warranty of    */
11 /*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the      */
12 /*     GNU General Public License for more details.                      */
13 
14 /*     You should have received a copy of the GNU General Public License */
15 /*     along with this program; if not, write to the Free Software       */
16 /*     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.         */
17 
18 /*     parallel part in resultsini.c	 */
19 
20 
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include <stdlib.h>
25 #include <pthread.h>
26 #include "CalculiX.h"
27 
28 static ITG *neapar=NULL,*nebpar=NULL,*mt1,*nactdof1;
29 
30 static double *b1,*v1,*veold1,*accold1,*scal11,*scal21,*cam01,*cam31;
31 
iniparll(ITG * mt,ITG * nactdof,double * b,double * v,double * veold,double * accold,double * bet,double * gam,double * dtime,double * cam,ITG * nk,ITG * num_cpus)32 void iniparll(ITG *mt,ITG *nactdof,double *b,double *v,
33 	      double *veold,double *accold,double *bet,
34 	      double *gam,double *dtime,double *cam,
35 	      ITG *nk,ITG *num_cpus){
36 
37     ITG i,idelta,isum;
38 
39     /* variables for multithreading procedure */
40 
41     ITG *ithread=NULL;
42 
43     double scal1,scal2;
44 
45     scal1=*bet**dtime**dtime;
46     scal2=*gam**dtime;
47 
48     pthread_t tid[*num_cpus];
49 
50     /* determining the element bounds in each thread */
51 
52     NNEW(neapar,ITG,*num_cpus);
53     NNEW(nebpar,ITG,*num_cpus);
54     NNEW(cam01,double,*num_cpus);
55     NNEW(cam31,double,*num_cpus);
56 
57     /* dividing the element number range into num_cpus equal numbers of
58        active entries.  */
59 
60     idelta=(ITG)floor(*nk/(double)(*num_cpus));
61     isum=0;
62     for(i=0;i<*num_cpus;i++){
63 	neapar[i]=isum;
64 	if(i!=*num_cpus-1){
65 	    isum+=idelta;
66 	}else{
67 	    isum=*nk;
68 	}
69 	nebpar[i]=isum;
70     }
71 
72     /* create threads and wait */
73 
74     mt1=mt;nactdof1=nactdof;b1=b;v1=v;veold1=veold;accold1=accold;
75     scal11=&scal1;scal21=&scal2;
76 
77     NNEW(ithread,ITG,*num_cpus);
78 
79     for(i=0; i<*num_cpus; i++)  {
80       ithread[i]=i;
81       pthread_create(&tid[i], NULL, (void *)iniparllmt, (void *)&ithread[i]);
82     }
83     for(i=0; i<*num_cpus; i++)  pthread_join(tid[i], NULL);
84 
85     /* determining the maximum cam[0] */
86 
87     cam[0]=cam01[0];
88     cam[3]=cam31[0];
89     for(i=1;i<*num_cpus;i++){
90 	if(cam01[i]>cam[0]){
91 	    cam[0]=cam01[i];
92 	    cam[3]=cam31[i];
93 	}
94     }
95 
96     SFREE(ithread);SFREE(neapar);SFREE(nebpar);SFREE(cam01);SFREE(cam31);
97 
98 }
99 
100 /* subroutine for multithreading of iniparll */
101 
iniparllmt(ITG * i)102 void *iniparllmt(ITG *i){
103 
104     ITG nea,neb,k,j;
105 
106     double bnac;
107 
108     nea=neapar[*i];
109     neb=nebpar[*i];
110 
111     for(k=nea;k<neb;++k){
112 	for(j=1;j<*mt1;j++){
113 	    if(nactdof1[*mt1*k+j]>0){
114 		bnac=b1[nactdof1[*mt1*k+j]-1];
115 	    }else{
116 		continue;
117 	    }
118 	    v1[*mt1*k+j]+=*scal11*bnac;
119 	    if(fabs(*scal11*bnac)>cam01[*i]){
120 		cam01[*i]=fabs(*scal11*bnac);
121 		cam31[*i]=nactdof1[*mt1*k+j]-0.5;
122 	    }
123 	    veold1[*mt1*k+j]+=*scal21*bnac;
124 	    accold1[*mt1*k+j]+=bnac;
125 	}
126     }
127 
128     return NULL;
129 }
130