Author Topic: Programma di verifica a presso-flessione deviata di sezioni generiche in c.a  (Read 134597 times)

0 Members and 1 Guest are viewing this topic.

Renato

  • Guest
A quali codici normativi fanno riferimento?
Sento che molti parlano bene di questo testo, vale la pena acquistarlo?
Ad oggi non sono riuscito a trovare un buon libro di sismica scritto in italiano.

Naturalmente non esplicitano i codici normativi.
Il volume è lottizzato tra vari autori: da quelli prima citati ad A.Vulcano e G.Monti di altre università a S.Casolo e Sanjust
Nel libro c'è un po' di tutto ma vedo solo pochi paragrafi interessanti.

Offline g.iaria

  • Veterano del forum
  • ****
  • Posts: 627
  • Karma: 220
Lasciando la questione se sia più corretto usare i valori medi o quelli di calcolo, spulciando sul Fardis ed in rete ho trovato questi due articoli scritti da lui e Biskinis:
http://www.iitk.ac.in/nicee/wcee/article/14_05-03-0153.PDF
http://www.strulab.civil.upatras.gr/sites/default/files/ACES_Report_SEE2009-01.pdf
Ovviamente questi articoli destano poco interesse per chi non è impegnato in ambiti di ricerca, tuttavia possono dare a noi comuni mortali delle indicazioni circa la precisione con cui i modelli analitici che intendiamo adottare per il calcolo della curvatura ultima riescono a riprodurre i valori dei risultati sperimentali.
Trattandosi di confronti con risultati sperimentali, credo che nei modelli analitici sono stati impiegati i valori medi delle resistenze, anche se negli articoli questo non è esplicitamente indicato.
Mettendo a confronto i vari modelli di confinamento con i risulati sperimentali il rapporto test/previsione analitica della curvatura ultima possiede i seguenti valori medi e coefficienti di variazione (deviazione standard/valor medio):
  • test monotonico / modello EC2: valore medio 1.37, c.v. 70.6%
  • test ciclico / modello EC2: valore medio 1.3, c.v. 51.3%
  • test monotonico / modello EC8: valore medio 1.04, c.v. 67.2%
  • test ciclico / modello EC8: valore medio 0.94, c.v. 47.3%
  • test monotonico / modello di Mander: valore medio 1.015, c.v. 71.5%
  • test ciclico / modello di Mander: valore medio 1.155, c.v. 52.4%
  • test monotonico / modello di Paulay&Priestley: valore medio 0.95, c.v. 74.5%
  • test ciclico / modello di Mander: valore medio 0.89, c.v. 53%
Si noti come il modello di confinamento di EC2 sia quello di gran lunga più cautelativo, sottostimando mediamente la curvatura ultima di un buon 30%.
Questo deve inoltre far pensare di quanto ancor più si sottostima la curvatura ultima se questa viene calcolata senza confinamento.
Il modello EC8 e quello di Mander sono invece molto più precisi, in particolare il primo ha inoltre una migliore dispersione dei risultati rispetto agli altri.
Il modello di Paulay e Pristley sembra invece essere un pò più ottimistico, a fronte di una dispersione dei risultati uguale agli altri.
« Last Edit: 18 April , 2012, 11:27:50 AM by g.iaria »
Un bravo scienziato è una persona con delle idee originali.
Un bravo ingegnere è una persona che fa un progetto che funziona con il minor numero possibile di idee originali.

Freeman Dyson

zax2010

  • Guest
Parte 15

Momenti di primo snervamento
Faccio un piccolo, ma necessario, riassunto delle funzioni che consentono di tracciare il dominio di rottura Mx-My di una sezione generica viste nelle parti precedenti:

La prima (parte 13):
calcola_dominio_SLU

Quella più in alto nella 'catena alimentare'. Questa funzione, facendo variare 24 volte l'inclinazione dell'asse neutro (o per meglio dire ruotando fittiziamente la sezione), alla fine restituisce 24 coppie di momenti Mx-My che determinano il dominio di rottura.

Per svolgere questo lavoro, per data inclinazione dell'asse neutro (Ma ancora non definito come posizione), la funzione passa la palla alla seconda funzione (Parte 12):

determina_asse_neutroSLU

Che esegue le varie 'prove' al fine di determinare la posizione effettiva dell'asse neutro, tale che la risultante complessiva nella sezione valga Nd.
Anche questa funzione a sua volta chiama altre funzioni che svolgono funzioni particolari, esse sono:

(Parte 10)
calcola_deform_ultime

(Parte 11)
risult_compr

risult_traz

La prima funzione, fissata una posizione di tentativo dell'asse neutro, è in grado di determinare le deformazioni a rottura della fibra più compressa della sezione e della armatura più tesa, congruenti con le 'regole' delle deformazioni a rottura.
La seconda funzione invece, sempre avendo fissato l'asse neutro di tentativo, determina la risultante di compressione agente sulla sezione, affettando in strisce sottili la parte compressa, utilizzando le uteriori funzioni:

(Parte 9)
calcola_lungh_fibra

(Parte 10)
parabola_rett

(Parte 8, oppure Parte 14)
elast_plast_indef

La terza funzione invece determina la risultante di trazione agente sulla sezione (le armature tese), utilizzando la sola funzione (Parte 8, oppure Parte 14)

elast_plast_indef

Si vedrà alla fine di questa parte che in pratica tutte le funzioni sviluppate finora con il solo fine di definire i momenti di rottura, con una semplice variazione, sono anche perfettamente in grado di calcolare i momenti di primo snervamento.
(Una delle fisse dei programmatori è quella del 'riutilizzo del codice'. Mai come in questo caso, un utilizzo accorto della strutturazione delle varie funzioni si è rivelato vincente.)

Dopo questo piccolo riassunto definiamo dunque il momento di primo snervamento. Trattasi di quel momento, per dato Nd, per cui viene raggiunto il valore di snervamento nelle barre di acciaio poste più in basso nella sezione.
Riprendiamo il solito diagramma che individua i campi di rottura:



In pratica nel determinare i momenti di rottura, come visto in precedenza, la configurazione deformata della sezione deve 'passare' per forza attraverso situazioni ben precise. Se però per epsyd invece di intendere il valore di deformazione ultima della barra a rottura, intendessimo il valore di deformazione cui corrisponde lo snervamento (ovvero espyd=fyd/Ea) si potrà continuare a trattare numericamente il problema così come è stato affrontato fino ad adesso.
Ed il tutto senza minimamente modificare tutto il 'meccanismo' che abbiamo messo in piedi per la rottura.
In pratica richiamando in modo opportuno la funzione 'madre' calcola_dominio_SLU potremo ottenere o il dominio di rottura, oppure il dominio di primo snervamento.
Per una migliore 'lettura' del tabulato e per renderlo più facilmente modificabile in futuro si è preferito creare una funzione gemella di calcola_deform_ultime;
chiamandola stavolta (il prototipo):

Code: [Select]
struct deform_ultime_sezione calcola_deform_snerv(struct poligono_sezione *,float,int,float,float);
Ed ecco la funzione:

Code: [Select]
struct deform_sezione calcola_deform_snerv(struct poligono_sezione *polic,float ymax,int npm,float yamin,float yn)
{
 int register k,np;
 float y1[NMAXPOLI],yc0,dpa,epsyd_snerv=-fyd/Ea;
 struct deform_sezione def;

 /* Calcola le massime ordinate di ogni singolo poligono */
 for (np=0;np<NMAXPOLI-1;np++)
     {
      y1[np]=-100000.0;
      for (k=0;k<=polic[np].numv-1;k++)
          {
           if (polic[np].y[k]>y1[np]) y1[np]=polic[np].y[k];
          }
     }

 /* Definisce la deformazione a snervamento della sezione - considerando i vari casi */
 if (yn>(fabs(epsyd_snerv)*ymax+polic[npm].epscu*yamin)/(polic[npm].epscu+fabs(epsyd_snerv)))
    {
     def.epsa=epsyd_snerv*(yn-ymax)/(yn-yamin);
     def.epsb=epsyd_snerv;
    }
 if (yn<=(fabs(epsyd_snerv)*ymax+polic[npm].epscu*yamin)/(polic[npm].epscu+fabs(epsyd_snerv)) && yn>yamin)
    {
     def.epsa=polic[npm].epscu;
     def.epsb=polic[npm].epscu*(yn-yamin)/(yn-ymax);
    }
 if (yn<=yamin)
    {
     yc0=yamin+polic[npm].epsc0*(ymax-yamin)/polic[npm].epscu;
     def.epsa=polic[npm].epsc0*(ymax-yn)/(yc0-yn);
     def.epsb=polic[npm].epsc0*(yamin-yn)/(yc0-yn);
    }

 /* Controlla che per tutti i contorni valga quanto ricavato */
 /* (per effetto di differenti deformazioni limite nei vari contorni) */
 for (np=0;np<=NMAXPOLI-1;np++)
     {
      if (np==npm || polic[np].numv==0) continue;

      dpa=def.epsa+(def.epsb-def.epsa)*(ymax-y1[np])/(ymax-yamin);

      if (dpa>polic[np].epscu)
         {
          if (yn<=(fabs(epsyd_snerv)*y1[np]+polic[np].epscu*yamin)/(polic[np].epscu+fabs(epsyd_snerv)) && yn>yamin)
             {
              def.epsa=polic[np].epscu*(ymax-yn)/(y1[np]-yn);
              def.epsb=polic[np].epscu*(yn-yamin)/(yn-y1[np]);
             }
          if (yn<=yamin)
             {
              yc0=yamin+polic[np].epsc0*(y1[np]-yamin)/polic[np].epscu;
              def.epsa=polic[np].epsc0*(ymax-yn)/(yc0-yn);
              def.epsb=polic[np].epsc0*(yamin-yn)/(yc0-yn);
             }
         }
     }

 return(def);
}

In pratica è la solita funzione scritta nella parte 10 (andate a vedere le varie considerazioni), avendo provveduto a sostituire nelle varie formule, al posto di epsyd la variabile epsyd_snerv ricavata tra l'altro all'interno della funzione stessa.

Bisognerà a questo punto istruire le funzioni che stanno più in alto di questa a chiamare la funzione 'giusta' per ottenere i risultati desiderati: rottura o snervamento.

A tal proposito si definiranno le macro:

Code: [Select]
#define ROTT 0
#define SNERV 1

La funzione calcola_dominio_SLU verrà adesso dotata di un parametro in più, pertanto il suo prototipo diventerà:

Code: [Select]
struct dominio_rottura calcola_dominio_SLU(float,int);
Code: [Select]
struct dominio_rottura calcola_dominio_SLU(float Nd,int dominio)
{
 corpo della funzione
}

Il corpo vero e proprio della funzione rimane di fatto inalterata, e per questo non si riporta - unica variazione la chiamata alla funzione determina_asse_neutroSLU per l'aggiunta di un parametro. Infatti l'ulteriore parametro dominio, in fase di chiamata della funzione sarà ROTT o SNERV, esempio:

Code: [Select]
dom_snerv=calcola_dominio_SLU(Nd,SNERV);
dom_rott=calcola_dominio_SLU(Nd,ROTT);

e tale variabile sarà pari pari 'girata' alla altra funzione: determina_asse_neutroSLU
anch'essa da modificare per l'aggiunta di un ulteriore parametro. Il suo prototipo diventerà:

Code: [Select]
struct risultante_n_finale determina_asse_neutroSLU(struct poligono_sezione *,struct armature_sezione,float, int);
La funzione vera e propria:

Code: [Select]
struct risultante_n_finale determina_asse_neutroSLU(struct poligono_sezione *polic,struct armature_sezione armc,float Nd,int dominio)
{
 int register k,np;
 int npm;
 float ymax=-1000000.0,yamin=+1000000.0,ntot;
 double yn,delta=10.0;
 struct risultante_n_finale nfin;
 struct deform_ultime_sezione deform;
 struct risultante_n nc,nt;

 /* Per prima cosa determina ymax della sezione */
 for (np=0;np<=4;np++)
     {
      for (k=0;k<=polic[np].numv-1;k++)
          {
           if (polic[np].y[k]>ymax) { ymax=polic[np].y[k]; npm=np; }
          }
     }
 /* Poi determina yamin tra tutte le armature */
 for (k=0;k<=armc.numarm-1;k++)
     {
      if (armc.y[k]<yamin) yamin=armc.y[k];
     }
 /* Quindi definisce un primo posizionamento dell'asse neutro */
 yn=yamin+0.8*(ymax-yamin);

 /* Inizia il ciclo iterativo alla ricerca della effettiva posizione dell'asse neutro */
 do
  {
   if (dominio==ROTT)  deform=calcola_deform_ultime(polic,ymax,npm,yamin,yn);
   if (dominio==SNERV) deform=calcola_deform_snerv(polic,ymax,npm,yamin,yn);
   /* Calcola lo sforzo normale nella parte compressa della sezione */
   nc=risult_compr(polic,armc,ymax,yamin,yn,deform);
   nt=risult_traz(armc,ymax,yamin,yn,deform);
   ntot=nc.n+nt.n;

   if (delta*(Nd-ntot)>0.0 && fabs(Nd-ntot)>1.0) { delta=-delta/5; yn+=delta; continue; }
   if (fabs(Nd-ntot)>1.0) yn+=delta;
  }
 while (fabs(Nd-ntot)>1.0 && fabs(delta)>1e-6);

 nfin.ncf.n=nc.n; nfin.ncf.x=nc.x; nfin.ncf.y=nc.y;
 nfin.ntf.n=nt.n; nfin.ntf.x=nt.x; nfin.ntf.y=nt.y;

 return (nfin);
}

Chi ha voglia di confrontare i due listati della funzione, quella della parte 12 e questa, vedrà che l'unica differenza consiste nel fatto che la funzione adesso chiama la funzione calcola_deform_ultime o calcola_deform_snerv in base al valore assunto dalla variabile dominio.

Una considerazione che esula dagli aspetti informatici. E' possibile, specie per elevati valori di  sforzo normale, che alla condizione di rottura si arrivi senza che la deformazione dell'acciaio superi mai quella di snervamento. Di fatto questo significa che il momento di primo snervamento non esiste. Oppure si potrà affermare che i due momenti coincidono.
Con la procedura di cui sopra in questo caso si ricaveranno dei momenti di primo snervamento che saranno identici a quelli di rottura.

Ultima annotazione. Mi sto tenendo abbastanza alla larga dalla diatriba: valori medi, caratterstici, di calcolo.
Quando ho iniziato questo topic il mio obiettivo era determinare momenti di rottura e pertanto per fcd o per fyd ho sempre inteso i valori di calcolo della resistenza a compressione del calcestruzzo, il valore di calcolo di snervamento dell'acciaio.
Nulla vieta in queste stesse routine di sostituire a fcd o fyd il valore che si ritiene più opportuno.
Ovviamente parlando sempre di momenti di rottura e di momenti di snervamento. Per altro....si vedrà.

Offline afazio

  • Veterano del forum
  • ****
  • Posts: 663
  • Karma: 273
  • dovizio mi delizio
    • CI si vede al Bar
(Una delle fisse dei programmatori è quella del 'riutilizzo del codice'. Mai come in questo caso, un utilizzo accorto della strutturazione delle varie funzioni si è rivelato vincente.)


già.
Chapeau
« Ogni qualvolta una teoria ti sembra essere l’unica possibile, prendilo come un segno che non hai capito né la teoria né il problema che si intendeva risolvere. »
K.P.

zax2010

  • Guest
Parte 16

Qualche passo indietro per farne qualcuno in avanti
Sarebbe giunto il momento di iniziare a parlare di curvatura.
Alla fine non sarebbe nulla di che. Definiamola, e togliamoci il pensiero.
Per curvatura si intende il rapporto:

epsc/x oppure (epsc-epsa)/d

Dove epsc è la deformazione del calcestruzzo nel suo lembo più compresso, e epsa (con segno opposto perchè ovviamente di trazione) la massima deformazione della barra di armatura più distante dall'asse neutro x, d altezza utile della sezione.
Tale rapporto in definitiva misura la 'inclinazione' che la sezione assume nella sua deformazione piana sotto date sollecitazioni.

Non ho detto nulla sulla natura di epsc e di epsa, perchè queste saranno le generiche deformazioni per 'generiche' sollecitazioni.
Però se queste deformazioni fossero quelle di rottura, troverò una curvatura di rottura, se invece fossero di snervamento, troverò una curvatura di snervamento.
Il rapporto tra la curvatura a rottura e la curvatura a snervamento viene definito 'duttilità di curvatura' e grande rilievo ha ormai assunto nelle analisi sismiche a partire dall'EC8 fino ad arrivare alle nostre NTC08.
(Avviso ai naviganti: per il momento non intendo scomodare confinamento, valori medi, caratteristici, di calcolo).

In pratica il risultato finale, quello che serve, è questo: la 'duttilità di curvatura'. Epperò è molto 'bello' andare a diagrammare la cosiddetta curva “momenti-curvatura”. Essa prevede in ascissa la curvatura, ed in ordinata il momento flettente. Il passo avanti cui accenno nel titolo di questa parte sarebbe dunque la sua costruzione per la sezione generica e genericamente caricata.
Sgombro subito il campo. Nel tracciare il diagramma partirò dal momento di primo snervamento per arrivare al momento di rottura, poco interessandomi della parte iniziale con sezione interamente reagente, poi fessurata, ecc.

Purtroppo dobbiamo però prima puntualizzare alcune cose da un punto di vista 'listato di calcolo', da qui i passi indietro del titolo.
Traduco con la simbologia finora adottata nei vari listati le formule della curvatura:

epsc/(ymax-yn) oppure (epsc-epsa)/(ymax-yamin)

Dove ymax è la massima ordinata dei vertici della sezione fittiziamente ruotata ed yamin la minima ordinata delle barre di armature della sezione fittiziamente ruotata. yn la ordinata dell'asse neutro.

Quelle elencate, sono variabili già calcolate dalle varie funzioni che arrivano a determinare momenti di rottura o momenti di primo snervamento.

Chi conosce però un po' di programmazione strutturata, ovvero quei linguaggi (ormai tutti a dire il vero) che prevedono lo spezzettamento del codice in più e più 'funzioni', sa che quanto avviene all'interno di una funzione, nella esecuzione del programma, sono affari solamente della funzione stessa.
In questi linguaggi un programma è costituito da una funzione principale che chiama delle funzioni secondarie, che a loro volta possono chiamarne altre, con un grado di 'annidamento' che può essere quel che si vuole.
Ciò che è importante qui sottolineare è che se io definisco una variabile all'interno della funzione, e se a questa variabile assegno un valore, essa 'vive' ed a quel valore posso accedere, solamente finchè mi trovo all'interno della funzione stessa. Una volta uscito dalla funzione e rientrato nella funzione che sta sopra di essa, della tipologia di variabile in oggetto non ho più traccia (non a caso queste vengono definite variabili 'locali'), e quindi tanto meno saprò che valore essa ha assunto durante l'elaborazione. A meno che proprio questa variabile non faccia parte di quanto viene restituito alla funzione chiamante.

Per fare un esempio concreto:
La funzione determina_asse_neutroSLU al suo interno dichiara la variabile double yn.
Trattasi in definitiva della posizione dell'asse neutro che proprio questa funzione ha il compito di individuare. Però alla fine tale funzione restituisce una struttura dati, la struct risultante_n_finale, che è fatta così (Parte 12):

Code: [Select]
struct risultante_n_finale
{
 struct risultante_n ncf; /* Risultante di compressione della sezione */
 struct risultante_n ntf; /* Risultante di trazione della sezione */
};

dove a loro volta ncf e ntf sono ulteriori strutture dati con questa forma (Parte 11):

Code: [Select]
struct risultante_n
{
 float n;    /* Sforzo normale risultante */
 float x;    /* Coordinate punto di applicazione risultante */
 float y;
};

ovvero ncf (risultante di compressione e suo punto di applicazione) ed ntf (risultante di trazione e suo punto di applicazione) consentono alla funzione chiamante calcola_dominio_SLU (poiché sono i valori restituiti da determina_asse_neutroSLU), di determinare i momenti di rottura (o di snervamento) della sezione. Ma questa ultima funzione non potrà affatto determinare la curvatura della sezione, poiché non conosce né la posizione dell'asse neutro, né tanto meno la deformazione di calcestruzzo e acciaio. Calcolati certamente da determina_asse_neutroSLU, ma irrimediabilemente perduti nel momento in cui si è usciti dalla funzione suddetta.

Vi ricordo che in C una funzione potrà restituire uno ed un solo 'numero'. Nel corso di tutto il listato che ho presentato però, avendo fatto uso (ed abuso) delle strutture dati di cui sopra, ho potuto bypassare il problema, facendo restituire proprio strutture dati alle varie funzioni. Ovvero: la funzione restituisce effettivamente un solo 'oggetto' alla funzione chiamante, ma questo 'oggetto', pensatelo come una scatola, a sua volta al suo interno comprende più di una informazione.
Come risolvere il problema, quindi? Semplice. Fare entrare nella 'scatola' struttura qualche ulteriore informazione e dunque spedire il tutto alla funzione chiamante.
La struttura dati struct risultante_n_finale diverrà dunque:

Code: [Select]
struct risultante_n_finale
{
 struct risultante_n ncf; /* Risultante di compressione della sezione */
 struct risultante_n ntf; /* Risultante di trazione della sezione */
 float  yn;
 float  epsc;
 float  epss;
};

Come si vede, rispetto a prima, si sono aggiunte le variabili yn, posizione dell'asse neutro,  epsc e epss deformazioni di calcestruzzo ed acciaio.

Se dunque alla fine delle sue elaborazioni determina_asse_neutroSLU, memorizza i dati di yn, epsc ed epss (variabili locali interne alla funzione) nella struttura dati appena 'ampliata' ecco che questi valori potranno essere utilizzati dalla funzione chiamante. In questo modo:

Code: [Select]
struct risultante_n_finale determina_asse_neutro(struct poligono_sezione *polic,struct armature_sezione armc,float Nd,int dominio)
{
 int register k,np;
 int npm;
 float ymax=-1000000.0,yamin=+1000000.0,ntot1,ntot;
 double yn2,yn1,yn,delta=10.0;
 struct risultante_n_finale nfin;
 struct deform_sezione deform;
 struct risultante_n nc,nt;

 /* Per prima cosa determina ymax della sezione */
 for (np=0;np<=NMAXPOLI-1;np++)
     {
      for (k=0;k<=polic[np].numv-1;k++)
          {
           if (polic[np].y[k]>ymax) { ymax=polic[np].y[k]; npm=np; }
          }
     }
 /* Poi determina yamin tra tutte le armature */
 for (k=0;k<=armc.numarm-1;k++)
     {
      if (armc.y[k]<yamin && armc.cong[k]==0) yamin=armc.y[k];
     }

 /* Quindi definisce un primo posizionamento dell'asse neutro */
 yn=yamin+0.8*(ymax-yamin);

 /* Inizia il ciclo iterativo alla ricerca della effettiva posizione dell'asse neutro */
 /* procede con un ciclo a passo variabile, diminuendo il passo di scansione di ricerca */
 /* della posizione dell'asse neutro ogni volta che la differenza tra ncompr ed ntraz cambia di segno */
 do
  {
   /* Calcola le deformazioni ultime/snervamento della sezione */
   if (dominio==ULT)   deform=calcola_deform_ultime(polic,ymax,npm,yamin,yn);
   if (dominio==SNERV) deform=calcola_deform_snerv(polic,ymax,npm,yamin,yn);
   /* Calcola lo sforzo normale nella parte compressa della sezione */
   nc=risult_compr(polic,armc,ymax,yamin,yn,deform);
   /* Calcola lo sforzo normale della parte tesa della sezione */
   nt=risult_traz(polic,armc,ymax,yamin,yn,deform);
   /* Totale sforzo normale sulla sezione da confrontare con Nd */
   ntot=nc.n+nt.n;

   if (delta*(Nd-ntot)>0.0 && fabs(Nd-ntot)>1.0) { delta=-delta/5; yn+=delta; continue; }
   if (fabs(Nd-ntot)>1.0) yn+=delta;
  }
 while (fabs(Nd-ntot)>1.0 && fabs(delta)>1e-6);

 /* Copia nella struttura dati i risultati definitivi con il posizionamento ultimo dell'asse neutro */
 nfin.ncf.n=nc.n; nfin.ncf.x=nc.x; nfin.ncf.y=nc.y;
 nfin.ntf.n=nt.n; nfin.ntf.x=nt.x; nfin.ntf.y=nt.y;
 nfin.yn=yn;
 nfin.epsc=deform.epsa;
 nfin.epss=deform.epsb;

 return (nfin);
}

Come si vede la funzione è sempre quella, ma proprio nelle ultime righe si sono aggiunte le istruzioni per copiare i valori di yn di epsa e di epsb nelle apposite variabili predisposte nella struttura dati struct risultante_n_finale nfin.

Infine sarà opportuno modificare la struttura dati (Parte 13):

Code: [Select]
struct dominio_rottura
{
 float nd;
 float mrx[24];
 float mry[24];
}

Facendola diventare così:

Code: [Select]
struct dominio_rottura
{
 float nd;            /* Sforzo normale con cui si determinano i vari momenti di rottura */
 float mrx[24];       /* vettore con i valori dei momenti Mrx del dominio */
 float mry[24];       /* vettore con i valori dei momenti Mry del dominio */
 float nrc[24];       /* vettore con valori dello sfozo normale nella parte compressa della sezione a rottura */
 float nrt[24];       /* vettore con valori dello sforzo normale nella parte in trazione della sezione a rottura */
 float xrc[24];       /* posizione della risultante dello sforzo di compressione */
 float yrc[24];       /* (nel sistema di riferimento cartesiano della sezione) */
 float xrt[24];       /* posizione della risultante dello sforzo di trazione */
 float yrt[24];       /* (nel sistema di riferimento cartesiano della sezione) */
 float epsc[24];      /* vettore con le deformazioni limite della fibra più compressa */
 float epss[24];      /* vettore con le deformazioni limite della barra di armatura più distante dall'asse neutro */
 float yn[24];        /* posizione asse neutro (nel sistema ruotato di ogni singola verifica) */
 float curv[24];      /* Curvatura della deformazione della sezione per diagrammi momenti-curvatura */
};

Vi abbiamo aggiunto parecchia carne al fuoco, come si vede, sia per poter dar modo al nostro programma di scendere nel 'dettaglio' (ovvero stampare o visualizzare da qualche parte non soltanto i valori di mx ed my, ma anche i valori di sforzo normale di trazione e compressione, posizioni delle risultanti, ecc.)
Nelle ultime posizioni abbiamo inserito anche i dati, epsc, epss, yn, curv che serviranno poi in seguito per poter parlare di curvatura. Per ognuno ho previsto 24 posizioni, poiché il dominio di rottura è previsto essere approssimato dai 24 punti in cui si calcolano i momenti.

Pertanto anche la funzione calcola_dominio_SLU a questo punto si modificherà nella sua coda finale, solamente per l'aggiunta di una serie di assegnazioni delle variabili di cui sopra. Così:

Code: [Select]
struct dominio_rottura calcola_dominio(float Nd,int dominio)
{
 int register k,np,step;
 struct poligono_sezione polic[NMAXPOLI];
 struct armature_sezione armc;
 struct risultante_n_finale nfin;
 struct dominio_rottura dom;
 float xc,yc,xt,yt;

 dom.nd=Nd;

 /* Ruota di 15° in 15° la sezione in modo da applicare sempre gli stessi algoritmi */
 /* di determinazione asse neutro che presuppongono lo stesso sempre orizzontale */
 for (step=0;step<=23;step++)
     {
      float alfa=step*0.261799; /* alfa in radianti – 0.261799=15° */
      float c=cos(alfa),s=sin(alfa);
      /* Calcola una sola volta cos(alfa) e sin(alfa) per evitare elaborazione ogni volta */

      /* Prima copia la sezione in altra struttura dati e poi la ruota di alfa */
      for (np=0;np<=NMAXPOLI-1;np++)
          {
           polic[np]=poli[np];
           for (k=0;k<=poli[np].numv-1;k++)
               {
                polic[np].x[k]= poli[np].x[k]*c+poli[np].y[k]*s;
                polic[np].y[k]=-poli[np].x[k]*s+poli[np].y[k]*c;
               }
          }

      /* Copia le armature in altra struttura dati e poi le ruota di alfa */
      armc=arm;
      for (k=0;k<=arm.numarm-1;k++)
          {
           armc.x[k]= arm.x[k]*c+arm.y[k]*s;
           armc.y[k]=-arm.x[k]*s+arm.y[k]*c;
          }

      /* Chiama la funzione per definire l'asse neutro della sezione (ruotata di alfa) */
      nfin=determina_asse_neutro(polic,armc,Nd,dominio);

      /* Ripristina il sistema di riferimento delle risultanti */
      xc=nfin.ncf.x*c-nfin.ncf.y*s;
      yc=nfin.ncf.x*s+nfin.ncf.y*c;

      xt=nfin.ntf.x*c-nfin.ntf.y*s;
      yt=nfin.ntf.x*s+nfin.ntf.y*c;

      dom.mrx[step]=nfin.ncf.n*(yc-yg)+nfin.ntf.n*(yt-yg);
      dom.mry[step]=nfin.ncf.n*(xc-xg)+nfin.ntf.n*(xt-xg);
      dom.nrc[step]=nfin.ncf.n;
      dom.nrt[step]=nfin.ntf.n;
      dom.xrc[step]=xc; dom.yrc[step]=yc;
      dom.xrt[step]=xt; dom.yrt[step]=yt;
      dom.epsc[step]=nfin.epsc;
      dom.epss[step]=nfin.epss;
      dom.yn[step]=nfin.yn;
     }

 return (dom);
}

Notate come ho ruotato il sistema di riferimento delle coordinate delle risultanti (il motivo è già spiegato nella parte 13), ed invece mi accontento di memorizzare la variabile nfin.yn tale e quale (perchè di averlo 'storto' questo valore non mi importa nulla).
La funzione suddetta restituirà alla funzione chiamante una struttura dati dom, praticamente molto più 'cicciotta' e piena di dati di prima.

Per il momento mi fermo qui, mi pare già di aver messo troppa carne al fuoco.
Mi scuserete per questa lunga dissertazione, ma essa era necessaria per poter continuare nella trattazione.
« Last Edit: 14 May , 2012, 22:50:59 PM by zax2010 »

Offline afazio

  • Veterano del forum
  • ****
  • Posts: 663
  • Karma: 273
  • dovizio mi delizio
    • CI si vede al Bar
Quando un forum diventa istruttivo. COme si farebbe su facebook: "mi piace"
« Ogni qualvolta una teoria ti sembra essere l’unica possibile, prendilo come un segno che non hai capito né la teoria né il problema che si intendeva risolvere. »
K.P.

zax2010

  • Guest
Parte 17

Momenti con data curvatura
Avendo definito la curvatura come:

epsc/(ymax-yn) oppure (epsc-epsa)/(ymax-yamin)

abbiamo visto come si è dovuto fare un certo lavoro 'preparatorio', ma tutto sommato non sconvolgente, per poter determinare il valore di curvatura che la sezione assume in corrispondenza dello snervamento e della rottura.
Per precisione 'didattica' ricordo che le curvature in tali punti dipendono, oltre che da geometria della sezione, dalle armature e dalle caratteristiche dei materiali, anche e soprattutto dal valore di sforzo normale della sezione.
E' intuibile infatti che maggiore è lo sforzo normale di compressione sulla sezione, minore diventa lo 'spazio' che separa la condizione di rottura da quella di snervamento, e più prossime tra loro diventano le rispettive curvature.
Se la duttilità sezionale è misurata dal rapporto tra curvatura a rottura e curvatura a snervamento, esso diventa via via più piccolo convergendo ad 1.0 per valori elevati di sforzo normale.

In questa parte si vedrà come calcolare, per dato sforzo normale, il momento flettente 'espresso' dalla sezione ad una data curvatura.
Ovvero si fisserà una curvatura compresa tra quella di snervamento e quella di rottura e si calcolerà il momento flettente corrispondente (i due momenti flettenti a dire il vero, poiché sempre nel caso generico ci poniamo).
Anche in questo caso Afazio sarà contento. Poiché basta un minimo di comprensione del problema per poter riutilizzare il solito ed ormai trito codice già scritto ed ampiamente sperimentato.
Guardiamo il seguente diagramma:



In pratica la barra inclinata in rosso che ho tracciato nel solito diagramma che indica le possibili configurazioni deformative della sezione a rottura, di fatto 'segna' una possibile curvatura (inclinazione della sezione sotto sollecitazione). Invece di seguire il solito 'percorso', ovvero massima deformazione nell'acciaio teso (rotazione attorno al punto A) o massima deformazione nel cls compresso (rotazione attorno al punto B), se decidiamo di non modificare l'inclinazione della barretta segnata nel grafico, di fatto ricercheremo una configurazione deformata della sezione sotto dato sforzo normale, per curvatura 'fissa'.
Ovvero definita la variabile curv (data dalle espressioni riportate), le deformazioni possibili ai lembi estremi della sezione potranno essere solamente:

epsc=curv*(ymax-yn)
epsa=-curv*(yn-yamin)


(ymax massima ordinata della sezione, yamin minima ordinata delle barre di armatura, yn la posizione dell'asse neutro nel sistema di riferimento la vera 'variabile' del problema).
che altro non sono le formule inverse viste sopra.
Se volessimo avere una visione 'geometrica' della situazione queste formule indicano che le deformazioni da ricercare nei lembi inferiore e superiore si ottengono semplicemente traslando la barra rossa tracciata nella figura superiore, senza farla ruotare (come dalle frecce gialle che ho disegnato). Traslazione che comporta un aumento o diminuzione della parte compressa della sezione (ovvero di posizione dell'asse neutro) alla ricerca di quella configurazione che equilibri lo sforzo normale Nd agente nella sezione.

In pratica si riconosce che il procedimento finora seguito per ricavare momenti di rottura e di snervamento potrà continuare ad essere utilizzato, con le solite iterazioni alla ricerca dell'asse neutro, con il solito calcolo dello sforzo normale che le parti compresse e tese sono in grado di esplicare, ma con un differente 'metodo' di determinazione delle massime deformazioni della sezione, lasciando inalterata tutta la costruzione già fatta circa la determinazione corretta dell'asse neutro, e di conseguenza dei momenti, stavolta non di rottura o snervamento, ma per data curvatura della sezione.

In questa parte mi limiterò a riscrivere la sola funzione determina_asse_neutro, nella prossima puntata invece vedrò di sviluppare una funzione di 'più alto livello' che utilizzerà proprio quest'ultima per i propri fini.

Aggiungo intanto una macro alle due già definite nella parte 15:

Code: [Select]
#define ROTT 0
#define SNERV 1
#define CURV 2

Quindi ridefinisco il prototipo di determina_asse_neutro aggiungendo un ulteriore parametro, ovvero la curvatura curv per cui si vuol determinare l'asse neutro e relativi momenti flettenti associati:

Code: [Select]
struct risultante_n_finale determina_asse_neutro(struct poligono_sezione *,struct armature_sezione,float,int,float);
Prima del corpo di questa funzione vera e proprio devo definire una altra funzione che mi consente di calcolare correttamente le deformazioni nella sezione per data curvatura (con prototipo e quindi corpo della funzione):

Code: [Select]
struct deform_sezione calcola_deform_curv(float,float,float,float);

struct deform_sezione calcola_deform_curv(float ymax,float yamin,float yn,float curv)
{
 struct deform_sezione def;

 def.epsa=curv*(ymax-yn);
 def.epsb=-curv*(yn-yamin);

 return(def);
}

Potete vedere come si tratta di funzioncina stupida stupida, poiché ho semplicemente implementato le due formule sopra viste, assegnando il risultato ai membri della struttura struct deform_sezione (ricordo che epsa è la deformazione nella parte alta della sezione – lembo compresso, epsb la deformazione della parte bassa della sezione – armatura in trazione, e che epsb essendo di trazione è negativa per definizione). Non ho volutamente introdotto alcun controllo sulla entità di tali deformazioni, poiché intendo passare alla funzione curvature comprese tra quelle di snervamento e quelle di rottura.

Infine la funzione vera e propria determina_asse_neutro, eccola qui:

Code: [Select]
struct risultante_n_finale determina_asse_neutro(struct poligono_sezione *polic,struct armature_sezione armc,float Nd,int dominio,float curv)
{
 int register k,np;
 int npm;
 float ymax=-1000000.0,yamin=+1000000.0,ntot1,ntot;
 double yn2,yn1,yn,delta=10.0;
 struct risultante_n_finale nfin;
 struct deform_sezione deform;
 struct risultante_n nc,nt;

 /* Per prima cosa determina ymax della sezione */
 for (np=0;np<=NMAXPOLI-1;np++)
     {
      for (k=0;k<=polic[np].numv-1;k++)
          {
           if (polic[np].y[k]>ymax) { ymax=polic[np].y[k]; npm=np; }
          }
     }
 /* Poi determina yamin tra tutte le armature */
 for (k=0;k<=armc.numarm-1;k++)
     {
      if (armc.y[k]<yamin && armc.cong[k]==0) yamin=armc.y[k];
     }

 /* Quindi definisce un primo posizionamento dell'asse neutro */
 yn=yamin+0.8*(ymax-yamin);

 /* Inizia il ciclo iterativo alla ricerca della effettiva posizione dell'asse neutro */
 /* procede con un ciclo a passo variabile, diminuendo il passo di scansione di ricerca */
 /* della posizione dell'asse neutro ogni volta che la differenza tra ncompr ed ntraz cambia di segno */
 do
  {
   /* Calcola le deformazioni ultime/snervamento della sezione */
   if (dominio==ULT)   deform=calcola_deform_ultime(polic,ymax,npm,yamin,yn);
   if (dominio==SNERV) deform=calcola_deform_snerv(polic,ymax,npm,yamin,yn);
   if (dominio==CURV)  deform=calcola_deform_curv(ymax,yamin,yn,curv);
   /* Calcola lo sforzo normale nella parte compressa della sezione */
   nc=risult_compr(polic,armc,ymax,yamin,yn,deform);
   /* Calcola lo sforzo normale della parte tesa della sezione */
   nt=risult_traz(polic,armc,ymax,yamin,yn,deform);
   /* Totale sforzo normale sulla sezione da confrontare con Nd */
   ntot=nc.n+nt.n;

   if (delta*(Nd-ntot)>0.0 && fabs(Nd-ntot)>1.0) { delta=-delta/5; yn+=delta; continue; }
   if (fabs(Nd-ntot)>1.0) yn+=delta;
  }
 while (fabs(Nd-ntot)>1.0 && fabs(delta)>1e-6);

 /* Copia nella struttura dati i risultati definitivi con il posizionamento ultimo dell'asse neutro */
 nfin.ncf.n=nc.n; nfin.ncf.x=nc.x; nfin.ncf.y=nc.y;
 nfin.ntf.n=nt.n; nfin.ntf.x=nt.x; nfin.ntf.y=nt.y;
 nfin.yn=yn;
 nfin.epsc=deform.epsa;
 nfin.epss=deform.epsb;

 return (nfin);
}

Rispetto alle altre volte la variabile dominio potrà avere valori ULT, SNERV, e adesso anche CURV. In funzione di questi 'indici' la funzione diventa 'tutto fare'. Può determinare l'asse neutro in condizioni di rottura, o di snervamento, o per dato valore della curvatura. Dal valore di asse neutro la funzione chiamante è poi in grado di determinare i momenti flettenti associati (di rottura, di snervamento, per data curvatura).

Spendo qualche parola in più sulle macro che ho definito. In effetti ULT, SNERV e CURV, non sono altro che i numeri 0,1 e 2. Avrei potuto scrivere tranquillamente nel listato:

Code: [Select]
   if (dominio==0) deform=calcola_deform_ultime(polic,ymax,npm,yamin,yn);
   if (dominio==1) deform=calcola_deform_snerv(polic,ymax,npm,yamin,yn);
   if (dominio==2) deform=calcola_deform_curv(ymax,yamin,yn,curv);

Ottenendo esattamente gli stessi esiti nelle elaborazioni. In effetti però chi volesse domani rivedere questo pezzetto di codice dovrebbe capire cosa fa effettivamente la funzione se la variabile dominio è uguale a 0, ad 1, a 2. E' facile in questo caso capirlo dalla struttura del listato e dalle funzioni richiamate. Ma possono esserci casi in cui questo non è così evidente. Avere quindi la possibilità di ribattezzare questi indici numerici (non sono nemmeno delle variabili) con un nome 'evocativo' migliora la leggibilità del listati.
I primi programmatori in C (o forse in linguaggi più antichi che prevedevano questa possibilità) hanno pensato bene di rendere ancora più evidente questi indici battezzandoli con nomi, non soltanto 'evocativi', ma anche scritti in maiuscolo (da qui il nome MACRO ad essi assegnato), in modo che spiccassero in tabulati che normalmente sono scritti tutti con lettere minuscole.
A tal proposito il C è un linguaggio 'case sensitive' ovvero la variabile (esempio) dominio, è diversa da Dominio. In ogni caso tutte le parole chiave del C (sono solamente una ventina, ad esempio for, oppure float) vanno sempre scritte in minuscolo, altrimenti non vengono correttamente interpretate come tali.

Tornando al problema esaminato una osservazione che ci servirà la prossima volta.

Abbiamo visto che per determinare il dominio di rottura e di snervamento abbiamo fittiziamente ruotato la sezione, piuttosto che l'asse neutro. Questo al fine di semplificare il problema analitico e di riutilizzare praticamente sempre un unico set di funzioni che ci ha permesso di superare in maniera quasi indolore il fatto che la sezione è di forma assolutamente generica.
Ciò che voglio sottolineare è che per data inclinazione dell'asse neutro si determineranno dei momenti flettenti di rottura, con asse momenti x ed y, che stanno in un determinato rapporto (asse vettore del momento risultante con certa inclinazione).
Orbene, in funzione della effettiva geometria della sezione, i momenti di snervamento Mx ed My, sempre per data inclinazione dell'asse neutro, avranno rapporto in generale differente. Così come lo stesso 'fenomeno' potrà riscontrarsi per momenti flettenti calcolati per date curvature ma a parità sempre di inclinazione dell'asse neutro.
Questo implica, e lo vedremo la prossima volta, che se vogliamo un diagramma momenti-curvatura che generalmente sta su un piano, dovremmo fare qualche ulteriore considerazione.

« Last Edit: 21 May , 2012, 23:45:35 PM by zax2010 »

zax2010

  • Guest
Parte 18

Completiamo il discorso sulle curvature
Guardiamo questo diagramma:



Non ha importanza da quale sezione esso derivi. In grigio è segnato il dominio di primo snervamento, ed in rosso il dominio di rottura. Il tutto per un certo valore di Nd.
Come già abbiamo visto con le varie routine, abbiamo sempre calcolato per 24 differenti assetti di inclinazione dell'asse neutro, la coppia di momenti (di snervamento o di rottura).
Preso un punto sulla curva snervamento del diagramma di cui sopra ed il corrispondente nel diagramma di rottura, ad essi è associata una ben precisa curvatura.
Poichè abbiamo visto nella parte precedente come procedere al calcolo dei momenti 'espressi' dalla sezione per data curvatura, ipotizzando di suddividere in 10 parti la differenza tra le 2 curvature di cui sopra, potremmo disegnare 9 ulteriori punti tra il punto del diagramma di snervamento ed il punto sul diagramma di rottura.
E calcolando questi ulteriori punti per tutti gli assetti possibili dell'asse neutro ricavare ulteriori 9 domini concentrici più o meno tra loro e ai due domini sopra riportati.
Attenzione però, questo 'esercizio' è di fatto inutile. Infatti tutti i punti uniti, nel sistema di riferimento scelto (Nd,Mx,My) non sarebbero dotati della stessa curvatura, ma semplicemente avrebbero lo stesso 'step' di differenza di curvatura funzione di quanto distante è la curvatura tra il punto di snervamento ed il punto di rottura.

Pertanto se vogliamo capire meglio come si comporta la nostra sezione, dobbiamo modificare la tipologia di rappresentazione. Ovvero fermo restando gli assi Mx ed My, l'asse ortogonale allo schermo non dovrà più essere Nd, ma proprio la curvatura.
Determinando quindi un diagramma tridimensionale che pressapoco avrebbe questa forma:



In cui la parte più 'piatta', quella posteriore e più blu risulta essere il dominio di snervamento, ma che non è compreso in un piano, ed a maggior ragione non è compreso in un piano il dominio di rottura, la parte di 'corona' del presente diagramma, che presenta dei picchi di curvatura in corrispondenza degli assi principali della sezione che decrescono notevolmente quando l'asse neutro assume inclinazione molto 'deviate'.
Vediamo, utilizzando ovviamente le routine già descritte nella parte precedente, come fare per ricavare tutte le coordinate dei vari punti che costituiscono il presente diagramma.

Facciamo anzitutto un triplo salto carpiato, definendo una struttura dati 'annidata'.

Code: [Select]
struct dom_momenti_curv
{
 struct dominio_rottura mcurv[12];
};

Sostanzialmente si tratta di un vettore di domini di rottura (per la precisione 12 strutture di tipo dominio_rottura differenti - che vi ricordo contiene al suo interno parecchie altre variabili 'elementari' e tutte relative non ad un solo punto ma all'intero dominio costituito da 24 punti), che però in forma di struttura dati potranno essere trattati alla stessa stregua di una singola variabile (e dunque valore restituibile da una funzione)

All'interno della funzione che calcolerà le variabili da piazzare in mcurv, definirò una variabile di tipo dom_momenti_curv, variabile che a fine elaborazioni restituirò alla funzione chiamante.

Spiego prima l'ossatura della funzione, per poi vedere meglio in dettaglio. Anzitutto si calcolano i domini a snervamento ed a rottura. E questo la funzione lo fa semplicemente richiamando la solita funzione calcola_dominio. Con i singoli valori per ogni punto duale di tali domini, si ricava uno step di curvatura e si ricavano quindi 'manualmente' stavolta, punto per punto i valori dei momenti flettenti per data curvatura, dovendo chiamare ogni volta la funzione determina_asse_neutro precedentemente vista.

Code: [Select]
/* Prototipo della funzione */
struct dom_momenti_curv diagramma_m_curv(float);

Code: [Select]
/* Corpo della funzione */
struct dom_momenti_curv diagramma_m_curv(float nd)
{
 int register step,k,ncurv,np,ns;
 int register unsigned j;
 int numcomb;
 float curv_snerv,curv_ult;
 float ymax,yamin;
 struct poligono_sezione polic[NMAXPOLI];
 struct armature_sezione armc;
 struct risultante_n_finale nfin;
 struct dom_momenti_curv m;
 char buffer[100],num[10];

 /* Comincia ad assegnare i valori ai singoli punti del diagramma */
 m.mcurv[0].nd=0.0;
 for (k=0;k<=23;k++)
     {
      m.mcurv[0].mrx[k]=0.0;  m.mcurv[0].mry[k]=0.0;
      m.mcurv[0].nrc[k]=0.0;  m.mcurv[0].nrt[k]=0.0;
      m.mcurv[0].xrc[k]=0.0;  m.mcurv[0].yrc[k]=0.0;
      m.mcurv[0].xrt[k]=0.0;  m.mcurv[0].yrt[k]=0.0;
      m.mcurv[0].epsc[k]=0.0; m.mcurv[0].epss[k]=0.0;
      m.mcurv[0].yn[k]=0.0;   m.mcurv[0].curv[k]=0.0;
     }

 m.mcurv[1]= calcola_dominio(nd,SNERV);
 m.mcurv[11]=calcola_dominio(nd,ULT);

 for (ncurv=0;ncurv<=23;ncurv++) /* Diagramma momento-curvatura per data inclinazione dell'asse neutro */
     {
      float alfa=ncurv*0.261799; /* alfa in radianti – 0.261799=15° */
      float c=cos(alfa),s=sin(alfa);
      /* Calcola una sola volta cos(alfa) e sin(alfa) per evitare elaborazione ogni volta */

      /* Prima copia la sezione in altra struttura dati e poi la ruota di alfa */
      for (np=0;np<=NMAXPOLI-1;np++)
          {
           polic[np]=poli[np];
           for (k=0;k<=poli[np].numv-1;k++)
               {
                polic[np].x[k]= poli[np].x[k]*c+poli[np].y[k]*s;
                polic[np].y[k]=-poli[np].x[k]*s+poli[np].y[k]*c;
               }
          }

      /* Copia le armature in altra struttura dati e poi le ruota di alfa */
      armc=arm;
      for (k=0;k<=arm.numarm-1;k++)
          {
           armc.x[k]= arm.x[k]*c+arm.y[k]*s;
           armc.y[k]=-arm.x[k]*s+arm.y[k]*c;
          }

      /* Poi determina massima ascissa compressa e minima armatura tesa per determinare altezza utile sezione */
      ymax=-100000.0;
      for (np=0;np<=NMAXPOLI-1;np++)
          {
           for (k=0;k<=polic[np].numv-1;k++) if (ymax<polic[np].y[k]) ymax=polic[np].y[k];
          }
      yamin=100000.0;
      for (k=0;k<=armc.numarm-1;k++) if (yamin>armc.y[k]) yamin=armc.y[k];

      m.mcurv[11].curv[ncurv]=(m.mcurv[11].epsc[ncurv]+fabs(m.mcurv[11].epss[ncurv]))/(ymax-yamin);
      m.mcurv[1].curv[ncurv]=(m.mcurv[1].epsc[ncurv]+fabs(m.mcurv[1].epss[ncurv]))/(ymax-yamin);

      for (step=2;step<=10;step++) /* Singoli punti diagramma-curvatura tra snervamento e rottura per data inclinazione dell'asse neutro */
          {
           float curv,xc,yc,xt,yt;

           curv=m.mcurv[1].curv[ncurv]+(step-1)*(m.mcurv[11].curv[ncurv]-m.mcurv[1].curv[ncurv])/10.0;

           nfin=determina_asse_neutro(polic,armc,nd,CURV,curv);

           /* Ripristina il sistema di riferimento delle risultanti */
           xc=nfin.ncf.x*c-nfin.ncf.y*s;
           yc=nfin.ncf.x*s+nfin.ncf.y*c;

           xt=nfin.ntf.x*c-nfin.ntf.y*s;
           yt=nfin.ntf.x*s+nfin.ntf.y*c;

           m.mcurv[step].mrx[ncurv]=nfin.ncf.n*(yc-yg)+nfin.ntf.n*(yt-yg);
           m.mcurv[step].mry[ncurv]=nfin.ncf.n*(xc-xg)+nfin.ntf.n*(xt-xg);
           m.mcurv[step].nrc[ncurv]=nfin.ncf.n;
           m.mcurv[step].nrt[ncurv]=nfin.ntf.n;
           m.mcurv[step].xrc[ncurv]=xc; m.mcurv[step].yrc[ncurv]=yc;
           m.mcurv[step].xrt[ncurv]=xt; m.mcurv[step].yrt[ncurv]=yt;
           m.mcurv[step].epsc[ncurv]=nfin.epsc;
           m.mcurv[step].epss[ncurv]=nfin.epss;
           m.mcurv[step].yn[ncurv]=nfin.yn;
           m.mcurv[step].curv[ncurv]=curv;
          }
     }
 return (m);
}

Quindi calcolati con due sole istruzioni:

Code: [Select]
mcurv[1]= calcola_dominio(nd,SNERV);
mcurv[11]=calcola_dominio(nd,ULT);

i domini di snervamento e rottura, la funzione prosegue, per assegnate inclinazioni dell'asse neutro (contatore ncurv) a ricavare la posizione effettiva dei vertici della sezione e delle armature (ricordatevi la rotazione, non dell'asse neutro, ma fittizia della sezione), e quindi con le curvature a rottura e snervamento ricava tramite il contatore step, il valore effettivo di curvatura compreso tra la curvatura a snervamento ed a rottura:

Code: [Select]
curv=m.mcurv[1].curv[ncurv]+(step-1)*(m.mcurv[11].curv[ncurv]-m.mcurv[1].curv[ncurv])/10.0;
(Dove il diviso 10 si riferisce al fatto che si sta procedendo per 10 step successivi tra la curvatura a snervamento e quella a rottura), e da questo, dato in pasto alla funzione:

Code: [Select]
determina_asse_neutro(polic,armc,nd,CURV,curv);
ricava i dati 'grezzi' per poter infine riempire la variabile m.mcurv[step], che opportunamente richiamata sarà in grado di far disegnare proprio il diagramma visto sopra.

In sintesi si avrà una funzione chiamante più meno fatta in questo modo:

Code: [Select]
.
struct dom_momenti_curv m;
.
m=diagramma_m_curv(soll[k].nd);
.
.

E si avranno dunque tutti i valori per poter disegnare il diagramma tridimensionale della seconda figura. Si è continuato a 'portarsi dietro' tante variabili parziali, quali le deformazioni dei materiali, o la posizione delle risultanti, in modo all'occorrenza di visualizzare o stampare i dati numerici.

E per disegnare invece un diagramma 'classico', bidimensionale in cui in ascissa si abbia la curvatura ed in ordinata i momenti?
Per quello ho fatto una semplice interpolazione dal diagramma 3D. Vista l'inclinazione del vettore Mdy/Mdx (dove Mdx e Mdy sono i valori dei momenti flettenti di calcolo associati al valore Nd di sforzo normale della singola combinazione di sollecitazioni esterne sulla sezione), proietto con semplice interpolazione lineare l'intersezione di questo piano con il diagramma 3D.
Ovviamente ci sarebbe il modo di poter affinare meglio la soluzione facendo variare più fittamente l'inclinazione dell'asse neutro, per data curvatura in modo da avere dei valori Mx ed My che stiano proprio nel rapporto dato dalle sollecitazioni flettenti esterne.

Come al solito, altra struttura dati:

Code: [Select]
struct d_curv
{
 float mx[12];
 float my[12];
 float nc[12];
 float nt[12];
 float xc[12];
 float yc[12];
 float xt[12];
 float yt[12];
 float epsc[12];
 float epss[12];
 float yn[12];
 float ang[12];
 float m[12];
 float crv[12];
};

Con tutte le variabili del caso in numero di 12, come i punti del diagramma (punto 0 origine, punto 1 il punto di snervamento, punto 11 il punto di rottura, punti intermedi tra 1 e 11 a curvatura via via crescenti).
La porzione di codice dovrà inizialmente, per ogni singolo punto del diagramma momenti-curvatura (variabile contatore step) trovare l'intersezione tra il raggio vettore di inclinazione Mdy/Mdx ed il corrispondente dominio (con il contatore ncurv), indi interpolare linearmente tra il punto ncurv ed ncurv+1 del suddetto dominio. In questo modo:

 
Code: [Select]
/* Determina il diagramma M-curv della specifica sollecitazione */
 dcurv.m[0]=0.0; dcurv.crv[0]=0.0;
 for (step=1;step<=11;step++)
     {
      for (ncurv=0;ncurv<=23;ncurv++)
          {
           int ncurvp1;
           double mdom,qdom,mvx,mvy;
           float xsb,xda,ysb,yda;

           if (ncurv==23) ncurvp1=0; else ncurvp1=ncurv+1;

           /* Parametri della retta del diagramma-3D momenti-curvatura */
           mdom=(m.mcurv[step].mry[ncurvp1]-m.mcurv[step].mry[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
           qdom=m.mcurv[step].mry[ncurv]-mdom*m.mcurv[step].mrx[ncurv];
           /* Determina i vertici del rettangolo basso sinistra e alto destra della retta del dominio */
           if(m.mcurv[step].mrx[ncurvp1]>=m.mcurv[step].mrx[ncurv]) { xsb=m.mcurv[step].mrx[ncurv];   xda=m.mcurv[step].mrx[ncurvp1]; }
           else                                                     { xsb=m.mcurv[step].mrx[ncurvp1]; xda=m.mcurv[step].mrx[ncurv];   }
           if(m.mcurv[step].mry[ncurvp1]>=m.mcurv[step].mry[ncurv]) { ysb=m.mcurv[step].mry[ncurv];   yda=m.mcurv[step].mry[ncurvp1]; }
           else                                                     { ysb=m.mcurv[step].mry[ncurvp1]; yda=m.mcurv[step].mry[ncurv];   }
           /* Intersezione tra diagramma-3D e retta vettore sollecitazioni */
           if (soll[numcomb].mx!=0.0)
              {
               mvx=qdom/(soll[numcomb].my/soll[numcomb].mx-mdom);
               mvy=soll[numcomb].my/soll[numcomb].mx*mvx;
              }
           else /* Vettore verticale */
              {
               mvx=0.0;
               mvy=qdom;
              }

           if (mvx>=xsb && mvx<=xda && mvy>=ysb && mvy<=yda && soll[numcomb].mx*mvx>=0.0 && soll[numcomb].my*mvy>=0.0)
              {
               dcurv.mx[step]=mvx;
               dcurv.my[step]=mvy;
               dcurv.m[step]=sqrt(mvx*mvx+mvy*mvy);
               dcurv.crv[step]=m.mcurv[step].curv[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].curv[ncurvp1]-m.mcurv[step].curv[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.nc[step]=m.mcurv[step].nrc[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].nrc[ncurvp1]-m.mcurv[step].nrc[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.xc[step]=m.mcurv[step].xrc[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].xrc[ncurvp1]-m.mcurv[step].xrc[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.yc[step]=m.mcurv[step].yrc[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].yrc[ncurvp1]-m.mcurv[step].yrc[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.nt[step]=m.mcurv[step].nrt[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].nrt[ncurvp1]-m.mcurv[step].nrt[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.xt[step]=m.mcurv[step].xrt[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].xrt[ncurvp1]-m.mcurv[step].xrt[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.yt[step]=m.mcurv[step].yrt[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].yrt[ncurvp1]-m.mcurv[step].yrt[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.epsc[step]=m.mcurv[step].epsc[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].epsc[ncurvp1]-m.mcurv[step].epsc[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.epss[step]=m.mcurv[step].epss[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].epss[ncurvp1]-m.mcurv[step].epss[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.yn[step]=m.mcurv[step].yn[ncurv]+(mvx-m.mcurv[step].mrx[ncurv])*(m.mcurv[step].yn[ncurvp1]-m.mcurv[step].yn[ncurv])/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               dcurv.ang[step]=ncurv*0.261799+(mvx-m.mcurv[step].mrx[ncurv])*0.261799*(ncurvp1-ncurv)/(m.mcurv[step].mrx[ncurvp1]-m.mcurv[step].mrx[ncurv]);
               break;
              }
          }
     }

Vediamo velocemente come funziona la cosa. Innanzitutto si determina l'equazione della retta del singolo segmento costituente il dominio, con il fattore angolare mdom e l'intersezione con l'asse delle ordinate qdom.
Si stabiliscono i vertici del rettangolo, ordinati da quello in basso a sinistra a quello in alto a destra, disegnato dal segmento del dominio (che ne è la diagonale), in modo che calcolata l'intersezione di tale segmento con il raggio vettore di inclinazione Mdy/Mdx si possa decidere se essa intersezione è interna al segmento stesso. Se si, si procede alla interpolazione lineare tra i il punto ncurv ed ncurv+1, e si interrompe il ciclo (istruzione break; perchè non ha senso continuare inutilmente l'elaborazione se si è già trovato cosa si cercava).

Offline genoveffo

  • Novizio del forum
  • *
  • Posts: 2
  • Karma: 2
  • Novizio
ottimo

Offline Salvatore Bennardo

  • Nonno del forum
  • *****
  • Posts: 1003
  • Karma: 123
ottimo

Ora finalmente sai cosa ti eri perso nella vita fino ad oggi.
« Last Edit: 23 May , 2013, 18:50:51 PM by Salvatore Bennardo »
massima mai scaduta: la tua sinistra non sappia mai del bene che fa la tua destra (sempre che sia vero che lo faccia)
sin²(theta)=omega*sin(alfa)
Mitico Crozza! Commento di Bossi dopo le disastrose elezioni amministrative: "Poteva andare peggio. Potevo avere più figli..." (per come replicato in un post da ing.Max)

Offline genoveffo

  • Novizio del forum
  • *
  • Posts: 2
  • Karma: 2
  • Novizio
Per la verità il programma in questione io l'ho completato qualche mese fa utilizzando excel e poi matlab , ho implementato anche i rinforzi in frp, in acciaio, e sto lavorando sulle verifiche al fuoco. Mi fa piacere che anche altre persone se ne sono interessate. Se posso esservi utile.

 

Sitemap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24